Merge branch 'master' of https://git.magicalgirl.moe/STJr/SRB2Internal.git into nightsplus-le

# Conflicts:
#	src/p_setup.c
#	src/p_user.c
This commit is contained in:
mazmazz 2018-08-10 13:44:47 -04:00
commit d97c25f6dd
58 changed files with 19500 additions and 14330 deletions

View File

@ -1,3 +1,4 @@
*.exe *.exe
*.mo *.mo
r_opengl.dll r_opengl.dll
*.bat

View File

@ -1,3 +1,4 @@
# GNU Make makefile for SRB2 # GNU Make makefile for SRB2
############################################################################# #############################################################################
# Copyright (C) 1998-2000 by DooM Legacy Team. # Copyright (C) 1998-2000 by DooM Legacy Team.
@ -357,7 +358,8 @@ endif
ifdef PROFILEMODE ifdef PROFILEMODE
# build with profiling information # build with profiling information
CFLAGS:=-pg $(CFLAGS) CFLAGS+=-pg
LDFLAGS+=-pg
endif endif
ifdef ZDEBUG ifdef ZDEBUG

View File

@ -275,8 +275,7 @@ void B_RespawnBot(INT32 playernum)
player->accelstart = sonic->player->accelstart; player->accelstart = sonic->player->accelstart;
player->thrustfactor = sonic->player->thrustfactor; player->thrustfactor = sonic->player->thrustfactor;
player->normalspeed = sonic->player->normalspeed; player->normalspeed = sonic->player->normalspeed;
player->pflags |= PF_AUTOBRAKE; player->pflags |= PF_AUTOBRAKE|(sonic->player->pflags & PF_DIRECTIONCHAR);
player->pflags &= ~PF_DIRECTIONCHAR;
P_TeleportMove(tails, x, y, z); P_TeleportMove(tails, x, y, z);
if (player->charability == CA_FLY) if (player->charability == CA_FLY)

View File

@ -16,7 +16,7 @@
#define ASSET_HASH_RINGS_DTA "${SRB2_ASSET_rings.dta_HASH}" #define ASSET_HASH_RINGS_DTA "${SRB2_ASSET_rings.dta_HASH}"
#define ASSET_HASH_ZONES_DTA "${SRB2_ASSET_zones.dta_HASH}" #define ASSET_HASH_ZONES_DTA "${SRB2_ASSET_zones.dta_HASH}"
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
#define ASSET_HASH_PATCH_DTA "${SRB2_ASSET_patch.dta_HASH}" #define ASSET_HASH_PATCH_PK3 "${SRB2_ASSET_patch.pk3_HASH}"
#endif #endif
#define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}" #define SRB2_COMP_REVISION "${SRB2_COMP_REVISION}"
@ -36,7 +36,7 @@
#define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799" #define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799"
#define ASSET_HASH_RINGS_DTA "85901ad4bf94637e5753d2ac2c03ea26" #define ASSET_HASH_RINGS_DTA "85901ad4bf94637e5753d2ac2c03ea26"
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
#define ASSET_HASH_PATCH_DTA "dbbf8bc6121618ee3be2d5b14650429b" #define ASSET_HASH_PATCH_PK3 "dbbf8bc6121618ee3be2d5b14650429b"
#endif #endif
#endif #endif

View File

@ -312,7 +312,7 @@ static void CON_SetupColormaps(void)
colset(lgreenmap, 97, 98, 106); colset(lgreenmap, 97, 98, 106);
colset(bluemap, 146, 147, 155); colset(bluemap, 146, 147, 155);
colset(redmap, 210, 32, 39); colset(redmap, 210, 32, 39);
colset(graymap, 8, 10, 15); colset(graymap, 6, 8, 14);
colset(orangemap, 51, 52, 57); colset(orangemap, 51, 52, 57);
colset(skymap, 129, 130, 133); colset(skymap, 129, 130, 133);
colset(purplemap, 160, 161, 163); colset(purplemap, 160, 161, 163);

View File

@ -395,8 +395,7 @@ static void ExtraDataTicker(void)
DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic));
} }
CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]);
D_FreeTextcmd(gametic); break;
return;
} }
} }
} }
@ -513,7 +512,8 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]);
// Score is resynched in the rspfirm resync packet // Score is resynched in the rspfirm resync packet
rsp->rings = LONG(players[i].rings); rsp->rings = SHORT(players[i].rings);
rsp->spheres = SHORT(players[i].spheres);
rsp->lives = players[i].lives; rsp->lives = players[i].lives;
rsp->continues = players[i].continues; rsp->continues = players[i].continues;
rsp->scoreadd = players[i].scoreadd; rsp->scoreadd = players[i].scoreadd;
@ -643,7 +643,8 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]);
// Score is resynched in the rspfirm resync packet // Score is resynched in the rspfirm resync packet
players[i].rings = LONG(rsp->rings); players[i].rings = SHORT(rsp->rings);
players[i].spheres = SHORT(rsp->spheres);
players[i].lives = rsp->lives; players[i].lives = rsp->lives;
players[i].continues = rsp->continues; players[i].continues = rsp->continues;
players[i].scoreadd = rsp->scoreadd; players[i].scoreadd = rsp->scoreadd;
@ -2254,7 +2255,7 @@ static void Command_connect(void)
// Assume we connect directly. // Assume we connect directly.
boolean viams = false; boolean viams = false;
if (COM_Argc() < 2) if (COM_Argc() < 2 || *COM_Argv(1) == 0)
{ {
CONS_Printf(M_GetText( CONS_Printf(M_GetText(
"Connect <serveraddress> (port): connect to a server\n" "Connect <serveraddress> (port): connect to a server\n"
@ -2377,11 +2378,11 @@ static void CL_RemovePlayer(INT32 playernum)
if (gametype == GT_CTF) if (gametype == GT_CTF)
P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you!
// If in a special stage, redistribute the player's rings across // If in a special stage, redistribute the player's spheres across
// the remaining players. // the remaining players.
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ {
INT32 i, count, increment, rings; INT32 i, count, increment, spheres;
for (i = 0, count = 0; i < MAXPLAYERS; i++) for (i = 0, count = 0; i < MAXPLAYERS; i++)
{ {
@ -2390,19 +2391,19 @@ static void CL_RemovePlayer(INT32 playernum)
} }
count--; count--;
rings = players[playernum].rings; spheres = players[playernum].spheres;
increment = rings/count; increment = spheres/count;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && i != playernum) if (playeringame[i] && i != playernum)
{ {
if (rings < increment) if (spheres < increment)
P_GivePlayerRings(&players[i], rings); P_GivePlayerSpheres(&players[i], spheres);
else else
P_GivePlayerRings(&players[i], increment); P_GivePlayerSpheres(&players[i], increment);
rings -= increment; spheres -= increment;
} }
} }
} }
@ -3326,7 +3327,7 @@ void SV_StopServer(void)
localtextcmd[0] = 0; localtextcmd[0] = 0;
localtextcmd2[0] = 0; localtextcmd2[0] = 0;
for (i = 0; i < BACKUPTICS; i++) for (i = firstticstosend; i < firstticstosend + BACKUPTICS; i++)
D_Clearticcmd(i); D_Clearticcmd(i);
consoleplayer = 0; consoleplayer = 0;

View File

@ -164,7 +164,8 @@ typedef struct
UINT16 powers[NUMPOWERS]; UINT16 powers[NUMPOWERS];
// Score is resynched in the confirm resync packet // Score is resynched in the confirm resync packet
INT32 rings; INT16 rings;
INT16 spheres;
SINT8 lives; SINT8 lives;
SINT8 continues; SINT8 continues;
UINT8 scoreadd; UINT8 scoreadd;

View File

@ -734,11 +734,6 @@ void D_StartTitle(void)
CON_ToggleOff(); CON_ToggleOff();
// Reset the palette // Reset the palette
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_SetPaletteColor(0);
else
#endif
if (rendermode != render_none) if (rendermode != render_none)
V_SetPaletteLump("PLAYPAL"); V_SetPaletteLump("PLAYPAL");
} }
@ -843,7 +838,7 @@ static void IdentifyVersion(void)
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
// Add our crappy patches to fix our bugs // Add our crappy patches to fix our bugs
D_AddFile(va(pandf,srb2waddir,"patch.dta")); D_AddFile(va(pandf,srb2waddir,"patch.pk3"));
#endif #endif
#if !defined (HAVE_SDL) || defined (HAVE_MIXER) #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
@ -1037,19 +1032,10 @@ void D_SRB2Main(void)
if (M_CheckParm("-password") && M_IsNextParm()) if (M_CheckParm("-password") && M_IsNextParm())
D_SetPassword(M_GetNextParm()); D_SetPassword(M_GetNextParm());
else
{
size_t z;
char junkpw[25];
for (z = 0; z < 24; z++)
junkpw[z] = (char)(rand() & 64)+32;
junkpw[24] = '\0';
D_SetPassword(junkpw);
}
// add any files specified on the command line with -file wadfile // add any files specified on the command line with -file wadfile
// to the wad list // to the wad list
if (!(M_CheckParm("-connect"))) if (!(M_CheckParm("-connect") && !M_CheckParm("-server")))
{ {
if (M_CheckParm("-file")) if (M_CheckParm("-file"))
{ {
@ -1129,7 +1115,7 @@ void D_SRB2Main(void)
//W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta //W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta
//W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta //W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
W_VerifyFileMD5(3, ASSET_HASH_PATCH_DTA); // patch.dta //W_VerifyFileMD5(3, ASSET_HASH_PATCH_PK3); // patch.pk3
#endif #endif
// don't check music.dta because people like to modify it, and it doesn't matter if they do // don't check music.dta because people like to modify it, and it doesn't matter if they do
@ -1138,7 +1124,7 @@ void D_SRB2Main(void)
mainwads = 3; // there are 3 wads not to unload mainwads = 3; // there are 3 wads not to unload
#ifdef USE_PATCH_DTA #ifdef USE_PATCH_DTA
++mainwads; // patch.dta adds one more ++mainwads; // patch.pk3 adds one more
#endif #endif
#ifdef DEVELOP #ifdef DEVELOP
++mainwads; // music_new, too ++mainwads; // music_new, too
@ -1204,7 +1190,15 @@ void D_SRB2Main(void)
R_Init(); R_Init();
// setting up sound // setting up sound
CONS_Printf("S_Init(): Setting up sound.\n"); if (dedicated)
{
nosound = true;
nomidimusic = nodigimusic = true;
}
else
{
CONS_Printf("S_Init(): Setting up sound.\n");
}
if (M_CheckParm("-nosound")) if (M_CheckParm("-nosound"))
nosound = true; nosound = true;
if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic if (M_CheckParm("-nomusic")) // combines -nomidimusic and -nodigmusic
@ -1316,7 +1310,7 @@ void D_SRB2Main(void)
} }
} }
if (autostart || netgame || M_CheckParm("+connect") || M_CheckParm("-connect")) if (autostart || netgame)
{ {
gameaction = ga_nothing; gameaction = ga_nothing;
@ -1350,8 +1344,7 @@ void D_SRB2Main(void)
} }
} }
if (server && !M_CheckParm("+map") && !M_CheckParm("+connect") if (server && !M_CheckParm("+map"))
&& !M_CheckParm("-connect"))
{ {
// Prevent warping to nonexistent levels // Prevent warping to nonexistent levels
if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR) if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR)

View File

@ -309,8 +309,8 @@ consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL,
consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t timetic_cons_t[] = {{0, "Normal"}, {1, "Centiseconds"}, {2, "Mania"}, {3, "Tics"}, {0, NULL}}; static CV_PossibleValue_t timetic_cons_t[] = {{0, "Classic"}, {1, "Centiseconds"}, {2, "Mania"}, {3, "Tics"}, {0, NULL}};
consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; // use tics in display consvar_t cv_timetic = {"timerres", "Classic", CV_SAVE, timetic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-person only"}, {2, "Always"}, {0, NULL}}; static CV_PossibleValue_t powerupdisplay_cons_t[] = {{0, "Never"}, {1, "First-person only"}, {2, "Always"}, {0, NULL}};
consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_powerupdisplay = {"powerupdisplay", "First-person only", CV_SAVE, powerupdisplay_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -2682,8 +2682,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
// Clear player score and rings if a spectator. // Clear player score and rings if a spectator.
if (players[playernum].spectator) if (players[playernum].spectator)
{ {
players[playernum].score = 0; players[playernum].score = players[playernum].rings = 0;
players[playernum].rings = 0;
if (players[playernum].mo) if (players[playernum].mo)
players[playernum].mo->health = 1; players[playernum].mo->health = 1;
} }
@ -2725,10 +2724,12 @@ static void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt,
#define BASESALT "basepasswordstorage" #define BASESALT "basepasswordstorage"
static UINT8 adminpassmd5[16]; static UINT8 adminpassmd5[16];
static boolean adminpasswordset = false;
void D_SetPassword(const char *pw) void D_SetPassword(const char *pw)
{ {
D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &adminpassmd5); D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &adminpassmd5);
adminpasswordset = true;
} }
// Remote Administration // Remote Administration
@ -2797,6 +2798,12 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
READMEM(*cp, sentmd5, 16); READMEM(*cp, sentmd5, 16);
if (!adminpasswordset)
{
CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[playernum]);
return;
}
if (client) if (client)
return; return;
@ -3930,28 +3937,7 @@ static void Command_ExitLevel_f(void)
else if (gamestate != GS_LEVEL || demoplayback) else if (gamestate != GS_LEVEL || demoplayback)
CONS_Printf(M_GetText("You must be in a level to use this.\n")); CONS_Printf(M_GetText("You must be in a level to use this.\n"));
else else
{
if ((netgame || multiplayer)
&& ((mapheaderinfo[gamemap-1]->nextlevel <= 0)
|| (mapheaderinfo[gamemap-1]->nextlevel > NUMMAPS)
|| !(mapvisited[mapheaderinfo[gamemap-1]->nextlevel-1])))
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].exiting)
break;
}
if (i == MAXPLAYERS)
{
CONS_Printf(M_GetText("Someone must finish the level for you to use this.\n"));
return;
}
}
SendNetXCmd(XD_EXITLEVEL, NULL, 0); SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
} }
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum)
@ -4066,7 +4052,7 @@ static void Command_RestartAudio_f(void)
I_ShutdownSound(); I_ShutdownSound();
I_StartupSound(); I_StartupSound();
I_InitMusic(); I_InitMusic();
// These must be called or no sound and music until manually set. // These must be called or no sound and music until manually set.
I_SetSfxVolume(cv_soundvolume.value); I_SetSfxVolume(cv_soundvolume.value);
@ -4074,7 +4060,7 @@ static void Command_RestartAudio_f(void)
I_SetMIDIMusicVolume(cv_midimusicvolume.value); I_SetMIDIMusicVolume(cv_midimusicvolume.value);
if (Playing()) // Gotta make sure the player is in a level if (Playing()) // Gotta make sure the player is in a level
P_RestoreMusic(&players[consoleplayer]); P_RestoreMusic(&players[consoleplayer]);
} }
/** Quits a game and returns to the title screen. /** Quits a game and returns to the title screen.

View File

@ -950,15 +950,37 @@ filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum)
return FS_FOUND; // will never happen, but makes the compiler shut up return FS_FOUND; // will never happen, but makes the compiler shut up
} }
// Rewritten by Monster Iestyn to be less stupid
// Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned
// (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore)
filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath) filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath)
{ {
filestatus_t homecheck = filesearch(filename, srb2home, wantedmd5sum, false, 10); filestatus_t homecheck; // store result of last file search
if (homecheck == FS_FOUND) boolean badmd5 = false; // store whether md5 was bad from either of the first two searches (if nothing was found in the third)
return filesearch(filename, srb2home, wantedmd5sum, completepath, 10);
homecheck = filesearch(filename, srb2path, wantedmd5sum, false, 10); // first, check SRB2's "home" directory
if (homecheck == FS_FOUND) homecheck = filesearch(filename, srb2home, wantedmd5sum, completepath, 10);
return filesearch(filename, srb2path, wantedmd5sum, completepath, 10);
return filesearch(filename, ".", wantedmd5sum, completepath, 10); if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
badmd5 = true;
// if not found at all, just move on without doing anything
// next, check SRB2's "path" directory
homecheck = filesearch(filename, srb2path, wantedmd5sum, completepath, 10);
if (homecheck == FS_FOUND) // we found the file, so return that we have :)
return FS_FOUND;
else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
badmd5 = true;
// if not found at all, just move on without doing anything
// finally check "." directory
homecheck = filesearch(filename, ".", wantedmd5sum, completepath, 10);
if (homecheck != FS_NOTFOUND) // if not found this time, fall back on the below return statement
return homecheck; // otherwise return the result we got
return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found
} }

View File

@ -324,7 +324,8 @@ typedef struct player_s
angle_t drawangle; angle_t drawangle;
// player's ring count // player's ring count
INT32 rings; INT16 rings;
INT16 spheres;
SINT8 pity; // i pity the fool. SINT8 pity; // i pity the fool.
INT32 currentweapon; // current weapon selected. INT32 currentweapon; // current weapon selected.
@ -462,7 +463,7 @@ typedef struct player_s
tic_t marebegunat; // Leveltime when mare begun tic_t marebegunat; // Leveltime when mare begun
tic_t startedtime; // Time which you started this mare with. tic_t startedtime; // Time which you started this mare with.
tic_t finishedtime; // Time it took you to finish the mare (used for display) tic_t finishedtime; // Time it took you to finish the mare (used for display)
INT16 finishedrings; // The rings you had left upon finishing the mare INT16 finishedspheres; // The spheres you had left upon finishing the mare
UINT32 marescore; // score for this nights stage UINT32 marescore; // score for this nights stage
UINT32 lastmarescore; // score for the last mare UINT32 lastmarescore; // score for the last mare
UINT8 lastmare; // previous mare UINT8 lastmare; // previous mare

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,9 @@ enum
ML_BLOCKMAP, // LUT, motion clipping, walls/grid element ML_BLOCKMAP, // LUT, motion clipping, walls/grid element
}; };
// Extra flag for objects.
#define MTF_EXTRA 1
// Reverse gravity flag for objects. // Reverse gravity flag for objects.
#define MTF_OBJECTFLIP 2 #define MTF_OBJECTFLIP 2

View File

@ -569,6 +569,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Handle touching sector specials in P_PlayerAfterThink instead of P_PlayerThink. /// Handle touching sector specials in P_PlayerAfterThink instead of P_PlayerThink.
/// \note Required for proper collision with moving sloped surfaces that have sector specials on them. /// \note Required for proper collision with moving sloped surfaces that have sector specials on them.
//#define SECTORSPECIALSAFTERTHINK #define SECTORSPECIALSAFTERTHINK
#endif // __DOOMDEF__ #endif // __DOOMDEF__

View File

@ -126,15 +126,13 @@ extern INT32 secondarydisplayplayer; // for splitscreen
// Maps of special importance // Maps of special importance
extern INT16 spstage_start; extern INT16 spstage_start;
extern INT16 sstage_start; extern INT16 sstage_start, sstage_end, smpstage_start, smpstage_end;
extern INT16 sstage_end;
extern INT16 titlemap; extern INT16 titlemap;
extern boolean hidetitlepics; extern boolean hidetitlepics;
extern INT16 bootmap; //bootmap for loading a map on startup extern INT16 bootmap; //bootmap for loading a map on startup
extern boolean looptitle; extern boolean looptitle;
extern boolean useNightsSS;
// CTF colors. // CTF colors.
extern UINT8 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering; extern UINT8 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering;
@ -175,7 +173,7 @@ extern cutscene_t *cutscenes[128];
extern INT16 nextmapoverride; extern INT16 nextmapoverride;
extern boolean skipstats; extern boolean skipstats;
extern UINT32 totalrings; // Total # of rings in a level extern UINT32 ssspheres; // Total # of spheres in a level
// Fun extra stuff // Fun extra stuff
extern INT16 lastmap; // Last level you were at (returning from special stages). extern INT16 lastmap; // Last level you were at (returning from special stages).

View File

@ -987,7 +987,6 @@ static const char *credits[] = {
"\1Programming", "\1Programming",
"Alam \"GBC\" Arias", "Alam \"GBC\" Arias",
"Logan \"GBA\" Arias", "Logan \"GBA\" Arias",
"Colette \"fickle\" Bordelon",
"Callum Dickinson", "Callum Dickinson",
"Scott \"Graue\" Feeney", "Scott \"Graue\" Feeney",
"Nathan \"Jazz\" Giroux", "Nathan \"Jazz\" Giroux",
@ -1345,7 +1344,7 @@ void F_GameEvaluationDrawer(void)
++timesBeatenUltimate; ++timesBeatenUltimate;
if (M_UpdateUnlockablesAndExtraEmblems()) if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_ncitem); S_StartSound(NULL, sfx_s3k68);
G_SaveGameData(); G_SaveGameData();
} }

View File

@ -116,20 +116,18 @@ INT32 secondarydisplayplayer; // for splitscreen
tic_t gametic; tic_t gametic;
tic_t levelstarttic; // gametic at level start tic_t levelstarttic; // gametic at level start
UINT32 totalrings; // for intermission UINT32 ssspheres; // old special stage
INT16 lastmap; // last level you were at (returning from special stages) INT16 lastmap; // last level you were at (returning from special stages)
tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
INT16 spstage_start; INT16 spstage_start;
INT16 sstage_start; INT16 sstage_start, sstage_end, smpstage_start, smpstage_end;
INT16 sstage_end;
INT16 titlemap = 0; INT16 titlemap = 0;
boolean hidetitlepics = false; boolean hidetitlepics = false;
INT16 bootmap; //bootmap for loading a map on startup INT16 bootmap; //bootmap for loading a map on startup
boolean looptitle = false; boolean looptitle = false;
boolean useNightsSS = false;
UINT8 skincolor_redteam = SKINCOLOR_RED; UINT8 skincolor_redteam = SKINCOLOR_RED;
UINT8 skincolor_blueteam = SKINCOLOR_BLUE; UINT8 skincolor_blueteam = SKINCOLOR_BLUE;
@ -2201,7 +2199,7 @@ void G_PlayerReborn(INT32 player)
p->pflags |= PF_JUMPDOWN; p->pflags |= PF_JUMPDOWN;
p->playerstate = PST_LIVE; p->playerstate = PST_LIVE;
p->rings = 0; // 0 rings p->rings = p->spheres = 0; // 0 rings
p->panim = PA_IDLE; // standing animation p->panim = PA_IDLE; // standing animation
//if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there //if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there
@ -2798,7 +2796,11 @@ INT32 G_GetGametypeByName(const char *gametypestr)
// //
boolean G_IsSpecialStage(INT32 mapnum) boolean G_IsSpecialStage(INT32 mapnum)
{ {
if (gametype == GT_COOP && modeattacking != ATTACKING_RECORD && mapnum >= sstage_start && mapnum <= sstage_end) if (gametype != GT_COOP || modeattacking == ATTACKING_RECORD)
return false;
if (mapnum >= sstage_start && mapnum <= sstage_end)
return true;
if (mapnum >= smpstage_start && mapnum <= smpstage_end)
return true; return true;
return false; return false;
@ -3023,21 +3025,14 @@ static void G_DoCompleted(void)
{ {
token--; token--;
if (!(emeralds & EMERALD1)) for (i = 0; i < 7; i++)
nextmap = (INT16)(sstage_start - 1); // Special Stage 1 if (!(emeralds & (1<<i)))
else if (!(emeralds & EMERALD2)) {
nextmap = (INT16)(sstage_start); // Special Stage 2 nextmap = ((netgame || multiplayer) ? smpstage_start : sstage_start) + i - 1; // to special stage!
else if (!(emeralds & EMERALD3)) break;
nextmap = (INT16)(sstage_start + 1); // Special Stage 3 }
else if (!(emeralds & EMERALD4))
nextmap = (INT16)(sstage_start + 2); // Special Stage 4 if (i == 7)
else if (!(emeralds & EMERALD5))
nextmap = (INT16)(sstage_start + 3); // Special Stage 5
else if (!(emeralds & EMERALD6))
nextmap = (INT16)(sstage_start + 4); // Special Stage 6
else if (!(emeralds & EMERALD7))
nextmap = (INT16)(sstage_start + 5); // Special Stage 7
else
gottoken = false; gottoken = false;
} }
@ -3209,9 +3204,9 @@ void G_LoadGameSettings(void)
{ {
// defaults // defaults
spstage_start = 1; spstage_start = 1;
sstage_start = 50; sstage_start = smpstage_start = 50;
sstage_end = 57; // 8 special stages in vanilla SRB2 sstage_end = smpstage_end = 56; // 7 special stages in vanilla SRB2
useNightsSS = false; //true; sstage_end++; // plus one weirdo
// initialize free sfx slots for skin sounds // initialize free sfx slots for skin sounds
S_InitRuntimeSounds(); S_InitRuntimeSounds();
@ -3817,7 +3812,8 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
unlocktriggers = 0; unlocktriggers = 0;
// clear itemfinder, just in case // clear itemfinder, just in case
CV_StealthSetValue(&cv_itemfinder, 0); if (!dedicated) // except in dedicated servers, where it is not registered and can actually I_Error debug builds
CV_StealthSetValue(&cv_itemfinder, 0);
} }
// internal game map // internal game map

View File

@ -68,7 +68,6 @@ typedef struct gr_vissprite_s
struct gr_vissprite_s *prev; struct gr_vissprite_s *prev;
struct gr_vissprite_s *next; struct gr_vissprite_s *next;
float x1, x2; float x1, x2;
float z1, z2;
float tz, ty; float tz, ty;
lumpnum_t patchlumpnum; lumpnum_t patchlumpnum;
boolean flip; boolean flip;
@ -79,6 +78,7 @@ typedef struct gr_vissprite_s
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
UINT8 *colormap; UINT8 *colormap;
INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
float z1, z2;
} gr_vissprite_t; } gr_vissprite_t;
// -------- // --------

View File

@ -62,7 +62,7 @@ static dynlights_t *dynlights = &view_dynlights[0];
light_t lspr[NUMLIGHTS] = light_t lspr[NUMLIGHTS] =
{ {
// type offset x, y coronas color, c_size,light color,l_radius, sqr radius computed at init // type offset x, y coronas color, c_size,light color,l_radius, sqr radius computed at init
// UNDEFINED: 0 // NOLIGHT: 0
{ UNDEFINED_SPR, 0.0f, 0.0f, 0x00000000, 24.0f, 0x00000000, 0.0f, 0.0f}, { UNDEFINED_SPR, 0.0f, 0.0f, 0x00000000, 24.0f, 0x00000000, 0.0f, 0.0f},
// weapons // weapons
// RINGSPARK_L // RINGSPARK_L
@ -151,10 +151,9 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_POSS &lspr[NOLIGHT], // SPR_POSS
&lspr[NOLIGHT], // SPR_SPOS &lspr[NOLIGHT], // SPR_SPOS
&lspr[NOLIGHT], // SPR_FISH &lspr[NOLIGHT], // SPR_FISH
&lspr[NOLIGHT], // SPR_BUZZ Graue 03-10-2004 &lspr[NOLIGHT], // SPR_BUZZ
&lspr[NOLIGHT], // SPR_RBUZ Graue 03-10-2004 &lspr[NOLIGHT], // SPR_RBUZ
&lspr[NOLIGHT], // SPR_JETB &lspr[NOLIGHT], // SPR_JETB
&lspr[NOLIGHT], // SPR_JETW
&lspr[NOLIGHT], // SPR_JETG &lspr[NOLIGHT], // SPR_JETG
&lspr[NOLIGHT], // SPR_CCOM &lspr[NOLIGHT], // SPR_CCOM
&lspr[NOLIGHT], // SPR_DETN &lspr[NOLIGHT], // SPR_DETN
@ -162,19 +161,20 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_TRET &lspr[NOLIGHT], // SPR_TRET
&lspr[NOLIGHT], // SPR_TURR &lspr[NOLIGHT], // SPR_TURR
&lspr[NOLIGHT], // SPR_SHRP &lspr[NOLIGHT], // SPR_SHRP
&lspr[NOLIGHT], // SPR_CRAB
&lspr[NOLIGHT], // SPR_JJAW &lspr[NOLIGHT], // SPR_JJAW
&lspr[NOLIGHT], // SPR_SNLR &lspr[NOLIGHT], // SPR_SNLR
&lspr[NOLIGHT], // SPR_VLTR &lspr[NOLIGHT], // SPR_VLTR
&lspr[NOLIGHT], // SPR_PNTY &lspr[NOLIGHT], // SPR_PNTY
&lspr[NOLIGHT], // SPR_ARCH &lspr[NOLIGHT], // SPR_ARCH
&lspr[NOLIGHT], // SPR_CBFS &lspr[NOLIGHT], // SPR_CBFS
&lspr[JETLIGHT_L], // SPR_STAB
&lspr[NOLIGHT], // SPR_SPSH &lspr[NOLIGHT], // SPR_SPSH
&lspr[NOLIGHT], // SPR_ESHI &lspr[NOLIGHT], // SPR_ESHI
&lspr[NOLIGHT], // SPR_GSNP &lspr[NOLIGHT], // SPR_GSNP
&lspr[NOLIGHT], // SPR_MNUS &lspr[NOLIGHT], // SPR_MNUS
&lspr[NOLIGHT], // SPR_SSHL &lspr[NOLIGHT], // SPR_SSHL
&lspr[NOLIGHT], // SPR_UNID &lspr[NOLIGHT], // SPR_UNID
&lspr[NOLIGHT], // SPR_BBUZ
// Generic Boos Items // Generic Boos Items
&lspr[JETLIGHT_L], // SPR_JETF // Boss jet fumes &lspr[JETLIGHT_L], // SPR_JETF // Boss jet fumes
@ -227,18 +227,18 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_RING &lspr[NOLIGHT], // SPR_RING
&lspr[NOLIGHT], // SPR_TRNG &lspr[NOLIGHT], // SPR_TRNG
&lspr[NOLIGHT], // SPR_TOKE &lspr[NOLIGHT], // SPR_TOKE
&lspr[REDBALL_L], // SPR_RFLG &lspr[REDBALL_L], // SPR_RFLG
&lspr[BLUEBALL_L], // SPR_BFLG &lspr[BLUEBALL_L], // SPR_BFLG
&lspr[NOLIGHT], // SPR_NWNG &lspr[NOLIGHT], // SPR_SPHR
&lspr[NOLIGHT], // SPR_NCHP
&lspr[NOLIGHT], // SPR_NSTR
&lspr[NOLIGHT], // SPR_EMBM &lspr[NOLIGHT], // SPR_EMBM
&lspr[NOLIGHT], // SPR_CEMG &lspr[NOLIGHT], // SPR_CEMG
&lspr[NOLIGHT], // SPR_EMER &lspr[NOLIGHT], // SPR_SHRD
// Interactive Objects // Interactive Objects
&lspr[NOLIGHT], // SPR_FANS
&lspr[NOLIGHT], // SPR_BBLS &lspr[NOLIGHT], // SPR_BBLS
&lspr[NOLIGHT], // SPR_SIGN &lspr[NOLIGHT], // SPR_SIGN
&lspr[NOLIGHT], // SPR_STEM
&lspr[NOLIGHT], // SPR_SPIK &lspr[NOLIGHT], // SPR_SPIK
&lspr[NOLIGHT], // SPR_SFLM &lspr[NOLIGHT], // SPR_SFLM
&lspr[NOLIGHT], // SPR_USPK &lspr[NOLIGHT], // SPR_USPK
@ -294,17 +294,19 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_FWR4 &lspr[NOLIGHT], // SPR_FWR4
&lspr[NOLIGHT], // SPR_BUS1 &lspr[NOLIGHT], // SPR_BUS1
&lspr[NOLIGHT], // SPR_BUS2 &lspr[NOLIGHT], // SPR_BUS2
&lspr[NOLIGHT], // SPR_BUS3
// Trees (both GFZ and misc) // Trees (both GFZ and misc)
&lspr[NOLIGHT], // SPR_TRE1 &lspr[NOLIGHT], // SPR_TRE1
&lspr[NOLIGHT], // SPR_TRE2 &lspr[NOLIGHT], // SPR_TRE2
&lspr[NOLIGHT], // SPR_TRE3 &lspr[NOLIGHT], // SPR_TRE3
&lspr[NOLIGHT], // SPR_TRE4 &lspr[NOLIGHT], // SPR_TRE4
&lspr[NOLIGHT], // SPR_TRE5 &lspr[NOLIGHT], // SPR_TRE5
&lspr[NOLIGHT], // SPR_TRE6
// Techno Hill Scenery // Techno Hill Scenery
&lspr[NOLIGHT], // SPR_THZP &lspr[NOLIGHT], // SPR_THZP
&lspr[NOLIGHT], // SPR_FWR5 &lspr[NOLIGHT], // SPR_FWR5
&lspr[REDBALL_L], // SPR_ALRM &lspr[REDBALL_L], // SPR_ALRM
// Deep Sea Scenery // Deep Sea Scenery
&lspr[NOLIGHT], // SPR_GARG &lspr[NOLIGHT], // SPR_GARG
@ -327,6 +329,15 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_RSPB &lspr[NOLIGHT], // SPR_RSPB
&lspr[REDBALL_L], // SPR_SFBR &lspr[REDBALL_L], // SPR_SFBR
&lspr[REDBALL_L], // SPR_BFBR &lspr[REDBALL_L], // SPR_BFBR
&lspr[NOLIGHT], // SPR_BANR
&lspr[NOLIGHT], // SPR_PINE
&lspr[NOLIGHT], // SPR_CEZB
&lspr[REDBALL_L], // SPR_CNDL
&lspr[NOLIGHT], // SPR_FLMH
&lspr[REDBALL_L], // SPR_CTRC
&lspr[NOLIGHT], // SPR_CFLG
&lspr[NOLIGHT], // SPR_CSTA
&lspr[NOLIGHT], // SPR_CBBS
// Arid Canyon Scenery // Arid Canyon Scenery
&lspr[NOLIGHT], // SPR_BTBL &lspr[NOLIGHT], // SPR_BTBL
@ -347,12 +358,25 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_XMS3 &lspr[NOLIGHT], // SPR_XMS3
&lspr[NOLIGHT], // SPR_XMS4 &lspr[NOLIGHT], // SPR_XMS4
&lspr[NOLIGHT], // SPR_XMS5 &lspr[NOLIGHT], // SPR_XMS5
&lspr[NOLIGHT], // SPR_FHZI
// Halloween Scenery
&lspr[RINGLIGHT_L], // SPR_PUMK
&lspr[NOLIGHT], // SPR_HHPL
&lspr[NOLIGHT], // SPR_SHRM
&lspr[NOLIGHT], // SPR_HHZM
// Botanic Serenity Scenery // Botanic Serenity Scenery
&lspr[NOLIGHT], // SPR_BSZ1 &lspr[NOLIGHT], // SPR_BSZ1
&lspr[NOLIGHT], // SPR_BSZ2 &lspr[NOLIGHT], // SPR_BSZ2
&lspr[NOLIGHT], // SPR_BSZ3 &lspr[NOLIGHT], // SPR_BSZ3
&lspr[NOLIGHT], // SPR_BSZ4 //&lspr[NOLIGHT], -- SPR_BSZ4
&lspr[NOLIGHT], // SPR_BST1
&lspr[NOLIGHT], // SPR_BST2
&lspr[NOLIGHT], // SPR_BST3
&lspr[NOLIGHT], // SPR_BST4
&lspr[NOLIGHT], // SPR_BST5
&lspr[NOLIGHT], // SPR_BST6
&lspr[NOLIGHT], // SPR_BSZ5 &lspr[NOLIGHT], // SPR_BSZ5
&lspr[NOLIGHT], // SPR_BSZ6 &lspr[NOLIGHT], // SPR_BSZ6
&lspr[NOLIGHT], // SPR_BSZ7 &lspr[NOLIGHT], // SPR_BSZ7
@ -375,8 +399,8 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_FIRS &lspr[NOLIGHT], // SPR_FIRS
&lspr[NOLIGHT], // SPR_BUBS &lspr[NOLIGHT], // SPR_BUBS
&lspr[NOLIGHT], // SPR_ZAPS &lspr[NOLIGHT], // SPR_ZAPS
&lspr[INVINCIBLE_L], // SPR_IVSP &lspr[INVINCIBLE_L], // SPR_IVSP
&lspr[SUPERSPARK_L], // SPR_SSPK &lspr[SUPERSPARK_L], // SPR_SSPK
&lspr[NOLIGHT], // SPR_GOAL &lspr[NOLIGHT], // SPR_GOAL
@ -398,13 +422,20 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_FL14 &lspr[NOLIGHT], // SPR_FL14
&lspr[NOLIGHT], // SPR_FL15 &lspr[NOLIGHT], // SPR_FL15
&lspr[NOLIGHT], // SPR_FL16 &lspr[NOLIGHT], // SPR_FL16
&lspr[NOLIGHT], // SPR_FS01
&lspr[NOLIGHT], // SPR_FS02
// Springs // Springs
&lspr[NOLIGHT], // SPR_FANS
&lspr[NOLIGHT], // SPR_STEM
&lspr[NOLIGHT], // SPR_BUMP
&lspr[NOLIGHT], // SPR_BLON
&lspr[NOLIGHT], // SPR_SPRY &lspr[NOLIGHT], // SPR_SPRY
&lspr[NOLIGHT], // SPR_SPRR &lspr[NOLIGHT], // SPR_SPRR
&lspr[NOLIGHT], // SPR_SPRB Graue &lspr[NOLIGHT], // SPR_SPRB
&lspr[NOLIGHT], // SPR_YSPR &lspr[NOLIGHT], // SPR_YSPR
&lspr[NOLIGHT], // SPR_RSPR &lspr[NOLIGHT], // SPR_RSPR
&lspr[NOLIGHT], // SPR_BSPR
&lspr[NOLIGHT], // SPR_SSWY &lspr[NOLIGHT], // SPR_SSWY
&lspr[NOLIGHT], // SPR_SSWR &lspr[NOLIGHT], // SPR_SSWR
&lspr[NOLIGHT], // SPR_SSWB &lspr[NOLIGHT], // SPR_SSWB
@ -420,7 +451,7 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_DUST &lspr[NOLIGHT], // SPR_DUST
&lspr[NOLIGHT], // SPR_FPRT &lspr[NOLIGHT], // SPR_FPRT
&lspr[SUPERSPARK_L], // SPR_TFOG &lspr[SUPERSPARK_L], // SPR_TFOG
&lspr[NIGHTSLIGHT_L], // SPR_SEED // Sonic CD flower seed &lspr[NIGHTSLIGHT_L], // SPR_SEED
&lspr[NOLIGHT], // SPR_PRTL &lspr[NOLIGHT], // SPR_PRTL
// Game Indicators // Game Indicators
@ -459,25 +490,43 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_GOOM &lspr[NOLIGHT], // SPR_GOOM
&lspr[NOLIGHT], // SPR_BGOM &lspr[NOLIGHT], // SPR_BGOM
&lspr[REDBALL_L], // SPR_FFWR &lspr[REDBALL_L], // SPR_FFWR
&lspr[SMALLREDBALL_L], // SPR_FBLL &lspr[SMALLREDBALL_L], // SPR_FBLL
&lspr[NOLIGHT], // SPR_SHLL &lspr[NOLIGHT], // SPR_SHLL
&lspr[REDBALL_L], // SPR_PUMA &lspr[REDBALL_L], // SPR_PUMA
&lspr[NOLIGHT], // SPR_HAMM &lspr[NOLIGHT], // SPR_HAMM
&lspr[NOLIGHT], // SPR_KOOP &lspr[NOLIGHT], // SPR_KOOP
&lspr[REDBALL_L], // SPR_BFLM &lspr[REDBALL_L], // SPR_BFLM
&lspr[NOLIGHT], // SPR_MAXE &lspr[NOLIGHT], // SPR_MAXE
&lspr[NOLIGHT], // SPR_MUS1 &lspr[NOLIGHT], // SPR_MUS1
&lspr[NOLIGHT], // SPR_MUS2 &lspr[NOLIGHT], // SPR_MUS2
&lspr[NOLIGHT], // SPR_TOAD &lspr[NOLIGHT], // SPR_TOAD
// NiGHTS Stuff // NiGHTS Stuff
&lspr[SUPERSONIC_L], // SPR_NDRN // NiGHTS drone &lspr[SUPERSONIC_L], // SPR_NDRN // NiGHTS drone
&lspr[NOLIGHT], // SPR_NSPK &lspr[NOLIGHT], // SPR_NSPK
&lspr[NOLIGHT], // SPR_NBMP &lspr[NOLIGHT], // SPR_NBMP
&lspr[NOLIGHT], // SPR_HOOP &lspr[NOLIGHT], // SPR_HOOP
&lspr[NOLIGHT], // SPR_HSCR &lspr[NOLIGHT], // SPR_HSCR
&lspr[NOLIGHT], // SPR_NPRU &lspr[NOLIGHT], // SPR_NPRU
&lspr[NOLIGHT], // SPR_CAPS &lspr[NOLIGHT], // SPR_CAPS
&lspr[INVINCIBLE_L], // SPR_IDYA
&lspr[NOLIGHT], // SPR_NTPN
&lspr[NOLIGHT], // SPR_SHLP
// Secret badniks and hazards, shhhh
&lspr[NOLIGHT], // SPR_PENG
&lspr[NOLIGHT], // SPR_POPH,
&lspr[NOLIGHT], // SPR_HIVE
&lspr[NOLIGHT], // SPR_BUMB,
&lspr[NOLIGHT], // SPR_BBUZ
&lspr[NOLIGHT], // SPR_FMCE,
&lspr[NOLIGHT], // SPR_HMCE,
&lspr[NOLIGHT], // SPR_CACO,
&lspr[BLUEBALL_L], // SPR_BAL2,
&lspr[NOLIGHT], // SPR_SBOB,
&lspr[BLUEBALL_L], // SPR_SBFL,
&lspr[BLUEBALL_L], // SPR_SBSK,
&lspr[NOLIGHT], // SPR_BATT,
// Debris // Debris
&lspr[RINGSPARK_L], // SPR_SPRK &lspr[RINGSPARK_L], // SPR_SPRK
@ -485,6 +534,7 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[SUPERSPARK_L], // SPR_BOM2 &lspr[SUPERSPARK_L], // SPR_BOM2
&lspr[SUPERSPARK_L], // SPR_BOM3 &lspr[SUPERSPARK_L], // SPR_BOM3
&lspr[NOLIGHT], // SPR_BOM4 &lspr[NOLIGHT], // SPR_BOM4
&lspr[REDBALL_L], // SPR_BMNB
// Crumbly rocks // Crumbly rocks
&lspr[NOLIGHT], // SPR_ROIA &lspr[NOLIGHT], // SPR_ROIA
@ -504,9 +554,6 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_ROIO &lspr[NOLIGHT], // SPR_ROIO
&lspr[NOLIGHT], // SPR_ROIP &lspr[NOLIGHT], // SPR_ROIP
// Blue Spheres
&lspr[NOLIGHT], // SPR_BBAL
// Gravity Well Objects // Gravity Well Objects
&lspr[NOLIGHT], // SPR_GWLG &lspr[NOLIGHT], // SPR_GWLG
&lspr[NOLIGHT], // SPR_GWLR &lspr[NOLIGHT], // SPR_GWLR

View File

@ -2115,27 +2115,34 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
} }
else else
{ {
#ifdef ESLOPE // P.S. this is better-organized than the old version fixed_t texturevpeg;
fixed_t offs = sides[(newline ? newline : rover->master)->sidenum[0]].rowoffset;
grTex = HWR_GetTexture(texnum);
wallVerts[3].t = (*rover->topheight - h + offs) * grTex->scaleY;
wallVerts[2].t = (*rover->topheight - hS + offs) * grTex->scaleY;
wallVerts[0].t = (*rover->topheight - l + offs) * grTex->scaleY;
wallVerts[1].t = (*rover->topheight - lS + offs) * grTex->scaleY;
#else
grTex = HWR_GetTexture(texnum);
// Wow, how was this missing from OpenGL for so long?
// ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software
// -- Monster Iestyn 26/06/18
if (newline) if (newline)
{ {
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset) * grTex->scaleY; texturevpeg = sides[newline->sidenum[0]].rowoffset;
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[newline->sidenum[0]].rowoffset)) * grTex->scaleY; if (newline->flags & ML_DONTPEGBOTTOM)
texturevpeg -= *rover->topheight - *rover->bottomheight;
} }
else else
{ {
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset) * grTex->scaleY; texturevpeg = sides[rover->master->sidenum[0]].rowoffset;
wallVerts[0].t = wallVerts[1].t = (h - l + (*rover->topheight - h + sides[rover->master->sidenum[0]].rowoffset)) * grTex->scaleY; if (gr_linedef->flags & ML_DONTPEGBOTTOM)
texturevpeg -= *rover->topheight - *rover->bottomheight;
} }
grTex = HWR_GetTexture(texnum);
#ifdef ESLOPE
wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY;
wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY;
#else
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
#endif #endif
wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX; wallVerts[0].s = wallVerts[3].s = cliplow * grTex->scaleX;
@ -3032,8 +3039,8 @@ static boolean HWR_CheckBBox(fixed_t *bspcoord)
return gld_clipper_SafeCheckRange(angle2, angle1); return gld_clipper_SafeCheckRange(angle2, angle1);
#else #else
// check clip list for an open space // check clip list for an open space
angle1 = R_PointToAngle(px1, py1) - dup_viewangle; angle1 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px1>>1, py1>>1) - dup_viewangle;
angle2 = R_PointToAngle(px2, py2) - dup_viewangle; angle2 = R_PointToAngle2(dup_viewx>>1, dup_viewy>>1, px2>>1, py2>>1) - dup_viewangle;
span = angle1 - angle2; span = angle1 - angle2;
@ -4072,7 +4079,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t
angle_t shadowdir; angle_t shadowdir;
// Set direction // Set direction
if (splitscreen && stplyr != &players[displayplayer]) if (splitscreen && stplyr == &players[secondarydisplayplayer])
shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value); shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value);
else else
shadowdir = localangle + FixedAngle(cv_cam_rotate.value); shadowdir = localangle + FixedAngle(cv_cam_rotate.value);
@ -4359,6 +4366,9 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
i = 0; i = 0;
temp = FLOAT_TO_FIXED(realtop); temp = FLOAT_TO_FIXED(realtop);
if (spr->mobj->frame & FF_FULLBRIGHT)
lightlevel = 255;
#ifdef ESLOPE #ifdef ESLOPE
for (i = 1; i < sector->numlights; i++) for (i = 1; i < sector->numlights; i++)
{ {
@ -4366,14 +4376,16 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
: sector->lightlist[i].height; : sector->lightlist[i].height;
if (h <= temp) if (h <= temp)
{ {
lightlevel = *list[i-1].lightlevel; if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *list[i-1].lightlevel;
colormap = list[i-1].extra_colormap; colormap = list[i-1].extra_colormap;
break; break;
} }
} }
#else #else
i = R_GetPlaneLight(sector, temp, false); i = R_GetPlaneLight(sector, temp, false);
lightlevel = *list[i].lightlevel; if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *list[i].lightlevel;
colormap = list[i].extra_colormap; colormap = list[i].extra_colormap;
#endif #endif
@ -4388,7 +4400,8 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
// even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite // even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite
if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES))
{ {
lightlevel = *list[i].lightlevel; if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *list[i].lightlevel;
colormap = list[i].extra_colormap; colormap = list[i].extra_colormap;
} }
@ -5305,7 +5318,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
float tr_x, tr_y; float tr_x, tr_y;
float tz; float tz;
float x1, x2; float x1, x2;
float z1, z2;
float rightsin, rightcos; float rightsin, rightcos;
float this_scale; float this_scale;
float gz, gzt; float gz, gzt;
@ -5320,9 +5332,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
INT32 heightsec, phs; INT32 heightsec, phs;
const boolean papersprite = (thing->frame & FF_PAPERSPRITE); const boolean papersprite = (thing->frame & FF_PAPERSPRITE);
angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle); angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle);
// float offset; float z1, z2;
// float ang_scale = 1.0f, ang_scalez = 0.0f;
// float z1, z2;
if (!thing) if (!thing)
return; return;
@ -5377,28 +5387,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
I_Error("sprframes NULL for sprite %d\n", thing->sprite); I_Error("sprframes NULL for sprite %d\n", thing->sprite);
#endif #endif
if (papersprite) ang = R_PointToAngle (thing->x, thing->y) - mobjangle;
{
// Use the actual view angle, rather than the angle formed
// between the view point and the thing
// this makes sure paper sprites always appear at the right angle!
// Note: DO NOT do this in software mode version, it actually
// makes papersprites look WORSE there (I know, I've tried)
// Monster Iestyn - 13/05/17
ang = dup_viewangle - mobjangle;
/*
ang_scale = FIXED_TO_FLOAT(FINESINE(ang>>ANGLETOFINESHIFT));
ang_scalez = FIXED_TO_FLOAT(FINECOSINE(ang>>ANGLETOFINESHIFT));
if (ang_scale < 0)
{
ang_scale = -ang_scale;
ang_scalez = -ang_scalez;
}
*/
}
else if (sprframe->rotate != SRF_SINGLE)
ang = R_PointToAngle (thing->x, thing->y) - mobjangle;
if (sprframe->rotate == SRF_SINGLE) if (sprframe->rotate == SRF_SINGLE)
{ {
@ -5406,6 +5395,14 @@ static void HWR_ProjectSprite(mobj_t *thing)
rot = 0; //Fab: for vis->patch below rot = 0; //Fab: for vis->patch below
lumpoff = sprframe->lumpid[0]; //Fab: see note above lumpoff = sprframe->lumpid[0]; //Fab: see note above
flip = sprframe->flip; // Will only be 0x00 or 0xFF flip = sprframe->flip; // Will only be 0x00 or 0xFF
if (papersprite && ang < ANGLE_180)
{
if (flip)
flip = 0;
else
flip = 255;
}
} }
else else
{ {
@ -5420,20 +5417,23 @@ static void HWR_ProjectSprite(mobj_t *thing)
//Fab: lumpid is the index for spritewidth,spriteoffset... tables //Fab: lumpid is the index for spritewidth,spriteoffset... tables
lumpoff = sprframe->lumpid[rot]; lumpoff = sprframe->lumpid[rot];
flip = sprframe->flip & (1<<rot); flip = sprframe->flip & (1<<rot);
if (papersprite && ang < ANGLE_180)
{
if (flip)
flip = 0;
else
flip = 1<<rot;
}
} }
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
if (papersprite) // replaces the ang_scale and scalez thing above if (papersprite)
{ {
rightsin = FIXED_TO_FLOAT(FINESINE(mobjangle>>ANGLETOFINESHIFT)); rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT));
rightcos = FIXED_TO_FLOAT(FINECOSINE(mobjangle>>ANGLETOFINESHIFT)); rightcos = FIXED_TO_FLOAT(FINECOSINE((mobjangle)>>ANGLETOFINESHIFT));
if (flip) // flip the signs of the above values so you don't end up displaying the sprite backwards
{
rightsin *= -1.0;
rightcos *= -1.0;
}
} }
else else
{ {
@ -5487,7 +5487,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
} }
heightsec = thing->subsector->sector->heightsec; heightsec = thing->subsector->sector->heightsec;
phs = players[displayplayer].mo->subsector->sector->heightsec; if (viewplayer->mo && viewplayer->mo->subsector)
phs = viewplayer->mo->subsector->sector->heightsec;
else
phs = -1;
if (heightsec != -1 && phs != -1) // only clip things which are in special sectors if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
{ {
@ -5505,13 +5508,13 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis = HWR_NewVisSprite(); vis = HWR_NewVisSprite();
vis->x1 = x1; vis->x1 = x1;
vis->x2 = x2; vis->x2 = x2;
vis->z1 = z1;
vis->z2 = z2;
vis->tz = tz; // Keep tz for the simple sprite sorting that happens vis->tz = tz; // Keep tz for the simple sprite sorting that happens
vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
vis->patchlumpnum = sprframe->lumppat[rot]; vis->patchlumpnum = sprframe->lumppat[rot];
vis->flip = flip; vis->flip = flip;
vis->mobj = thing; vis->mobj = thing;
vis->z1 = z1;
vis->z2 = z2;
//Hurdler: 25/04/2000: now support colormap in hardware mode //Hurdler: 25/04/2000: now support colormap in hardware mode
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"

View File

@ -89,7 +89,7 @@ patch_t *tallinfin;
// coop hud // coop hud
//------------------------------------------- //-------------------------------------------
patch_t *emeraldpics[3][7]; // 0 = normal, 1 = tiny, 2 = coinbox patch_t *emeraldpics[3][8]; // 0 = normal, 1 = tiny, 2 = coinbox
static patch_t *emblemicon; static patch_t *emblemicon;
patch_t *tokenicon; patch_t *tokenicon;
static patch_t *exiticon; static patch_t *exiticon;
@ -256,6 +256,7 @@ void HU_LoadGraphics(void)
emeraldpics[0][4] = W_CachePatchName("CHAOS5", PU_HUDGFX); emeraldpics[0][4] = W_CachePatchName("CHAOS5", PU_HUDGFX);
emeraldpics[0][5] = W_CachePatchName("CHAOS6", PU_HUDGFX); emeraldpics[0][5] = W_CachePatchName("CHAOS6", PU_HUDGFX);
emeraldpics[0][6] = W_CachePatchName("CHAOS7", PU_HUDGFX); emeraldpics[0][6] = W_CachePatchName("CHAOS7", PU_HUDGFX);
emeraldpics[0][7] = W_CachePatchName("CHAOS8", PU_HUDGFX);
emeraldpics[1][0] = W_CachePatchName("TEMER1", PU_HUDGFX); emeraldpics[1][0] = W_CachePatchName("TEMER1", PU_HUDGFX);
emeraldpics[1][1] = W_CachePatchName("TEMER2", PU_HUDGFX); emeraldpics[1][1] = W_CachePatchName("TEMER2", PU_HUDGFX);
@ -264,6 +265,7 @@ void HU_LoadGraphics(void)
emeraldpics[1][4] = W_CachePatchName("TEMER5", PU_HUDGFX); emeraldpics[1][4] = W_CachePatchName("TEMER5", PU_HUDGFX);
emeraldpics[1][5] = W_CachePatchName("TEMER6", PU_HUDGFX); emeraldpics[1][5] = W_CachePatchName("TEMER6", PU_HUDGFX);
emeraldpics[1][6] = W_CachePatchName("TEMER7", PU_HUDGFX); emeraldpics[1][6] = W_CachePatchName("TEMER7", PU_HUDGFX);
//emeraldpics[1][7] = W_CachePatchName("TEMER8", PU_HUDGFX); -- unused
emeraldpics[2][0] = W_CachePatchName("EMBOX1", PU_HUDGFX); emeraldpics[2][0] = W_CachePatchName("EMBOX1", PU_HUDGFX);
emeraldpics[2][1] = W_CachePatchName("EMBOX2", PU_HUDGFX); emeraldpics[2][1] = W_CachePatchName("EMBOX2", PU_HUDGFX);
@ -272,6 +274,7 @@ void HU_LoadGraphics(void)
emeraldpics[2][4] = W_CachePatchName("EMBOX5", PU_HUDGFX); emeraldpics[2][4] = W_CachePatchName("EMBOX5", PU_HUDGFX);
emeraldpics[2][5] = W_CachePatchName("EMBOX6", PU_HUDGFX); emeraldpics[2][5] = W_CachePatchName("EMBOX6", PU_HUDGFX);
emeraldpics[2][6] = W_CachePatchName("EMBOX7", PU_HUDGFX); emeraldpics[2][6] = W_CachePatchName("EMBOX7", PU_HUDGFX);
//emeraldpics[2][7] = W_CachePatchName("EMBOX8", PU_HUDGFX); -- unused
} }
// Initialise Heads up // Initialise Heads up

View File

@ -63,7 +63,7 @@ extern patch_t *tallnum[10];
extern patch_t *nightsnum[10]; extern patch_t *nightsnum[10];
extern patch_t *lt_font[LT_FONTSIZE]; extern patch_t *lt_font[LT_FONTSIZE];
extern patch_t *cred_font[CRED_FONTSIZE]; extern patch_t *cred_font[CRED_FONTSIZE];
extern patch_t *emeraldpics[3][7]; extern patch_t *emeraldpics[3][8];
extern patch_t *rflagico; extern patch_t *rflagico;
extern patch_t *bflagico; extern patch_t *bflagico;
extern patch_t *rmatcico; extern patch_t *rmatcico;

3355
src/info.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -768,6 +768,19 @@ static int lib_pCanRunOnWater(lua_State *L)
return 1; return 1;
} }
static int lib_pMaceRotate(lua_State *L)
{
mobj_t *center = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
INT32 baserot = luaL_checkinteger(L, 2);
INT32 baseprevrot = luaL_checkinteger(L, 3);
NOHUD
INLEVEL
if (!center)
return LUA_ErrInvalid(L, "mobj_t");
P_MaceRotate(center, baserot, baseprevrot);
return 0;
}
// P_USER // P_USER
//////////// ////////////
@ -1343,11 +1356,12 @@ static int lib_pRadiusAttack(lua_State *L)
mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); mobj_t *spot = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
fixed_t damagedist = luaL_checkfixed(L, 3); fixed_t damagedist = luaL_checkfixed(L, 3);
UINT8 damagetype = luaL_optinteger(L, 4, 0);
NOHUD NOHUD
INLEVEL INLEVEL
if (!spot || !source) if (!spot || !source)
return LUA_ErrInvalid(L, "mobj_t"); return LUA_ErrInvalid(L, "mobj_t");
P_RadiusAttack(spot, source, damagedist); P_RadiusAttack(spot, source, damagedist, damagetype);
return 0; return 0;
} }
@ -2517,6 +2531,7 @@ static luaL_Reg lib[] = {
{"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide}, {"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide},
{"P_CheckSolidLava",lib_pCheckSolidLava}, {"P_CheckSolidLava",lib_pCheckSolidLava},
{"P_CanRunOnWater",lib_pCanRunOnWater}, {"P_CanRunOnWater",lib_pCanRunOnWater},
{"P_MaceRotate",lib_pMaceRotate},
// p_user // p_user
{"P_GetPlayerHeight",lib_pGetPlayerHeight}, {"P_GetPlayerHeight",lib_pGetPlayerHeight},

View File

@ -85,7 +85,9 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum)
deny: deny:
//must be hacked/buggy client //must be hacked/buggy client
lua_settop(gL, 0); // clear stack if (gL) // check if Lua is actually turned on first, you dummmy -- Monster Iestyn 04/07/18
lua_settop(gL, 0); // clear stack
CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]); CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]);
if (server) if (server)
{ {

View File

@ -24,7 +24,7 @@ enum hud {
// NiGHTS mode // NiGHTS mode
hud_nightslink, hud_nightslink,
hud_nightsdrill, hud_nightsdrill,
hud_nightsrings, hud_nightsspheres,
hud_nightsscore, hud_nightsscore,
hud_nightstime, hud_nightstime,
hud_nightsrecords, hud_nightsrecords,

View File

@ -530,10 +530,22 @@ static int mobj_set(lua_State *L)
case mobj_bprev: case mobj_bprev:
return UNIMPLEMENTED; return UNIMPLEMENTED;
case mobj_hnext: case mobj_hnext:
mo->hnext = luaL_checkudata(L, 3, META_MOBJ); if (lua_isnil(L, 3))
P_SetTarget(&mo->hnext, NULL);
else
{
mobj_t *hnext = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
P_SetTarget(&mo->hnext, hnext);
}
break; break;
case mobj_hprev: case mobj_hprev:
mo->hprev = luaL_checkudata(L, 3, META_MOBJ); if (lua_isnil(L, 3))
P_SetTarget(&mo->hprev, NULL);
else
{
mobj_t *hprev = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
P_SetTarget(&mo->hprev, hprev);
}
break; break;
case mobj_type: // yeah sure, we'll let you change the mobj's type. case mobj_type: // yeah sure, we'll let you change the mobj's type.
{ {

View File

@ -130,6 +130,8 @@ static int player_get(lua_State *L)
lua_pushangle(L, plr->drawangle); lua_pushangle(L, plr->drawangle);
else if (fastcmp(field,"rings")) else if (fastcmp(field,"rings"))
lua_pushinteger(L, plr->rings); lua_pushinteger(L, plr->rings);
else if (fastcmp(field,"spheres"))
lua_pushinteger(L, plr->spheres);
else if (fastcmp(field,"pity")) else if (fastcmp(field,"pity"))
lua_pushinteger(L, plr->pity); lua_pushinteger(L, plr->pity);
else if (fastcmp(field,"currentweapon")) else if (fastcmp(field,"currentweapon"))
@ -298,8 +300,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->startedtime); lua_pushinteger(L, plr->startedtime);
else if (fastcmp(field,"finishedtime")) else if (fastcmp(field,"finishedtime"))
lua_pushinteger(L, plr->finishedtime); lua_pushinteger(L, plr->finishedtime);
else if (fastcmp(field,"finishedrings")) else if (fastcmp(field,"finishedspheres"))
lua_pushinteger(L, plr->finishedrings); lua_pushinteger(L, plr->finishedspheres);
else if (fastcmp(field,"marescore")) else if (fastcmp(field,"marescore"))
lua_pushinteger(L, plr->marescore); lua_pushinteger(L, plr->marescore);
else if (fastcmp(field,"lastmarescore")) else if (fastcmp(field,"lastmarescore"))
@ -400,6 +402,8 @@ static int player_set(lua_State *L)
plr->drawangle = luaL_checkangle(L, 3); plr->drawangle = luaL_checkangle(L, 3);
else if (fastcmp(field,"rings")) else if (fastcmp(field,"rings"))
plr->rings = (INT32)luaL_checkinteger(L, 3); plr->rings = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"spheres"))
plr->spheres = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"pity")) else if (fastcmp(field,"pity"))
plr->pity = (SINT8)luaL_checkinteger(L, 3); plr->pity = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"currentweapon")) else if (fastcmp(field,"currentweapon"))
@ -452,7 +456,7 @@ static int player_set(lua_State *L)
else if (fastcmp(field,"followitem")) else if (fastcmp(field,"followitem"))
plr->followitem = luaL_checkinteger(L, 3); plr->followitem = luaL_checkinteger(L, 3);
else if (fastcmp(field,"followmobj")) else if (fastcmp(field,"followmobj"))
plr->followmobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); P_SetTarget(&plr->followmobj, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
else if (fastcmp(field,"actionspd")) else if (fastcmp(field,"actionspd"))
plr->actionspd = (INT32)luaL_checkinteger(L, 3); plr->actionspd = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"mindash")) else if (fastcmp(field,"mindash"))
@ -578,8 +582,8 @@ static int player_set(lua_State *L)
plr->startedtime = (tic_t)luaL_checkinteger(L, 3); plr->startedtime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"finishedtime")) else if (fastcmp(field,"finishedtime"))
plr->finishedtime = (tic_t)luaL_checkinteger(L, 3); plr->finishedtime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"finishedrings")) else if (fastcmp(field,"finishedspheres"))
plr->finishedrings = (INT16)luaL_checkinteger(L, 3); plr->finishedspheres = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"marescore")) else if (fastcmp(field,"marescore"))
plr->marescore = (UINT32)luaL_checkinteger(L, 3); plr->marescore = (UINT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"lastmarescore")) else if (fastcmp(field,"lastmarescore"))

View File

@ -499,56 +499,211 @@ void Command_Teleport_f(void)
REQUIRE_INLEVEL; REQUIRE_INLEVEL;
REQUIRE_SINGLEPLAYER; REQUIRE_SINGLEPLAYER;
if (COM_Argc() < 3 || COM_Argc() > 7) if (COM_Argc() < 3 || COM_Argc() > 11)
{ {
CONS_Printf(M_GetText("teleport -x <value> -y <value> -z <value>: teleport to a location\n")); CONS_Printf(M_GetText("teleport -x <value> -y <value> -z <value> -ang <value> -aim <value>: teleport to a location\nteleport -sp <sequence> <placement>: teleport to specified checkpoint\n"));
return; return;
} }
if (!p->mo) if (!p->mo)
return; return;
i = COM_CheckParm("-x"); i = COM_CheckParm("-sp");
if (i)
intx = atoi(COM_Argv(i + 1));
else
{
CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "X");
return;
}
i = COM_CheckParm("-y");
if (i)
inty = atoi(COM_Argv(i + 1));
else
{
CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified\n"), "Y");
return;
}
ss = R_PointInSubsector(intx*FRACUNIT, inty*FRACUNIT);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));
return;
}
i = COM_CheckParm("-z");
if (i) if (i)
{ {
intz = atoi(COM_Argv(i + 1)); INT32 starpostnum = atoi(COM_Argv(i + 1)); // starpost number
intz <<= FRACBITS; INT32 starpostpath = atoi(COM_Argv(i + 2)); // quick, dirty way to distinguish between paths
if (intz < ss->sector->floorheight)
intz = ss->sector->floorheight; if (starpostnum < 0 || starpostpath < 0)
if (intz > ss->sector->ceilingheight - p->mo->height) {
intz = ss->sector->ceilingheight - p->mo->height; CONS_Alert(CONS_NOTICE, M_GetText("Negative starpost indexing is not valid.\n"));
return;
}
if (!starpostnum) // spawnpoints...
{
mapthing_t *mt;
if (starpostpath >= numcoopstarts)
{
CONS_Alert(CONS_NOTICE, M_GetText("Player %d spawnpoint not found (%d max).\n"), starpostpath+1, numcoopstarts-1);
return;
}
mt = playerstarts[starpostpath]; // Given above check, should never be NULL.
intx = mt->x<<FRACBITS;
inty = mt->y<<FRACBITS;
ss = R_IsPointInSubsector(intx, inty);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Spawnpoint not in a valid location.\n"));
return;
}
// Flagging a player's ambush will make them start on the ceiling
// Objectflip inverts
if (!!(mt->options & MTF_AMBUSH) ^ !!(mt->options & MTF_OBJECTFLIP))
{
intz = ss->sector->ceilingheight - p->mo->height;
if (mt->options >> ZSHIFT)
intz -= ((mt->options >> ZSHIFT) << FRACBITS);
}
else
{
intz = ss->sector->floorheight;
if (mt->options >> ZSHIFT)
intz += ((mt->options >> ZSHIFT) << FRACBITS);
}
if (mt->options & MTF_OBJECTFLIP) // flip the player!
{
p->mo->eflags |= MFE_VERTICALFLIP;
p->mo->flags2 |= MF2_OBJECTFLIP;
}
else
{
p->mo->eflags &= ~MFE_VERTICALFLIP;
p->mo->flags2 &= ~MF2_OBJECTFLIP;
}
localangle = p->mo->angle = p->drawangle = FixedAngle(mt->angle<<FRACBITS);
}
else // scan the thinkers to find starposts...
{
mobj_t *mo2;
thinker_t *th;
INT32 starpostmax = 0;
intz = starpostpath; // variable reuse - counting down for selection purposes
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo2 = (mobj_t *)th;
if (mo2->type != MT_STARPOST)
continue;
if (mo2->health != starpostnum)
{
if (mo2->health > starpostmax)
starpostmax = mo2->health;
continue;
}
if (intz--)
continue;
break;
}
if (th == &thinkercap)
{
if (intz == starpostpath)
CONS_Alert(CONS_NOTICE, M_GetText("No starpost of position %d found (%d max).\n"), starpostnum, starpostmax);
else
CONS_Alert(CONS_NOTICE, M_GetText("Starpost of position %d, %d not found (%d, %d max).\n"), starpostnum, starpostpath, starpostmax, (starpostpath-intz)-1);
return;
}
ss = R_IsPointInSubsector(mo2->x, mo2->y);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Starpost not in a valid location.\n"));
return;
}
intx = mo2->x;
inty = mo2->y;
intz = mo2->z;
if (mo2->flags2 & MF2_OBJECTFLIP) // flip the player!
{
p->mo->eflags |= MFE_VERTICALFLIP;
p->mo->flags2 |= MF2_OBJECTFLIP;
}
else
{
p->mo->eflags &= ~MFE_VERTICALFLIP;
p->mo->flags2 &= ~MF2_OBJECTFLIP;
}
localangle = p->mo->angle = p->drawangle = mo2->angle;
}
CONS_Printf(M_GetText("Teleporting to checkpoint %d, %d...\n"), starpostnum, starpostpath);
} }
else else
intz = ss->sector->floorheight; {
i = COM_CheckParm("-nop"); // undocumented stupid addition to allow pivoting on the spot with -ang and -aim
if (i)
{
intx = p->mo->x;
inty = p->mo->y;
}
else
{
i = COM_CheckParm("-x");
if (i)
intx = atoi(COM_Argv(i + 1))<<FRACBITS;
else
{
CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified.\n"), "X");
return;
}
CONS_Printf(M_GetText("Teleporting to %d, %d, %d...\n"), intx, inty, FixedInt(intz)); i = COM_CheckParm("-y");
if (i)
inty = atoi(COM_Argv(i + 1))<<FRACBITS;
else
{
CONS_Alert(CONS_NOTICE, M_GetText("%s value not specified.\n"), "Y");
return;
}
}
ss = R_IsPointInSubsector(intx, inty);
if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
{
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));
return;
}
i = COM_CheckParm("-z");
if (i)
{
intz = atoi(COM_Argv(i + 1))<<FRACBITS;
if (intz < ss->sector->floorheight)
intz = ss->sector->floorheight;
if (intz > ss->sector->ceilingheight - p->mo->height)
intz = ss->sector->ceilingheight - p->mo->height;
}
else
intz = ((p->mo->eflags & MFE_VERTICALFLIP) ? ss->sector->ceilingheight : ss->sector->floorheight);
i = COM_CheckParm("-ang");
if (i)
localangle = p->drawangle = p->mo->angle = FixedAngle(atoi(COM_Argv(i + 1))<<FRACBITS);
i = COM_CheckParm("-aim");
if (i)
{
angle_t aim = FixedAngle(atoi(COM_Argv(i + 1))<<FRACBITS);
if (aim >= ANGLE_90 && aim <= ANGLE_270)
{
CONS_Alert(CONS_NOTICE, M_GetText("Not a valid aiming angle (between +/-90).\n"));
return;
}
localaiming = p->aiming = aim;
}
CONS_Printf(M_GetText("Teleporting to %d, %d, %d...\n"), FixedInt(intx), FixedInt(inty), FixedInt(intz));
}
P_MapStart(); P_MapStart();
if (!P_TeleportMove(p->mo, intx*FRACUNIT, inty*FRACUNIT, intz)) if (!P_TeleportMove(p->mo, intx, inty, intz))
CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n"));
else else
S_StartSound(p->mo, sfx_mixup); S_StartSound(p->mo, sfx_mixup);
@ -728,7 +883,7 @@ void Command_Setrings_f(void)
// P_GivePlayerRings does value clamping // P_GivePlayerRings does value clamping
players[consoleplayer].rings = 0; players[consoleplayer].rings = 0;
P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1))); P_GivePlayerRings(&players[consoleplayer], atoi(COM_Argv(1)));
if (!G_IsSpecialStage(gamemap) || !useNightsSS) if (!G_IsSpecialStage(gamemap) || !(maptol & TOL_NIGHTS))
players[consoleplayer].totalring -= atoi(COM_Argv(1)); //undo totalring addition done in P_GivePlayerRings players[consoleplayer].totalring -= atoi(COM_Argv(1)); //undo totalring addition done in P_GivePlayerRings
G_SetGameModified(multiplayer); G_SetGameModified(multiplayer);
@ -744,9 +899,15 @@ void Command_Setlives_f(void)
if (COM_Argc() > 1) if (COM_Argc() > 1)
{ {
// P_GivePlayerLives does value clamping SINT8 lives = atoi(COM_Argv(1));
players[consoleplayer].lives = 0; if (lives == -1)
P_GivePlayerLives(&players[consoleplayer], atoi(COM_Argv(1))); players[consoleplayer].lives = 0x7f; // infinity!
else
{
// P_GivePlayerLives does value clamping
players[consoleplayer].lives = 0;
P_GivePlayerLives(&players[consoleplayer], atoi(COM_Argv(1)));
}
G_SetGameModified(multiplayer); G_SetGameModified(multiplayer);
} }
@ -1010,7 +1171,7 @@ void OP_NightsObjectplace(player_t *player)
mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS); mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS);
mt->angle = (INT16)(mt->angle+(INT16)((FixedInt(FixedDiv(temp*FRACUNIT, 360*(FRACUNIT/256))))<<8)); mt->angle = (INT16)(mt->angle+(INT16)((FixedInt(FixedDiv(temp*FRACUNIT, 360*(FRACUNIT/256))))<<8));
P_SpawnHoopsAndRings(mt); P_SpawnHoopsAndRings(mt, false);
} }
// This places a bumper! // This places a bumper!
@ -1024,26 +1185,26 @@ void OP_NightsObjectplace(player_t *player)
P_SpawnMapThing(mt); P_SpawnMapThing(mt);
} }
// This places a ring! // This places a sphere!
if (cmd->buttons & BT_WEAPONNEXT) if (cmd->buttons & BT_WEAPONNEXT)
{ {
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_ATTACKDOWN;
if (!OP_HeightOkay(player, false)) if (!OP_HeightOkay(player, false))
return; return;
mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_RING].doomednum, false); mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_BLUESPHERE].doomednum, false);
P_SpawnHoopsAndRings(mt); P_SpawnHoopsAndRings(mt, false);
} }
// This places a wing item! // This places a ring!
if (cmd->buttons & BT_WEAPONPREV) if (cmd->buttons & BT_WEAPONPREV)
{ {
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_ATTACKDOWN;
if (!OP_HeightOkay(player, false)) if (!OP_HeightOkay(player, false))
return; return;
mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_NIGHTSWING].doomednum, false); mt = OP_CreateNewMapThing(player, (UINT16)mobjinfo[MT_RING].doomednum, false);
P_SpawnHoopsAndRings(mt); P_SpawnHoopsAndRings(mt, false);
} }
// This places a custom object as defined in the console cv_mapthingnum. // This places a custom object as defined in the console cv_mapthingnum.
@ -1077,12 +1238,12 @@ void OP_NightsObjectplace(player_t *player)
if (mt->type == 300 // Ring if (mt->type == 300 // Ring
|| mt->type == 308 || mt->type == 309 // Team Rings || mt->type == 308 || mt->type == 309 // Team Rings
|| mt->type == 1706 // Nights Wing || mt->type == 1706 // Sphere
|| (mt->type >= 600 && mt->type <= 609) // Placement patterns || (mt->type >= 600 && mt->type <= 609) // Placement patterns
|| mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops || mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops
|| mt->type == 1800) // Mario Coin || mt->type == 1800) // Mario Coin
{ {
P_SpawnHoopsAndRings(mt); P_SpawnHoopsAndRings(mt, false);
} }
else else
P_SpawnMapThing(mt); P_SpawnMapThing(mt);
@ -1227,7 +1388,7 @@ void OP_ObjectplaceMovement(player_t *player)
|| mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops || mt->type == 1705 || mt->type == 1713 // NiGHTS Hoops
|| mt->type == 1800) // Mario Coin || mt->type == 1800) // Mario Coin
{ {
P_SpawnHoopsAndRings(mt); P_SpawnHoopsAndRings(mt, false);
} }
else else
P_SpawnMapThing(mt); P_SpawnMapThing(mt);

View File

@ -33,7 +33,9 @@
*/ */
fixed_t FixedMul(fixed_t a, fixed_t b) fixed_t FixedMul(fixed_t a, fixed_t b)
{ {
return (fixed_t)((((INT64)a * b) ) / FRACUNIT); // Need to cast to unsigned before shifting to avoid undefined behaviour
// for negative integers
return (fixed_t)(((UINT64)((INT64)a * b)) >> FRACBITS);
} }
#endif //__USE_C_FIXEDMUL__ #endif //__USE_C_FIXEDMUL__

View File

@ -458,7 +458,7 @@ consvar_t cv_ghost_guest = {"ghost_guest", "Show", CV_SAVE, ghost2_cons_
static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}};
static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}};
static CV_PossibleValue_t ringlimit_cons_t[] = {{0, "MIN"}, {9999, "MAX"}, {0, NULL}}; static CV_PossibleValue_t ringlimit_cons_t[] = {{0, "MIN"}, {9999, "MAX"}, {0, NULL}};
static CV_PossibleValue_t liveslimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NULL}}; static CV_PossibleValue_t liveslimit_cons_t[] = {{-1, "MIN"}, {99, "MAX"}, {0, NULL}};
static CV_PossibleValue_t dummymares_cons_t[] = { static CV_PossibleValue_t dummymares_cons_t[] = {
{-1, "END"}, {0,"Overall"}, {1,"Mare 1"}, {2,"Mare 2"}, {3,"Mare 3"}, {4,"Mare 4"}, {5,"Mare 5"}, {6,"Mare 6"}, {7,"Mare 7"}, {8,"Mare 8"}, {0,NULL} {-1, "END"}, {0,"Overall"}, {1,"Mare 1"}, {2,"Mare 2"}, {3,"Mare 3"}, {4,"Mare 4"}, {5,"Mare 5"}, {6,"Mare 6"}, {7,"Mare 7"}, {8,"Mare 8"}, {0,NULL}
}; };
@ -4938,6 +4938,7 @@ static void M_DrawAddons(void)
{ {
INT32 x, y; INT32 x, y;
ssize_t i, max; ssize_t i, max;
const char* topstr;
// hack - need to refresh at end of frame to handle addfile... // hack - need to refresh at end of frame to handle addfile...
if (refreshdirmenu & M_AddonsRefresh()) if (refreshdirmenu & M_AddonsRefresh())
@ -4949,9 +4950,16 @@ static void M_DrawAddons(void)
if (addonsresponselimit) if (addonsresponselimit)
addonsresponselimit--; addonsresponselimit--;
V_DrawCenteredString(BASEVIDWIDTH/2, 4+offs, 0, (Playing() if (Playing())
? "\x85""Adding files mid-game may cause problems." topstr = "\x85""Adding files mid-game may cause problems.";
: LOCATIONSTRING)); else if (savemoddata)
topstr = "\x83""Add-on has its own data, saving enabled.";
else if (modifiedgame)
topstr = "\x87""Game is modified, saving is disabled.";
else
topstr = LOCATIONSTRING;
V_DrawCenteredString(BASEVIDWIDTH/2, 4+offs, 0, topstr);
if (numwadfiles <= mainwads+1) if (numwadfiles <= mainwads+1)
y = 0; y = 0;
@ -5222,7 +5230,7 @@ static void M_HandleAddons(INT32 choice)
case EXT_SOC: case EXT_SOC:
case EXT_WAD: case EXT_WAD:
case EXT_PK3: case EXT_PK3:
COM_BufAddText(va("addfile %s%s", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING));
addonsresponselimit = 5; addonsresponselimit = 5;
break; break;
default: default:
@ -5266,7 +5274,10 @@ static void M_PandorasBox(INT32 choice)
{ {
(void)choice; (void)choice;
CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0)); CV_StealthSetValue(&cv_dummyrings, max(players[consoleplayer].rings, 0));
CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives); if (players[consoleplayer].lives == 0x7f)
CV_StealthSetValue(&cv_dummylives, -1);
else
CV_StealthSetValue(&cv_dummylives, players[consoleplayer].lives);
CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues); CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues);
SR_PandorasBox[6].status = ((players[consoleplayer].charflags & SF_SUPER) SR_PandorasBox[6].status = ((players[consoleplayer].charflags & SF_SUPER)
#ifndef DEVELOP #ifndef DEVELOP
@ -8441,6 +8452,13 @@ Update the maxplayers label...
static void M_ConnectIP(INT32 choice) static void M_ConnectIP(INT32 choice)
{ {
(void)choice; (void)choice;
if (*setupm_ip == 0)
{
M_StartMessage("You must specify an IP address.\n", NULL, MM_NOTHING);
return;
}
COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); COM_BufAddText(va("connect \"%s\"\n", setupm_ip));
// A little "please wait" message. // A little "please wait" message.
@ -8822,7 +8840,7 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
break; break;
S_StartSound(NULL,sfx_menu1); // Tails S_StartSound(NULL,sfx_menu1); // Tails
l = strlen(setupm_name); l = strlen(setupm_name);
if (l < MAXPLAYERNAME-1) if (l < MAXPLAYERNAME)
{ {
setupm_name[l] = (char)choice; setupm_name[l] = (char)choice;
setupm_name[l+1] = 0; setupm_name[l+1] = 0;

View File

@ -56,7 +56,9 @@ typedef off_t off64_t;
#endif #endif
#endif #endif
#if defined (_WIN32) #if defined(__MINGW32__) && ((__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3))
#define PRIdS "u"
#elif defined (_WIN32)
#define PRIdS "Iu" #define PRIdS "Iu"
#elif defined (DJGPP) #elif defined (DJGPP)
#define PRIdS "u" #define PRIdS "u"

File diff suppressed because it is too large Load Diff

View File

@ -2144,6 +2144,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
boolean floortouch = false; boolean floortouch = false;
fixed_t bottomheight, topheight; fixed_t bottomheight, topheight;
msecnode_t *node; msecnode_t *node;
ffloor_t *rover;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
@ -2191,6 +2192,19 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
{ {
targetsec = &sectors[targetsecnum]; targetsec = &sectors[targetsecnum];
// Find the FOF corresponding to the control linedef
for (rover = targetsec->ffloors; rover; rover = rover->next)
{
if (rover->master == sec->lines[i])
break;
}
if (!rover) // This should be impossible, but don't complain if it is the case somehow
continue;
if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there
continue;
for (j = 0; j < MAXPLAYERS; j++) for (j = 0; j < MAXPLAYERS; j++)
{ {
if (!playeringame[j]) if (!playeringame[j])
@ -3304,7 +3318,7 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
P_SetThingPosition(thing); P_SetThingPosition(thing);
if (thing->flags & MF_SHOOTABLE) if (thing->flags & MF_SHOOTABLE)
P_DamageMobj(thing, puncher, puncher, 1, 0); P_DamageMobj(thing, puncher, puncher, 1, 0);
else if (thing->type == MT_RING || thing->type == MT_COIN) else if (thing->type == MT_RING || thing->type == MT_COIN || thing->type == MT_TOKEN)
{ {
thing->momz = FixedMul(3*FRACUNIT, thing->scale); thing->momz = FixedMul(3*FRACUNIT, thing->scale);
P_TouchSpecialThing(thing, puncher, false); P_TouchSpecialThing(thing, puncher, false);

File diff suppressed because it is too large Load Diff

View File

@ -146,6 +146,7 @@ void P_SpawnShieldOrb(player_t *player);
void P_SwitchShield(player_t *player, UINT16 shieldtype); void P_SwitchShield(player_t *player, UINT16 shieldtype);
mobj_t *P_SpawnGhostMobj(mobj_t *mobj); mobj_t *P_SpawnGhostMobj(mobj_t *mobj);
void P_GivePlayerRings(player_t *player, INT32 num_rings); void P_GivePlayerRings(player_t *player, INT32 num_rings);
void P_GivePlayerSpheres(player_t *player, INT32 num_spheres);
void P_GivePlayerLives(player_t *player, INT32 numlives); void P_GivePlayerLives(player_t *player, INT32 numlives);
void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound); void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound);
UINT8 P_GetNextEmerald(void); UINT8 P_GetNextEmerald(void);
@ -256,6 +257,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f
boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover); boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover);
boolean P_CheckDeathPitCollide(mobj_t *mo); boolean P_CheckDeathPitCollide(mobj_t *mo);
boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover); boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover);
void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype);
mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type); mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type);
@ -280,6 +282,8 @@ mobj_t *P_GetClosestAxis(mobj_t *source);
boolean P_CanRunOnWater(player_t *player, ffloor_t *rover); boolean P_CanRunOnWater(player_t *player, ffloor_t *rover);
void P_MaceRotate(mobj_t *center, INT32 baserot, INT32 baseprevrot);
void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration); void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration);
#define PAL_WHITE 1 #define PAL_WHITE 1
#define PAL_MIXUP 2 #define PAL_MIXUP 2
@ -360,7 +364,7 @@ void P_DelPrecipSeclist(mprecipsecnode_t *node);
void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y); void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y);
void P_Initsecnode(void); void P_Initsecnode(void);
void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist); void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype);
fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height);
boolean PIT_PushableMoved(mobj_t *thing); boolean PIT_PushableMoved(mobj_t *thing);
@ -410,6 +414,8 @@ typedef struct BasicFF_s
#define DMG_DEATHPIT 0x80+3 #define DMG_DEATHPIT 0x80+3
#define DMG_CRUSHED 0x80+4 #define DMG_CRUSHED 0x80+4
#define DMG_SPECTATOR 0x80+5 #define DMG_SPECTATOR 0x80+5
// Masks
#define DMG_CANHURTSELF 0x40 // Flag - can hurt self/team indirectly, such as through mines
#define DMG_DEATHMASK DMG_INSTAKILL // if bit 7 is set, this is a death type instead of a damage type #define DMG_DEATHMASK DMG_INSTAKILL // if bit 7 is set, this is a death type instead of a damage type
void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period); void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period);

View File

@ -109,21 +109,148 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
// MOVEMENT ITERATOR FUNCTIONS // MOVEMENT ITERATOR FUNCTIONS
// ========================================================================= // =========================================================================
// P_DoSpring
//
// MF_SPRING does some weird, mildly hacky stuff sometimes.
// mass = vertical speed
// damage = horizontal speed
// raisestate = state to change spring to on collision
// reactiontime = number of times it can give 10 points (0 is standard)
// painchance = spring mode:
// 0 = standard vanilla spring behaviour
// Positive spring modes are minor variants of vanilla spring behaviour.
// 1 = launch players in jump
// 2 = don't modify player at all, just add momentum
// Negative spring modes are mildly-related gimmicks with customisation.
// -1 = pinball bumper
// Any other spring mode defaults to standard vanilla spring behaviour,
// ****** but forward compatibility is not guaranteed for these. ******
//
boolean P_DoSpring(mobj_t *spring, mobj_t *object) boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{ {
INT32 pflags;
fixed_t offx, offy;
fixed_t vertispeed = spring->info->mass; fixed_t vertispeed = spring->info->mass;
fixed_t horizspeed = spring->info->damage; fixed_t horizspeed = spring->info->damage;
UINT8 secondjump; boolean final;
if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic // Object was already sprung this tic
if (object->eflags & MFE_SPRUNG)
return false; return false;
// Spectators don't trigger springs. // Spectators don't trigger springs.
if (object->player && object->player->spectator) if (object->player && object->player->spectator)
return false; return false;
// "Even in Death" is a song from Volume 8, not a command.
if (!spring->health || !object->health)
return false;
if (spring->info->painchance == -1) // Pinball bumper mode.
{
// The first of the entirely different spring modes!
// Some of the attributes mean different things here.
// mass = default strength (can be controlled by mapthing's spawnangle)
// damage = unused
angle_t horizangle, vertiangle;
if (!vertispeed)
return false;
if (object->player && object->player->homing) // Sonic Heroes and Shadow the Hedgehog are the only games to contain homing-attackable bumpers!
{
horizangle = 0;
vertiangle = ((object->eflags & MFE_VERTICALFLIP) ? ANGLE_270 : ANGLE_90) >> ANGLETOFINESHIFT;
object->player->pflags &= ~PF_THOKKED;
if (spring->eflags & MFE_VERTICALFLIP)
object->z = spring->z - object->height - 1;
else
object->z = spring->z + spring->height + 1;
}
else
{
horizangle = R_PointToAngle2(spring->x, spring->y, object->x, object->y);
vertiangle = (R_PointToAngle2(
0,
spring->z + spring->height/2,
FixedHypot(object->x - spring->x, object->y - spring->y),
object->z + object->height/2)
>> ANGLETOFINESHIFT) & FINEMASK;
}
if (spring->spawnpoint && spring->spawnpoint->angle > 0)
vertispeed = (spring->spawnpoint->angle<<(FRACBITS-1))/5;
vertispeed = FixedMul(vertispeed, FixedMul(object->scale, spring->scale));
if (object->player)
{
fixed_t playervelocity;
if (!(object->player->pflags & PF_THOKKED) && !(object->player->homing)
&& ((playervelocity = FixedDiv(9*FixedHypot(object->player->speed, object->momz), 10<<FRACBITS)) > vertispeed))
vertispeed = playervelocity;
if (object->player->powers[pw_carry] == CR_NIGHTSMODE) // THIS has NiGHTS support, at least...
{
angle_t nightsangle = 0;
if (object->player->bumpertime >= TICRATE/4)
return false;
if ((object->player->pflags & PF_TRANSFERTOCLOSEST) && object->player->axis1 && object->player->axis2)
{
nightsangle = R_PointToAngle2(object->player->axis1->x, object->player->axis1->y, object->player->axis2->x, object->player->axis2->y);
nightsangle += ANGLE_90;
}
else if (object->target)
{
if (object->target->flags2 & MF2_AMBUSH)
nightsangle = R_PointToAngle2(object->target->x, object->target->y, object->x, object->y);
else
nightsangle = R_PointToAngle2(object->x, object->y, object->target->x, object->target->y);
}
object->player->flyangle = AngleFixed(R_PointToAngle2(
0,
spring->z + spring->height/2,
FixedMul(
FINESINE(((nightsangle - horizangle) >> ANGLETOFINESHIFT) & FINEMASK),
FixedHypot(object->x - spring->x, object->y - spring->y)),
object->z + object->height/2))>>FRACBITS;
object->player->bumpertime = TICRATE/2;
}
else
{
INT32 pflags = object->player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // Not identical to below...
UINT8 secondjump = object->player->secondjump;
if (object->player->pflags & PF_GLIDING)
P_SetPlayerMobjState(object, S_PLAY_FALL);
P_ResetPlayer(object->player);
object->player->pflags |= pflags;
object->player->secondjump = secondjump;
}
}
if (!P_IsObjectOnGround(object)) // prevents uncurling when spinning due to "landing"
object->momz = FixedMul(vertispeed, FINESINE(vertiangle));
P_InstaThrust(object, horizangle, FixedMul(vertispeed, FINECOSINE(vertiangle)));
object->eflags |= MFE_SPRUNG; // apply this flag asap!
goto springstate;
}
// Does nothing?
if (!vertispeed && !horizspeed)
return false;
#ifdef ESLOPE
object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you.
#endif
if (spring->eflags & MFE_VERTICALFLIP)
vertispeed *= -1;
if (object->player && (object->player->powers[pw_carry] == CR_NIGHTSMODE)) if (object->player && (object->player->powers[pw_carry] == CR_NIGHTSMODE))
{ {
/*Someone want to make these work like bumpers?*/ /*Someone want to make these work like bumpers?*/
@ -135,48 +262,51 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|| (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2))) || (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2)))
{ {
S_StartSound(object, sfx_s3k8b); S_StartSound(object, sfx_s3k8b);
horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3); if (horizspeed)
vertispeed = FixedMul(vertispeed, (6*FRACUNIT)/5); // aprox square root of above horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3);
if (vertispeed)
vertispeed = FixedMul(vertispeed, (6*FRACUNIT)/5); // aprox square root of above
} }
object->eflags |= MFE_SPRUNG; // apply this flag asap! object->eflags |= MFE_SPRUNG; // apply this flag asap!
spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify spring->flags &= ~(MF_SPRING|MF_SPECIAL); // De-solidify
if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA if (spring->info->painchance != 2)
{ {
object->momx = object->momy = 0; if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA
P_TryMove(object, spring->x, spring->y, true); {
} object->momx = object->momy = 0;
P_TryMove(object, spring->x, spring->y, true);
}
if (spring->eflags & MFE_VERTICALFLIP) if (vertispeed > 0)
vertispeed *= -1; object->z = spring->z + spring->height + 1;
else if (vertispeed < 0)
object->z = spring->z - object->height - 1;
else
{
fixed_t offx, offy;
// Horizontal springs teleport you in FRONT of them.
object->momx = object->momy = 0;
if (vertispeed > 0) // Overestimate the distance to position you at
object->z = spring->z + spring->height + 1; offx = P_ReturnThrustX(spring, spring->angle, (spring->radius + object->radius + 1) * 2);
else if (vertispeed < 0) offy = P_ReturnThrustY(spring, spring->angle, (spring->radius + object->radius + 1) * 2);
object->z = spring->z - object->height - 1;
else
{
// Horizontal springs teleport you in FRONT of them.
object->momx = object->momy = 0;
// Overestimate the distance to position you at // Make it square by clipping
offx = P_ReturnThrustX(spring, spring->angle, (spring->radius + object->radius + 1) * 2); if (offx > (spring->radius + object->radius + 1))
offy = P_ReturnThrustY(spring, spring->angle, (spring->radius + object->radius + 1) * 2); offx = spring->radius + object->radius + 1;
else if (offx < -(spring->radius + object->radius + 1))
offx = -(spring->radius + object->radius + 1);
// Make it square by clipping if (offy > (spring->radius + object->radius + 1))
if (offx > (spring->radius + object->radius + 1)) offy = spring->radius + object->radius + 1;
offx = spring->radius + object->radius + 1; else if (offy < -(spring->radius + object->radius + 1))
else if (offx < -(spring->radius + object->radius + 1)) offy = -(spring->radius + object->radius + 1);
offx = -(spring->radius + object->radius + 1);
if (offy > (spring->radius + object->radius + 1)) // Set position!
offy = spring->radius + object->radius + 1; P_TryMove(object, spring->x + offx, spring->y + offy, true);
else if (offy < -(spring->radius + object->radius + 1)) }
offy = -(spring->radius + object->radius + 1);
// Set position!
P_TryMove(object, spring->x + offx, spring->y + offy, true);
} }
if (vertispeed) if (vertispeed)
@ -186,12 +316,14 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(horizspeed,FixedSqrt(FixedMul(object->scale, spring->scale)))); P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(horizspeed,FixedSqrt(FixedMul(object->scale, spring->scale))));
// Re-solidify // Re-solidify
spring->flags |= (spring->info->flags & (MF_SPECIAL|MF_SOLID)); spring->flags |= (spring->info->flags & (MF_SPRING|MF_SPECIAL));
P_SetMobjState(spring, spring->info->raisestate);
if (object->player) if (object->player)
{ {
INT32 pflags;
UINT8 secondjump;
boolean washoming;
if (spring->flags & MF_ENEMY) // Spring shells if (spring->flags & MF_ENEMY) // Spring shells
P_SetTarget(&spring->target, object); P_SetTarget(&spring->target, object);
@ -212,19 +344,28 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
} }
} }
pflags = object->player->pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_SHIELDABILITY|PF_BOUNCING); // I still need these. pflags = object->player->pflags & (PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // I still need these.
secondjump = object->player->secondjump; secondjump = object->player->secondjump;
washoming = object->player->homing;
if (object->player->pflags & PF_GLIDING)
P_SetPlayerMobjState(object, S_PLAY_FALL);
P_ResetPlayer(object->player); P_ResetPlayer(object->player);
if (spring->info->painchance) if (spring->info->painchance == 1) // For all those ancient, SOC'd abilities.
{ {
object->player->pflags |= P_GetJumpFlags(object->player); object->player->pflags |= P_GetJumpFlags(object->player);
P_SetPlayerMobjState(object, S_PLAY_JUMP); P_SetPlayerMobjState(object, S_PLAY_JUMP);
} }
else if (!vertispeed || (pflags & PF_BOUNCING)) // horizontal spring or bouncing else if ((spring->info->painchance == 2) || (pflags & PF_BOUNCING)) // Adding momentum only.
{ {
if ((pflags & PF_BOUNCING) object->player->pflags |= (pflags &~ PF_STARTJUMP);
|| (pflags & (PF_JUMPED|PF_SPINNING) && (object->player->panim == PA_ROLL || object->player->panim == PA_JUMP || object->player->panim == PA_FALL))) object->player->secondjump = secondjump;
if (washoming)
object->player->pflags &= ~PF_THOKKED;
}
else if (!vertispeed)
{
if (pflags & (PF_JUMPED|PF_SPINNING))
{ {
object->player->pflags |= pflags; object->player->pflags |= pflags;
object->player->secondjump = secondjump; object->player->secondjump = secondjump;
@ -239,10 +380,25 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
} }
#ifdef ESLOPE #ifdef ESLOPE
object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you. object->standingslope = NULL; // And again.
#endif #endif
return true; final = true;
springstate:
if ((statenum_t)(spring->state-states) < spring->info->raisestate)
{
P_SetMobjState(spring, spring->info->raisestate);
if (object->player && spring->reactiontime && !(spring->info->flags & MF_ENEMY))
{
if (object->player->powers[pw_carry] != CR_NIGHTSMODE) // don't make graphic in NiGHTS
P_SetMobjState(P_SpawnMobj(spring->x, spring->y, spring->z + (spring->height/2), MT_SCORE), mobjinfo[MT_SCORE].spawnstate+11);
P_AddPlayerScore(object->player, 10);
spring->reactiontime--;
}
}
return final;
} }
static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
@ -398,7 +554,6 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
static boolean PIT_CheckThing(mobj_t *thing) static boolean PIT_CheckThing(mobj_t *thing)
{ {
fixed_t blockdist; fixed_t blockdist;
boolean iwassprung = false;
// don't clip against self // don't clip against self
if (thing == tmthing) if (thing == tmthing)
@ -514,7 +669,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; return true;
} }
if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE))) if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING)))
return true; return true;
// Don't collide with your buddies while NiGHTS-flying. // Don't collide with your buddies while NiGHTS-flying.
@ -622,6 +777,54 @@ static boolean PIT_CheckThing(mobj_t *thing)
} }
#endif #endif
// Billiards mines!
if (thing->type == MT_BIGMINE)
{
if (tmthing->type == MT_BIGMINE)
{
if (!tmthing->momx && !tmthing->momy)
return true;
if ((statenum_t)(thing->state-states) >= thing->info->meleestate)
return true;
if (thing->z > tmthing->z + tmthing->height)
return true; // overhead
if (thing->z + thing->height < tmthing->z)
return true; // underneath
thing->momx = tmthing->momx/3;
thing->momy = tmthing->momy/3;
thing->momz = tmthing->momz/3;
tmthing->momx /= -8;
tmthing->momy /= -8;
tmthing->momz /= -8;
if (thing->info->activesound)
S_StartSound(thing, thing->info->activesound);
P_SetMobjState(thing, thing->info->meleestate);
P_SetTarget(&thing->tracer, tmthing->tracer);
return true;
}
else if (tmthing->type == MT_CRUSHCLAW)
{
if (tmthing->extravalue1 <= 0)
return true;
if ((statenum_t)(thing->state-states) >= thing->info->meleestate)
return true;
if (thing->z > tmthing->z + tmthing->height)
return true; // overhead
if (thing->z + thing->height < tmthing->z)
return true; // underneath
thing->momx = P_ReturnThrustX(tmthing, tmthing->angle, 2*tmthing->extravalue1*tmthing->scale/3);
thing->momy = P_ReturnThrustY(tmthing, tmthing->angle, 2*tmthing->extravalue1*tmthing->scale/3);
if (thing->info->activesound)
S_StartSound(thing, thing->info->activesound);
P_SetMobjState(thing, thing->info->meleestate);
if (tmthing->tracer)
P_SetTarget(&thing->tracer, tmthing->tracer->target);
return false;
}
}
// When solid spikes move, assume they just popped up and teleport things on top of them to hurt. // When solid spikes move, assume they just popped up and teleport things on top of them to hurt.
if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID) if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID)
{ {
@ -639,35 +842,37 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; return true;
} }
if (thing->flags & MF_PAIN) if (thing->flags & MF_PAIN && tmthing->player)
{ // Player touches painful thing sitting on the floor { // Player touches painful thing sitting on the floor
// see if it went over / under // see if it went over / under
if (thing->z > tmthing->z + tmthing->height) if (thing->z > tmthing->z + tmthing->height)
return true; // overhead return true; // overhead
if (thing->z + thing->height < tmthing->z) if (thing->z + thing->height < tmthing->z)
return true; // underneath return true; // underneath
if (tmthing->player && tmthing->flags & MF_SHOOTABLE && thing->health > 0) if (tmthing->flags & MF_SHOOTABLE && thing->health > 0)
{ {
UINT8 damagetype = 0; UINT8 damagetype = (thing->info->mass & 0xFF);
if (thing->flags & MF_FIRE) // BURN! if (!damagetype && thing->flags & MF_FIRE) // BURN!
damagetype = DMG_FIRE; damagetype = DMG_FIRE;
P_DamageMobj(tmthing, thing, thing, 1, damagetype); if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8)))
S_StartSound(thing, damagetype);
} }
return true; return true;
} }
else if (tmthing->flags & MF_PAIN) else if (tmthing->flags & MF_PAIN && thing->player)
{ // Painful thing splats player in the face { // Painful thing splats player in the face
// see if it went over / under // see if it went over / under
if (tmthing->z > thing->z + thing->height) if (tmthing->z > thing->z + thing->height)
return true; // overhead return true; // overhead
if (tmthing->z + tmthing->height < thing->z) if (tmthing->z + tmthing->height < thing->z)
return true; // underneath return true; // underneath
if (thing->player && thing->flags & MF_SHOOTABLE && tmthing->health > 0) if (thing->flags & MF_SHOOTABLE && tmthing->health > 0)
{ {
UINT8 damagetype = 0; UINT8 damagetype = (tmthing->info->mass & 0xFF);
if (tmthing->flags & MF_FIRE) // BURN! if (!damagetype && tmthing->flags & MF_FIRE) // BURN!
damagetype = DMG_FIRE; damagetype = DMG_FIRE;
P_DamageMobj(thing, tmthing, tmthing, 1, damagetype); if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && (damagetype = (tmthing->info->mass>>8)))
S_StartSound(tmthing, damagetype);
} }
return true; return true;
} }
@ -714,6 +919,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down
return true; return true;
} }
// missiles can hit other things // missiles can hit other things
if (tmthing->flags & MF_MISSILE || tmthing->type == MT_SHELL) if (tmthing->flags & MF_MISSILE || tmthing->type == MT_SHELL)
{ {
@ -768,30 +974,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->type == MT_EGGSHIELD) if (thing->type == MT_EGGSHIELD)
{ {
fixed_t touchx, touchy; angle_t angle = (R_PointToAngle2(thing->x, thing->y, tmthing->x - tmthing->momx, tmthing->y - tmthing->momy) - thing->angle) - ANGLE_90;
angle_t angle;
if (P_AproxDistance(tmthing->x-thing->x, tmthing->y-thing->y) > if (angle < ANGLE_180) // hit shield from behind, shield is destroyed!
P_AproxDistance((tmthing->x-tmthing->momx)-thing->x, (tmthing->y-tmthing->momy)-thing->y))
{
touchx = tmthing->x + tmthing->momx;
touchy = tmthing->y + tmthing->momy;
}
else
{
touchx = tmthing->x;
touchy = tmthing->y;
}
angle = R_PointToAngle2(thing->x, thing->y, touchx, touchy) - thing->angle;
if (!(angle > ANGLE_90 && angle < ANGLE_270)) // hit front of shield, didn't destroy it
return false;
else // hit shield from behind, shield is destroyed!
{
P_KillMobj(thing, tmthing, tmthing, 0); P_KillMobj(thing, tmthing, tmthing, 0);
return false; return false;
}
} }
// damage / explode // damage / explode
@ -835,7 +1022,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
P_SetThingPosition(tmthing); P_SetThingPosition(tmthing);
} }
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial
P_DamageMobj(thing, tmthing, tmthing->target, 1, 0); {
UINT8 damagetype = tmthing->info->mass;
if (!damagetype && tmthing->flags & MF_FIRE) // BURN!
damagetype = DMG_FIRE;
P_DamageMobj(thing, tmthing, tmthing->target, 1, damagetype);
}
// don't traverse any more // don't traverse any more
@ -1039,15 +1231,28 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->flags & MF_PUSHABLE) if (tmthing->flags & MF_PUSHABLE)
{ {
if (thing->type == MT_FAN || thing->type == MT_STEAM) if (thing->type == MT_FAN || thing->type == MT_STEAM)
{
P_DoFanAndGasJet(thing, tmthing); P_DoFanAndGasJet(thing, tmthing);
return true;
}
else if (thing->flags & MF_SPRING) else if (thing->flags & MF_SPRING)
{ {
if ( thing->z <= tmthing->z + tmthing->height if ( thing->z <= tmthing->z + tmthing->height
&& tmthing->z <= thing->z + thing->height) && tmthing->z <= thing->z + thing->height)
iwassprung = P_DoSpring(thing, tmthing); if (P_DoSpring(thing, tmthing))
return false;
return true;
} }
} }
// thanks to sal for solidenemies dot lua
if (thing->flags & (MF_ENEMY|MF_BOSS) && tmthing->flags & (MF_ENEMY|MF_BOSS))
{
if ((thing->z + thing->height >= tmthing->z)
&& (tmthing->z + tmthing->height >= thing->z))
return false;
}
// Damage other players when invincible // Damage other players when invincible
if (tmthing->player && thing->player if (tmthing->player && thing->player
// Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person. // Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person.
@ -1112,7 +1317,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
{ {
// Objects kill you if it falls from above. // Objects kill you if it falls from above.
if (thing != tmthing->target) if (thing != tmthing->target)
P_DamageMobj(thing, tmthing, tmthing->target, 1, DMG_INSTAKILL); P_DamageMobj(thing, tmthing, tmthing->target, 1, DMG_CRUSHED);
tmthing->momz = -tmthing->momz/2; // Bounce, just for fun! tmthing->momz = -tmthing->momz/2; // Bounce, just for fun!
// The tmthing->target allows the pusher of the object // The tmthing->target allows the pusher of the object
@ -1135,75 +1340,62 @@ static boolean PIT_CheckThing(mobj_t *thing)
{ {
if ( thing->z <= tmthing->z + tmthing->height if ( thing->z <= tmthing->z + tmthing->height
&& tmthing->z <= thing->z + thing->height) && tmthing->z <= thing->z + thing->height)
iwassprung = P_DoSpring(thing, tmthing); if (P_DoSpring(thing, tmthing))
return false;
return true;
} }
// Are you touching the side of the object you're interacting with? // Monitor?
else if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height else if (thing->flags & MF_MONITOR
&& thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z) && !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2)))
{ {
// 0 = none, 1 = elemental pierce, 2 = bubble bounce // 0 = none, 1 = elemental pierce, 2 = bubble bounce
UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY) UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY)
? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2) ? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
: 0); : 0);
if (thing->flags & MF_MONITOR if (!(thing->flags & MF_SOLID)
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING) || tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED) || ((tmthing->player->pflags & PF_JUMPED)
&& (!(tmthing->player->pflags & PF_NOJUMPDAMAGE) && (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY))) || (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2) || (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING) || ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)) && (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
|| elementalpierce)) || elementalpierce)
{ {
player_t *player = tmthing->player; if (thing->z - thing->scale <= tmthing->z + tmthing->height
SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed. && thing->z + thing->height + thing->scale >= tmthing->z)
fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
fixed_t *z = &tmthing->z; // aau.
P_DamageMobj(thing, tmthing, tmthing, 1, 0); // break the monitor
// Going down? Then bounce back up.
if ((P_MobjWasRemoved(thing) // Monitor was removed
|| !thing->health) // or otherwise popped
&& (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up
&& (elementalpierce != 1)) // you're not piercing through the monitor...
{ {
if (elementalpierce == 2) player_t *player = tmthing->player;
P_DoBubbleBounce(player); SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)) fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically. fixed_t *z = &tmthing->z; // aau.
// Going down? Then bounce back up.
if (P_DamageMobj(thing, tmthing, tmthing, 1, 0) // break the monitor
&& (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up
&& (elementalpierce != 1)) // you're not piercing through the monitor...
{
if (elementalpierce == 2)
P_DoBubbleBounce(player);
else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
}
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
{
if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false);
return false;
}
else
*z -= *momz; // to ensure proper collision.
} }
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
{ return true;
if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false);
return false;
}
else
*z -= *momz; // to ensure proper collision.
} }
} }
} }
if (!(tmthing->player) && (thing->player)) if ((!tmthing->player) && (thing->player))
; // no solid thing should ever be able to step up onto a player ; // no solid thing should ever be able to step up onto a player
else if (thing->flags & MF_SPRING && (tmthing->player || tmthing->flags & MF_PUSHABLE))
{
if (iwassprung) // this spring caused you to gain MFE_SPRUNG just now...
return false; // "cancel" P_TryMove via blocking so you keep your current position
}
else if (tmthing->flags & MF_SPRING && (thing->flags & MF_PUSHABLE))
; // Fix a few nasty spring-jumping bugs that happen sometimes.
// Monitors are not treated as solid to players who are jumping, spinning or gliding,
// unless it's a CTF team monitor and you're on the wrong team
else if (thing->flags & MF_MONITOR && tmthing->player
&& (tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED)
&& (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0)))
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2)))
;
// z checking at last // z checking at last
// Treat noclip things as non-solid! // Treat noclip things as non-solid!
else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID
@ -1230,16 +1422,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
if (thing->flags & MF_SPRING)
;
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// since return false doesn't handle momentum properly, // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high // we lie to P_TryMove() so it's always too high
else if (tmthing->player && tmthing->z + tmthing->height > topz if (tmthing->player && tmthing->z + tmthing->height > topz
&& tmthing->z + tmthing->height < tmthing->ceilingz) && tmthing->z + tmthing->height < tmthing->ceilingz)
{ {
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack...
return false; return false;
tmfloorz = tmceilingz = topz; // block while in air tmfloorz = tmceilingz = topz; // block while in air
@ -1276,16 +1466,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
if (thing->flags & MF_SPRING)
;
// block only when jumping not high enough, // block only when jumping not high enough,
// (dont climb max. 24units while already in air) // (dont climb max. 24units while already in air)
// since return false doesn't handle momentum properly, // since return false doesn't handle momentum properly,
// we lie to P_TryMove() so it's always too high // we lie to P_TryMove() so it's always too high
else if (tmthing->player && tmthing->z < topz if (tmthing->player && tmthing->z < topz
&& tmthing->z > tmthing->floorz) && tmthing->z > tmthing->floorz)
{ {
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->flags2 & MF2_STANDONME)) // Gold monitor hack... if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack...
return false; return false;
tmfloorz = tmceilingz = topz; // block while in air tmfloorz = tmceilingz = topz; // block while in air
@ -3507,6 +3695,7 @@ bounceback:
static fixed_t bombdamage; static fixed_t bombdamage;
static mobj_t *bombsource; static mobj_t *bombsource;
static mobj_t *bombspot; static mobj_t *bombspot;
static UINT8 bombdamagetype;
// //
// PIT_RadiusAttack // PIT_RadiusAttack
@ -3517,17 +3706,13 @@ static boolean PIT_RadiusAttack(mobj_t *thing)
{ {
fixed_t dx, dy, dz, dist; fixed_t dx, dy, dz, dist;
if (thing == bombspot // ignore the bomb itself (Deton fix) if (thing == bombspot) // ignore the bomb itself (Deton fix)
|| (bombsource && thing->type == bombsource->type)) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.)
return true; return true;
if (!(thing->flags & MF_SHOOTABLE)) if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) != MF_SHOOTABLE)
return true; return true;
if (thing->flags & MF_BOSS) if (bombsource && thing->type == bombsource->type && !(bombdamagetype & DMG_CANHURTSELF)) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.)
return true;
if (thing->flags & MF_MONITOR)
return true; return true;
dx = abs(thing->x - bombspot->x); dx = abs(thing->x - bombspot->x);
@ -3551,7 +3736,7 @@ static boolean PIT_RadiusAttack(mobj_t *thing)
if (P_CheckSight(thing, bombspot)) if (P_CheckSight(thing, bombspot))
{ // must be in direct path { // must be in direct path
P_DamageMobj(thing, bombspot, bombsource, 1, 0); // Tails 01-11-2001 P_DamageMobj(thing, bombspot, bombsource, 1, bombdamagetype); // Tails 01-11-2001
} }
return true; return true;
@ -3561,7 +3746,7 @@ static boolean PIT_RadiusAttack(mobj_t *thing)
// P_RadiusAttack // P_RadiusAttack
// Source is the creature that caused the explosion at spot. // Source is the creature that caused the explosion at spot.
// //
void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist) void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype)
{ {
INT32 x, y; INT32 x, y;
INT32 xl, xh, yl, yh; INT32 xl, xh, yl, yh;
@ -3578,6 +3763,7 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist)
bombspot = spot; bombspot = spot;
bombsource = source; bombsource = source;
bombdamage = FixedMul(damagedist, spot->scale); bombdamage = FixedMul(damagedist, spot->scale);
bombdamagetype = damagetype;
for (y = yl; y <= yh; y++) for (y = yl; y <= yh; y++)
for (x = xl; x <= xh; x++) for (x = xl; x <= xh; x++)

File diff suppressed because it is too large Load Diff

View File

@ -175,8 +175,8 @@ typedef enum
MF2_SCATTER = 1<<8, // Thrown ring has scatter properties MF2_SCATTER = 1<<8, // Thrown ring has scatter properties
MF2_BEYONDTHEGRAVE = 1<<9, // Source of this missile has died and has since respawned. MF2_BEYONDTHEGRAVE = 1<<9, // Source of this missile has died and has since respawned.
MF2_SLIDEPUSH = 1<<10, // MF_PUSHABLE that pushes continuously. MF2_SLIDEPUSH = 1<<10, // MF_PUSHABLE that pushes continuously.
MF2_CLASSICPUSH = 1<<11, // Drops straight down when object has negative Z. MF2_CLASSICPUSH = 1<<11, // Drops straight down when object has negative momz.
MF2_STANDONME = 1<<12, // While not pushable, stand on me anyway. MF2_INVERTAIMABLE = 1<<12, // Flips whether it's targetable by A_LookForEnemies (enemies no, decoys yes)
MF2_INFLOAT = 1<<13, // Floating to a height for a move, don't auto float to target's height. MF2_INFLOAT = 1<<13, // Floating to a height for a move, don't auto float to target's height.
MF2_DEBRIS = 1<<14, // Splash ring from explosion ring MF2_DEBRIS = 1<<14, // Splash ring from explosion ring
MF2_NIGHTSPULL = 1<<15, // Attracted from a paraloop MF2_NIGHTSPULL = 1<<15, // Attracted from a paraloop
@ -194,7 +194,6 @@ typedef enum
MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH
MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position)
MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use)
MF2_MACEROTATE = 1<<30, // Thinker calls P_MaceRotate around tracer
// free: to and including 1<<31 // free: to and including 1<<31
} mobjflag2_t; } mobjflag2_t;
@ -315,7 +314,7 @@ typedef struct mobj_s
mobjtype_t type; mobjtype_t type;
const mobjinfo_t *info; // &mobjinfo[mobj->type] const mobjinfo_t *info; // &mobjinfo[mobj->type]
INT32 health; // for player this is rings + 1 INT32 health; // for player this is rings + 1 -- no it isn't, not any more!!
// Movement direction, movement generation (zig-zagging). // Movement direction, movement generation (zig-zagging).
angle_t movedir; // dirtype_t 0-7; also used by Deton for up/down angle angle_t movedir; // dirtype_t 0-7; also used by Deton for up/down angle
@ -389,6 +388,7 @@ typedef struct precipmobj_s
angle_t angle; // orientation angle_t angle; // orientation
spritenum_t sprite; // used to find patch_t and flip value spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h UINT32 frame; // frame number, plus bits see p_pspr.h
UINT8 sprite2; // player sprites
UINT16 anim_duration; // for FF_ANIMATE states UINT16 anim_duration; // for FF_ANIMATE states
struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears
@ -436,7 +436,7 @@ void P_MovePlayerToStarpost(INT32 playernum);
void P_AfterPlayerSpawn(INT32 playernum); void P_AfterPlayerSpawn(INT32 playernum);
void P_SpawnMapThing(mapthing_t *mthing); void P_SpawnMapThing(mapthing_t *mthing);
void P_SpawnHoopsAndRings(mapthing_t *mthing); void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime);
void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle); void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle);
void P_SpawnPrecipitation(void); void P_SpawnPrecipitation(void);
void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, statenum_t nstate, angle_t rotangle, boolean spawncenter); void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, statenum_t nstate, angle_t rotangle, boolean spawncenter);

View File

@ -116,7 +116,8 @@ static void P_NetArchivePlayers(void)
WRITEANGLE(save_p, players[i].drawangle); WRITEANGLE(save_p, players[i].drawangle);
WRITEANGLE(save_p, players[i].awayviewaiming); WRITEANGLE(save_p, players[i].awayviewaiming);
WRITEINT32(save_p, players[i].awayviewtics); WRITEINT32(save_p, players[i].awayviewtics);
WRITEINT32(save_p, players[i].rings); WRITEINT16(save_p, players[i].rings);
WRITEINT16(save_p, players[i].spheres);
WRITESINT8(save_p, players[i].pity); WRITESINT8(save_p, players[i].pity);
WRITEINT32(save_p, players[i].currentweapon); WRITEINT32(save_p, players[i].currentweapon);
@ -203,7 +204,7 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, players[i].marebegunat); WRITEUINT32(save_p, players[i].marebegunat);
WRITEUINT32(save_p, players[i].startedtime); WRITEUINT32(save_p, players[i].startedtime);
WRITEUINT32(save_p, players[i].finishedtime); WRITEUINT32(save_p, players[i].finishedtime);
WRITEINT16(save_p, players[i].finishedrings); WRITEINT16(save_p, players[i].finishedspheres);
WRITEUINT32(save_p, players[i].marescore); WRITEUINT32(save_p, players[i].marescore);
WRITEUINT32(save_p, players[i].lastmarescore); WRITEUINT32(save_p, players[i].lastmarescore);
WRITEUINT8(save_p, players[i].lastmare); WRITEUINT8(save_p, players[i].lastmare);
@ -305,7 +306,8 @@ static void P_NetUnArchivePlayers(void)
players[i].drawangle = READANGLE(save_p); players[i].drawangle = READANGLE(save_p);
players[i].awayviewaiming = READANGLE(save_p); players[i].awayviewaiming = READANGLE(save_p);
players[i].awayviewtics = READINT32(save_p); players[i].awayviewtics = READINT32(save_p);
players[i].rings = READINT32(save_p); players[i].rings = READINT16(save_p);
players[i].spheres = READINT16(save_p);
players[i].pity = READSINT8(save_p); players[i].pity = READSINT8(save_p);
players[i].currentweapon = READINT32(save_p); players[i].currentweapon = READINT32(save_p);
@ -392,7 +394,7 @@ static void P_NetUnArchivePlayers(void)
players[i].marebegunat = READUINT32(save_p); players[i].marebegunat = READUINT32(save_p);
players[i].startedtime = READUINT32(save_p); players[i].startedtime = READUINT32(save_p);
players[i].finishedtime = READUINT32(save_p); players[i].finishedtime = READUINT32(save_p);
players[i].finishedrings = READINT16(save_p); players[i].finishedspheres = READINT16(save_p);
players[i].marescore = READUINT32(save_p); players[i].marescore = READUINT32(save_p);
players[i].lastmarescore = READUINT32(save_p); players[i].lastmarescore = READUINT32(save_p);
players[i].lastmare = READUINT8(save_p); players[i].lastmare = READUINT8(save_p);
@ -1990,7 +1992,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case
{ {
P_SpawnHoopsAndRings(&mapthings[spawnpointnum]); P_SpawnHoopsAndRings(&mapthings[spawnpointnum], false);
return; return;
} }
@ -3265,7 +3267,7 @@ static void P_NetArchiveMisc(void)
WRITEUINT32(save_p, tokenlist); WRITEUINT32(save_p, tokenlist);
WRITEUINT32(save_p, leveltime); WRITEUINT32(save_p, leveltime);
WRITEUINT32(save_p, totalrings); WRITEUINT32(save_p, ssspheres);
WRITEINT16(save_p, lastmap); WRITEINT16(save_p, lastmap);
WRITEUINT16(save_p, emeralds); WRITEUINT16(save_p, emeralds);
@ -3342,7 +3344,7 @@ static inline boolean P_NetUnArchiveMisc(void)
// get the time // get the time
leveltime = READUINT32(save_p); leveltime = READUINT32(save_p);
totalrings = READUINT32(save_p); ssspheres = READUINT32(save_p);
lastmap = READINT16(save_p); lastmap = READINT16(save_p);
emeralds = READUINT16(save_p); emeralds = READUINT16(save_p);

View File

@ -808,7 +808,7 @@ void P_ReloadRings(void)
mapthing_t *hoopsToRespawn[4096]; mapthing_t *hoopsToRespawn[4096];
mapthing_t *mt = mapthings; mapthing_t *mt = mapthings;
// scan the thinkers to find rings/wings/hoops to unset // scan the thinkers to find rings/spheres/hoops to unset
for (th = thinkercap.next; th != &thinkercap; th = th->next) for (th = thinkercap.next; th != &thinkercap; th = th->next)
{ {
if (th->function.acp1 != (actionf_p1)P_MobjThinker) if (th->function.acp1 != (actionf_p1)P_MobjThinker)
@ -826,7 +826,9 @@ void P_ReloadRings(void)
} }
continue; continue;
} }
if (!(mo->type == MT_RING || mo->type == MT_NIGHTSWING || mo->type == MT_COIN || mo->type == MT_BLUEBALL)) if (!(mo->type == MT_RING || mo->type == MT_COIN
|| mo->type == MT_BLUESPHERE || mo->type == MT_BOMBSPHERE
|| mo->type == MT_NIGHTSCHIP || mo->type == MT_NIGHTSSTAR))
continue; continue;
// Don't auto-disintegrate things being pulled to us // Don't auto-disintegrate things being pulled to us
@ -840,9 +842,10 @@ void P_ReloadRings(void)
for (i = 0; i < nummapthings; i++, mt++) for (i = 0; i < nummapthings; i++, mt++)
{ {
// Notice an omission? We handle hoops differently. // Notice an omission? We handle hoops differently.
if (mt->type == 300 || mt->type == 308 || mt->type == 309 if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_COIN].doomednum
|| mt->type == 1706 || (mt->type >= 600 && mt->type <= 609) || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum
|| mt->type == 1800) || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum
|| (mt->type >= 600 && mt->type <= 609)) // circles and diagonals
{ {
mt->mobj = NULL; mt->mobj = NULL;
@ -850,12 +853,45 @@ void P_ReloadRings(void)
mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
->sector->floorheight>>FRACBITS); ->sector->floorheight>>FRACBITS);
P_SpawnHoopsAndRings (mt); P_SpawnHoopsAndRings(mt,
#ifdef MANIASPHERES
true);
#else
!G_IsSpecialStage(gamemap)); // prevent flashing spheres in special stages
#endif
} }
} }
for (i = 0; i < numHoops; i++) for (i = 0; i < numHoops; i++)
{ {
P_SpawnHoopsAndRings(hoopsToRespawn[i]); P_SpawnHoopsAndRings(hoopsToRespawn[i], false);
}
}
void P_SwitchSpheresBonusMode(boolean bonustime)
{
mobj_t *mo;
thinker_t *th;
#ifndef MANIASPHERES
if (G_IsSpecialStage(gamemap)) // prevent flashing spheres in special stages
return;
#endif
// scan the thinkers to find spheres to switch
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo = (mobj_t *)th;
if (mo->type != MT_BLUESPHERE && mo->type != MT_NIGHTSCHIP)
continue;
if (!mo->health)
continue;
P_SetMobjState(mo, ((bonustime) ? mo->info->raisestate : mo->info->spawnstate));
} }
} }
@ -1025,20 +1061,22 @@ static void P_LoadThings(void)
} }
//decrement spawn values to the actual number because zero is valid. //decrement spawn values to the actual number because zero is valid.
if (emer1) if (emer1--)
P_SpawnMobj(huntemeralds[emer1 - 1]->x<<FRACBITS, P_SpawnMobj(huntemeralds[emer1]->x<<FRACBITS,
huntemeralds[emer1 - 1]->y<<FRACBITS, huntemeralds[emer1]->y<<FRACBITS,
huntemeralds[emer1 - 1]->z<<FRACBITS, MT_EMERHUNT); huntemeralds[emer1]->z<<FRACBITS, MT_EMERHUNT);
if (emer2) if (emer2--)
P_SpawnMobj(huntemeralds[emer2 - 1]->x<<FRACBITS, P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer2]->x<<FRACBITS,
huntemeralds[emer2 - 1]->y<<FRACBITS, huntemeralds[emer2]->y<<FRACBITS,
huntemeralds[emer2 - 1]->z<<FRACBITS, MT_EMERHUNT); huntemeralds[emer2]->z<<FRACBITS, MT_EMERHUNT),
mobjinfo[MT_EMERHUNT].spawnstate+1);
if (emer3) if (emer3--)
P_SpawnMobj(huntemeralds[emer3 - 1]->x<<FRACBITS, P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer3]->x<<FRACBITS,
huntemeralds[emer3 - 1]->y<<FRACBITS, huntemeralds[emer3]->y<<FRACBITS,
huntemeralds[emer3 - 1]->z<<FRACBITS, MT_EMERHUNT); huntemeralds[emer3]->z<<FRACBITS, MT_EMERHUNT),
mobjinfo[MT_EMERHUNT].spawnstate+2);
} }
if (metalrecording) // Metal Sonic gets no rings to distract him. if (metalrecording) // Metal Sonic gets no rings to distract him.
@ -1048,9 +1086,11 @@ static void P_LoadThings(void)
mt = mapthings; mt = mapthings;
for (i = 0; i < nummapthings; i++, mt++) for (i = 0; i < nummapthings; i++, mt++)
{ {
if (mt->type == 300 || mt->type == 308 || mt->type == 309 if (mt->type == mobjinfo[MT_RING].doomednum || mt->type == mobjinfo[MT_COIN].doomednum
|| mt->type == 1706 || (mt->type >= 600 && mt->type <= 609) || mt->type == mobjinfo[MT_REDTEAMRING].doomednum || mt->type == mobjinfo[MT_BLUETEAMRING].doomednum
|| mt->type == 1705 || mt->type == 1713 || mt->type == 1800) || mt->type == mobjinfo[MT_BLUESPHERE].doomednum || mt->type == mobjinfo[MT_BOMBSPHERE].doomednum
|| (mt->type >= 600 && mt->type <= 609) // circles and diagonals
|| mt->type == 1705 || mt->type == 1713 || mt->type == 1800) // hoops
{ {
mt->mobj = NULL; mt->mobj = NULL;
@ -1058,7 +1098,7 @@ static void P_LoadThings(void)
mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
->sector->floorheight>>FRACBITS); ->sector->floorheight>>FRACBITS);
P_SpawnHoopsAndRings (mt); P_SpawnHoopsAndRings(mt, false);
} }
} }
} }
@ -2298,7 +2338,7 @@ static void P_LevelInitStuff(void)
// circuit, race and competition stuff // circuit, race and competition stuff
circuitmap = false; circuitmap = false;
numstarposts = 0; numstarposts = 0;
totalrings = timeinmap = 0; ssspheres = timeinmap = 0;
// special stage // special stage
stagefailed = false; stagefailed = false;
@ -2320,6 +2360,8 @@ static void P_LevelInitStuff(void)
} }
} }
countdown = countdown2 = 0;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (canresetlives && (netgame || multiplayer) && playeringame[i] && (gametype == GT_COMPETITION || players[i].lives <= 0)) if (canresetlives && (netgame || multiplayer) && playeringame[i] && (gametype == GT_COMPETITION || players[i].lives <= 0))
@ -2328,42 +2370,37 @@ static void P_LevelInitStuff(void)
players[i].lives = cv_startinglives.value; players[i].lives = cv_startinglives.value;
} }
players[i].realtime = countdown = countdown2 = 0; // obliteration station...
players[i].rings = players[i].spheres =\
players[i].xtralife = players[i].deadtimer =\
players[i].numboxes = players[i].totalring =\
players[i].laps = players[i].aiming =\
players[i].losstime = players[i].timeshit =\
players[i].marescore = players[i].lastmarescore =\
players[i].maxlink = players[i].startedtime =\
players[i].finishedtime = players[i].finishedspheres =\
players[i].lastmare = players[i].marebegunat =\
players[i].textvar = players[i].texttimer =\
players[i].linkcount = players[i].linktimer =\
players[i].flyangle = players[i].anotherflyangle =\
players[i].nightstime = players[i].mare =\
players[i].marelap = players[i].marebonuslap =\
players[i].realtime = players[i].exiting = 0;
// i guess this could be part of the above but i feel mildly uncomfortable implicitly casting
players[i].gotcontinue = false; players[i].gotcontinue = false;
players[i].xtralife = players[i].deadtimer = players[i].numboxes = players[i].totalring = players[i].laps = 0; // aha, the first evidence this shouldn't be a memset!
players[i].rings = 0;
players[i].aiming = 0;
players[i].pflags &= ~PF_GAMETYPEOVER;
players[i].losstime = 0;
players[i].timeshit = 0;
players[i].marescore = players[i].lastmarescore = players[i].maxlink = 0;
players[i].startedtime = players[i].finishedtime = players[i].finishedrings = 0;
players[i].lastmare = players[i].marebegunat = 0;
// Don't show anything
players[i].textvar = players[i].texttimer = 0;
players[i].linkcount = players[i].linktimer = 0;
players[i].flyangle = players[i].anotherflyangle = 0;
players[i].nightstime = players[i].mare = 0;
players[i].marelap = 0; players[i].marebonuslap = 0;
P_SetTarget(&players[i].capsule, NULL);
players[i].drillmeter = 40*20; players[i].drillmeter = 40*20;
players[i].exiting = 0;
P_ResetPlayer(&players[i]); P_ResetPlayer(&players[i]);
// hit these too
players[i].pflags &= ~(PF_GAMETYPEOVER|PF_TRANSFERTOCLOSEST);
players[i].mo = NULL; // unset ALL the pointers. P_SetTarget isn't needed here because if this
// function is being called we're just going to clobber the data anyways
// we must unset axis details too players[i].mo = players[i].followmobj = players[i].awayviewmobj =\
players[i].axis1 = players[i].axis2 = NULL; players[i].capsule = players[i].axis1 = players[i].axis2 = NULL;
// and this stupid flag as a result
players[i].pflags &= ~PF_TRANSFERTOCLOSEST;
} }
} }
@ -2403,7 +2440,17 @@ void P_LoadThingsOnly(void)
P_LevelInitStuff(); P_LevelInitStuff();
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can use the things lump
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
fileinfo += ML_THINGS; // we only need the THINGS lump
P_PrepareRawThings(wadData + fileinfo->filepos, fileinfo->size);
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
P_LoadThings(); P_LoadThings();
@ -2676,11 +2723,6 @@ boolean P_SetupLevel(boolean skipprecip)
// Reset the palette // Reset the palette
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_SetPaletteColor(0);
else
#endif
if (rendermode != render_none) if (rendermode != render_none)
V_SetPaletteLump("PLAYPAL"); V_SetPaletteLump("PLAYPAL");
@ -2738,6 +2780,7 @@ boolean P_SetupLevel(boolean skipprecip)
{ {
tic_t starttime = I_GetTime(); tic_t starttime = I_GetTime();
tic_t endtime = starttime + (3*TICRATE)/2; tic_t endtime = starttime + (3*TICRATE)/2;
tic_t nowtime;
S_StartSound(NULL, sfx_s3kaf); S_StartSound(NULL, sfx_s3kaf);
@ -2747,9 +2790,17 @@ boolean P_SetupLevel(boolean skipprecip)
F_WipeEndScreen(); F_WipeEndScreen();
F_RunWipe(wipedefs[wipe_speclevel_towhite], false); F_RunWipe(wipedefs[wipe_speclevel_towhite], false);
nowtime = lastwipetic;
// Hold on white for extra effect. // Hold on white for extra effect.
while (I_GetTime() < endtime) while (nowtime < endtime)
I_Sleep(); {
// wait loop
while (!((nowtime = I_GetTime()) - lastwipetic))
I_Sleep();
lastwipetic = nowtime;
if (moviemode) // make sure we save frames for the white hold too
M_SaveFrame();
}
ranspecialwipe = 1; ranspecialwipe = 1;
} }
@ -3337,7 +3388,7 @@ boolean P_AddWadFile(const char *wadfilename)
if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX) if ((numlumps = W_InitFile(wadfilename)) == INT16_MAX)
{ {
refreshdirmenu |= REFRESHDIR_NOTLOADED; refreshdirmenu |= REFRESHDIR_NOTLOADED;
CONS_Printf(M_GetText("Errors occured while loading %s; not added.\n"), wadfilename); CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename);
return false; return false;
} }
else else
@ -3351,7 +3402,7 @@ boolean P_AddWadFile(const char *wadfilename)
for (i = 0; i < numlumps; i++, lumpinfo++) for (i = 0; i < numlumps; i++, lumpinfo++)
{ {
// lumpinfo = FindFolder("Lua/", &luaPos, &luaNum, lumpinfo, &numlumps, &i); // lumpinfo = FindFolder("Lua/", &luaPos, &luaNum, lumpinfo, &numlumps, &i);
// lumpinfo = FindFolder("SOCs/", &socPos, &socNum, lumpinfo, &numlumps, &i); // lumpinfo = FindFolder("SOC/", &socPos, &socNum, lumpinfo, &numlumps, &i);
lumpinfo = FindFolder("Sounds/", &sfxPos, &sfxNum, lumpinfo, &numlumps, &i); lumpinfo = FindFolder("Sounds/", &sfxPos, &sfxNum, lumpinfo, &numlumps, &i);
lumpinfo = FindFolder("Music/", &musPos, &musNum, lumpinfo, &numlumps, &i); lumpinfo = FindFolder("Music/", &musPos, &musNum, lumpinfo, &numlumps, &i);
// lumpinfo = FindFolder("Sprites/", &sprPos, &sprNum, lumpinfo, &numlumps, &i); // lumpinfo = FindFolder("Sprites/", &sprPos, &sprNum, lumpinfo, &numlumps, &i);

View File

@ -72,6 +72,7 @@ void P_DeleteFlickies(INT16 i);
// Needed for NiGHTS // Needed for NiGHTS
void P_ReloadRings(void); void P_ReloadRings(void);
void P_SwitchSpheresBonusMode(boolean bonustime);
void P_DeleteGrades(INT16 i); void P_DeleteGrades(INT16 i);
void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext); void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext);
UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare); UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare);

View File

@ -3076,7 +3076,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// Unlocked something? // Unlocked something?
if (M_UpdateUnlockablesAndExtraEmblems()) if (M_UpdateUnlockablesAndExtraEmblems())
{ {
S_StartSound(NULL, sfx_ncitem); S_StartSound(NULL, sfx_s3k68);
G_SaveGameData(); // only save if unlocked something G_SaveGameData(); // only save if unlocked something
} }
} }
@ -3735,7 +3735,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
if (player->exiting || player->bot) // Don't do anything for bots or players who have just finished if (player->exiting || player->bot) // Don't do anything for bots or players who have just finished
break; break;
if (!(player->powers[pw_shield] || player->rings > 0)) // Don't do anything if no shield or rings anyway if (!(player->powers[pw_shield] || player->spheres > 0)) // Don't do anything if no shield or spheres anyway
break; break;
P_SpecialStageDamage(player, NULL, NULL); P_SpecialStageDamage(player, NULL, NULL);
@ -3983,8 +3983,8 @@ DoneSection2:
case 2: // Special stage GOAL sector / Exit Sector / CTF Flag Return case 2: // Special stage GOAL sector / Exit Sector / CTF Flag Return
if (player->bot) if (player->bot)
break; break;
if (!useNightsSS && G_IsSpecialStage(gamemap) && sstimer > 6) if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6)
sstimer = 6; // Just let P_Ticker take care of the rest. player->nightstime = 6; // Just let P_Ticker take care of the rest.
// Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c) // Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c)
{ {
@ -4851,7 +4851,7 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector)
switch(GETSECSPECIAL(sector->special, 4)) switch(GETSECSPECIAL(sector->special, 4))
{ {
case 2: // Level Exit / GOAL Sector / Flag Return case 2: // Level Exit / GOAL Sector / Flag Return
if (!useNightsSS && G_IsSpecialStage(gamemap)) if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))
{ {
// Special stage GOAL sector // Special stage GOAL sector
// requires touching floor. // requires touching floor.
@ -5710,7 +5710,7 @@ void P_InitSpecials(void)
// Defaults in case levels don't have them set. // Defaults in case levels don't have them set.
sstimer = 90*TICRATE + 6; sstimer = 90*TICRATE + 6;
totalrings = 1; ssspheres = 1;
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
@ -5735,6 +5735,30 @@ void P_InitSpecials(void)
P_InitTagLists(); // Create xref tables for tags P_InitTagLists(); // Create xref tables for tags
} }
static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs)
{
if (!(master->flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set
{
sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle;
sector->floor_xoffs += xoffs;
sector->floor_yoffs += yoffs;
// saved for netgames
sector->spawn_flr_xoffs = sector->floor_xoffs;
sector->spawn_flr_yoffs = sector->floor_yoffs;
}
if (!(master->flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set
{
sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle;
sector->ceiling_xoffs += xoffs;
sector->ceiling_yoffs += yoffs;
// saved for netgames
sector->spawn_ceil_xoffs = sector->ceiling_xoffs;
sector->spawn_ceil_yoffs = sector->ceiling_yoffs;
}
}
/** After the map has loaded, scans for specials that spawn 3Dfloors and /** After the map has loaded, scans for specials that spawn 3Dfloors and
* thinkers. * thinkers.
* *
@ -5780,7 +5804,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
{ {
case 10: // Time for special stage case 10: // Time for special stage
sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish
totalrings = sector->ceilingheight>>FRACBITS; // Ring count for special stage ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage
break; break;
case 11: // Custom global gravity! case 11: // Custom global gravity!
@ -5938,27 +5962,13 @@ void P_SpawnSpecials(INT32 fromnetsave)
yoffs = lines[i].v1->y; yoffs = lines[i].v1->y;
} }
for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) //If no tag is given, apply to front sector
if (lines[i].tag == 0)
P_ApplyFlatAlignment(lines + i, lines[i].frontsector, flatangle, xoffs, yoffs);
else
{ {
if (!(lines[i].flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0;)
{ P_ApplyFlatAlignment(lines + i, sectors + s, flatangle, xoffs, yoffs);
sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = flatangle;
sectors[s].floor_xoffs += xoffs;
sectors[s].floor_yoffs += yoffs;
// saved for netgames
sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs;
sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs;
}
if (!(lines[i].flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set
{
sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = flatangle;
sectors[s].ceiling_xoffs += xoffs;
sectors[s].ceiling_yoffs += yoffs;
// saved for netgames
sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs;
sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs;
}
} }
} }
else // Otherwise, print a helpful warning. Can I do no less? else // Otherwise, print a helpful warning. Can I do no less?
@ -6908,6 +6918,7 @@ void T_Scroll(scroll_t *s)
line_t *line; line_t *line;
size_t i; size_t i;
INT32 sect; INT32 sect;
ffloor_t *rover;
case sc_side: // scroll wall texture case sc_side: // scroll wall texture
side = sides + s->affectee; side = sides + s->affectee;
@ -6949,6 +6960,19 @@ void T_Scroll(scroll_t *s)
sector_t *psec; sector_t *psec;
psec = sectors + sect; psec = sectors + sect;
// Find the FOF corresponding to the control linedef
for (rover = psec->ffloors; rover; rover = rover->next)
{
if (rover->master == sec->lines[i])
break;
}
if (!rover) // This should be impossible, but don't complain if it is the case somehow
continue;
if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there
continue;
for (node = psec->touching_thinglist; node; node = node->m_thinglist_next) for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
{ {
thing = node->m_thing; thing = node->m_thing;
@ -7012,6 +7036,19 @@ void T_Scroll(scroll_t *s)
sector_t *psec; sector_t *psec;
psec = sectors + sect; psec = sectors + sect;
// Find the FOF corresponding to the control linedef
for (rover = psec->ffloors; rover; rover = rover->next)
{
if (rover->master == sec->lines[i])
break;
}
if (!rover) // This should be impossible, but don't complain if it is the case somehow
continue;
if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there
continue;
for (node = psec->touching_thinglist; node; node = node->m_thinglist_next) for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
{ {
thing = node->m_thing; thing = node->m_thing;
@ -7865,7 +7902,6 @@ void T_Pusher(pusher_t *p)
thing->player->pflags |= jumped; thing->player->pflags |= jumped;
thing->player->pflags |= PF_SLIDING; thing->player->pflags |= PF_SLIDING;
P_SetPlayerMobjState (thing, thing->info->painstate); // Whee!
thing->angle = R_PointToAngle2 (0, 0, xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR)); thing->angle = R_PointToAngle2 (0, 0, xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR));
if (!demoplayback || P_AnalogMove(thing->player)) if (!demoplayback || P_AnalogMove(thing->player))

View File

@ -424,7 +424,7 @@ void P_DoTeamscrambling(void)
static inline void P_DoSpecialStageStuff(void) static inline void P_DoSpecialStageStuff(void)
{ {
boolean inwater = false; boolean stillalive = false;
INT32 i; INT32 i;
// Can't drown in a special stage // Can't drown in a special stage
@ -436,68 +436,60 @@ static inline void P_DoSpecialStageStuff(void)
players[i].powers[pw_underwater] = players[i].powers[pw_spacetime] = 0; players[i].powers[pw_underwater] = players[i].powers[pw_spacetime] = 0;
} }
if (sstimer < 15*TICRATE+6 && sstimer > 7 && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)) //if (sstimer < 15*TICRATE+6 && sstimer > 7 && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
S_SpeedMusic(1.4f); //S_SpeedMusic(1.4f);
if (sstimer < 7 && sstimer > 0) // The special stage time is up! if (sstimer && !objectplacing)
{ {
sstimer = 0; UINT16 countspheres = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
players[i].exiting = (14*TICRATE)/5 + 1;
players[i].pflags &= ~PF_GLIDING;
}
if (i == consoleplayer)
S_StartSound(NULL, sfx_lose);
}
if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
S_SpeedMusic(1.0f);
stagefailed = true;
}
if (sstimer > 1) // As long as time isn't up...
{
UINT32 ssrings = 0;
// Count up the rings of all the players and see if // Count up the rings of all the players and see if
// they've collected the required amount. // they've collected the required amount.
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]) if (playeringame[i])
{ {
ssrings += players[i].rings; tic_t oldnightstime = players[i].nightstime;
countspheres += players[i].spheres;
// If in water, deplete timer 6x as fast. // If in water, deplete timer 6x as fast.
if ((players[i].mo->eflags & MFE_TOUCHWATER) if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))
|| (players[i].mo->eflags & MFE_UNDERWATER)) players[i].nightstime -= 5;
inwater = true; if (--players[i].nightstime > 6)
{
if (P_IsLocalPlayer(&players[i]) && oldnightstime > 10*TICRATE && players[i].nightstime <= 10*TICRATE)
S_ChangeMusicInternal("_drown", false);
stillalive = true;
}
else if (!players[i].exiting)
{
players[i].exiting = (14*TICRATE)/5 + 1;
players[i].pflags &= ~(PF_GLIDING|PF_BOUNCING);
players[i].nightstime = 0;
if (P_IsLocalPlayer(&players[i]))
S_StartSound(NULL, sfx_s3k66);
}
} }
if (ssrings >= totalrings && totalrings > 0) if (stillalive)
{ {
// Halt all the players if (countspheres >= ssspheres)
for (i = 0; i < MAXPLAYERS; i++) {
if (playeringame[i]) // Halt all the players
{ for (i = 0; i < MAXPLAYERS; i++)
players[i].mo->momx = players[i].mo->momy = 0; if (playeringame[i])
players[i].exiting = (14*TICRATE)/5 + 1; {
} players[i].mo->momx = players[i].mo->momy = 0;
players[i].exiting = (14*TICRATE)/5 + 1;
}
sstimer = 0; sstimer = 0;
P_GiveEmerald(true);
P_GiveEmerald(true); P_RestoreMusic(&players[consoleplayer]);
}
} }
else
// Decrement the timer
if (!objectplacing)
{ {
if (inwater) sstimer = 0;
sstimer -= 6; stagefailed = true;
else
sstimer--;
} }
} }
} }
@ -606,9 +598,10 @@ void P_Ticker(boolean run)
} }
// Keep track of how long they've been playing! // Keep track of how long they've been playing!
totalplaytime++; if (!demoplayback) // Don't increment if a demo is playing.
totalplaytime++;
if (!useNightsSS && G_IsSpecialStage(gamemap)) if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))
P_DoSpecialStageStuff(); P_DoSpecialStageStuff();
if (runemeraldmanager) if (runemeraldmanager)

View File

@ -283,22 +283,11 @@ boolean P_PlayerMoving(INT32 pnum)
// //
UINT8 P_GetNextEmerald(void) UINT8 P_GetNextEmerald(void)
{ {
if (!useNightsSS) // In order if (gamemap >= sstage_start && gamemap <= sstage_end)
{
if (!(emeralds & EMERALD1)) return 0;
if (!(emeralds & EMERALD2)) return 1;
if (!(emeralds & EMERALD3)) return 2;
if (!(emeralds & EMERALD4)) return 3;
if (!(emeralds & EMERALD5)) return 4;
if (!(emeralds & EMERALD6)) return 5;
return 6;
}
else // Depends on stage
{
if (gamemap < sstage_start || gamemap > sstage_end)
return 0;
return (UINT8)(gamemap - sstage_start); return (UINT8)(gamemap - sstage_start);
} if (gamemap >= smpstage_start || gamemap <= smpstage_end)
return (UINT8)(gamemap - smpstage_start);
return 0;
} }
// //
@ -309,20 +298,19 @@ UINT8 P_GetNextEmerald(void)
// //
void P_GiveEmerald(boolean spawnObj) void P_GiveEmerald(boolean spawnObj)
{ {
INT32 i; UINT8 em = P_GetNextEmerald();
UINT8 em;
S_StartSound(NULL, sfx_cgot); // Got the emerald! S_StartSound(NULL, sfx_cgot); // Got the emerald!
em = P_GetNextEmerald();
emeralds |= (1 << em); emeralds |= (1 << em);
if (spawnObj) if (spawnObj && playeringame[consoleplayer])
{ {
for (i = 0; i < MAXPLAYERS; i++) // The Chaos Emerald begins to orbit us!
if (playeringame[i]) // Only give it to ONE person!
P_SetMobjState(P_SpawnMobj(players[i].mo->x, players[i].mo->y, players[i].mo->z + players[i].mo->info->height, MT_GOTEMERALD), mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD);
mobjinfo[MT_GOTEMERALD].spawnstate + em); P_SetTarget(&emmo->target, players[consoleplayer].mo);
P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
P_SetTarget(&players[consoleplayer].mo->tracer, emmo);
} }
} }
@ -698,10 +686,10 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
oldmare = player->mare; oldmare = player->mare;
if (P_TransferToNextMare(player) == false) if (!P_TransferToNextMare(player))
{ {
INT32 i; INT32 i;
INT32 total_rings = 0; INT32 total_spheres = 0;
P_SetTarget(&player->mo->target, NULL); P_SetTarget(&player->mo->target, NULL);
@ -709,7 +697,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
{ {
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i]/* && players[i].powers[pw_carry] == CR_NIGHTSMODE*/) if (playeringame[i]/* && players[i].powers[pw_carry] == CR_NIGHTSMODE*/)
total_rings += players[i].rings; total_spheres += players[i].spheres;
} }
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
@ -722,13 +710,13 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
players[i].lastmare = players[i].mare; players[i].lastmare = players[i].mare;
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ {
players[i].finishedrings = (INT16)total_rings; players[i].finishedspheres = (INT16)total_spheres;
P_AddPlayerScore(player, total_rings * 50); P_AddPlayerScore(player, total_spheres * 50);
} }
else else
{ {
players[i].finishedrings = (INT16)(players[i].rings); players[i].finishedspheres = (INT16)(players[i].spheres);
P_AddPlayerScore(&players[i], (players[i].rings) * 50); P_AddPlayerScore(&players[i], (players[i].spheres) * 50);
} }
// Add score to leaderboards now // Add score to leaderboards now
@ -739,20 +727,20 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
players[i].lastmarescore = players[i].marescore; players[i].lastmarescore = players[i].marescore;
players[i].marescore = 0; players[i].marescore = 0;
players[i].rings = 0; players[i].spheres = 0;
P_DoPlayerExit(&players[i]); P_DoPlayerExit(&players[i]);
} }
} }
else if (oldmare != player->mare) else if (oldmare != player->mare)
{ {
/// \todo Handle multi-mare special stages. /// \todo Handle multi-mare special stages.
// Ring bonus // Spheres bonus
P_AddPlayerScore(player, (player->rings) * 50); P_AddPlayerScore(player, (player->spheres) * 50);
player->lastmare = (UINT8)oldmare; player->lastmare = (UINT8)oldmare;
player->texttimer = 4*TICRATE; player->texttimer = 4*TICRATE;
player->textvar = 4; // Score and grades player->textvar = 4; // Score and grades
player->finishedrings = (INT16)(player->rings); player->finishedspheres = (INT16)(player->spheres);
// Add score to temp leaderboards // Add score to temp leaderboards
if (!(netgame||multiplayer) && P_IsLocalPlayer(player)) if (!(netgame||multiplayer) && P_IsLocalPlayer(player))
@ -763,7 +751,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->marescore = 0; player->marescore = 0;
player->marebegunat = leveltime; player->marebegunat = leveltime;
player->rings = 0; player->spheres = 0;
} }
else else
{ {
@ -866,7 +854,7 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor)
} }
else else
{ {
ang = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0); ang = ((player->mo->momx || player->mo->momy) ? R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0) : player->drawangle);
fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale); fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale);
} }
@ -932,8 +920,7 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings)
player->rings += num_rings; player->rings += num_rings;
if (!G_IsSpecialStage(gamemap) || !useNightsSS) player->totalring += num_rings;
player->totalring += num_rings;
// Can only get up to 9999 rings, sorry! // Can only get up to 9999 rings, sorry!
if (player->rings > 9999) if (player->rings > 9999)
@ -965,6 +952,26 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings)
} }
} }
void P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
{
if (!player)
return;
if (player->bot)
player = &players[consoleplayer];
if (!player->mo)
return;
player->spheres += num_spheres;
// Can only get up to 9999 spheres, sorry!
if (player->spheres > 9999)
player->spheres = 9999;
else if (player->spheres < 0)
player->spheres = 0;
}
// //
// P_GivePlayerLives // P_GivePlayerLives
// //
@ -1044,12 +1051,11 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
player->mo->momx = player->mo->momy = player->mo->momz = player->cmomx = player->cmomy = player->rmomx = player->rmomy = 0;
// Transformation animation // Transformation animation
P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_TRANS1); P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_TRANS1);
player->mo->momx = player->mo->momy = player->mo->momz = 0;
player->pflags |= PF_NOJUMPDAMAGE; // just to avoid recurling but still allow thok
if (giverings) if (giverings)
player->rings = 50; player->rings = 50;
@ -1805,6 +1811,9 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
for (rover = sector->ffloors; rover; rover = rover->next) for (rover = sector->ffloors; rover; rover = rover->next)
{ {
if (!(rover->flags & FF_EXISTS))
continue;
if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL) if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL)
continue; continue;
#ifdef ESLOPE #ifdef ESLOPE
@ -2165,6 +2174,12 @@ static void P_CheckBouncySectors(player_t *player)
for (rover = node->m_sector->ffloors; rover; rover = rover->next) for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{ {
if (!(rover->flags & FF_EXISTS))
continue; // FOFs should not be bouncy if they don't even "exist"
if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 15)
continue; // this sector type is required for FOFs to be bouncy
topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
@ -2178,7 +2193,6 @@ static void P_CheckBouncySectors(player_t *player)
&& oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)) && oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL))
top = false; top = false;
if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 15)
{ {
fixed_t linedist; fixed_t linedist;
@ -3493,194 +3507,198 @@ static void P_SetWeaponDelay(player_t *player, INT32 delay)
static void P_DoFiring(player_t *player, ticcmd_t *cmd) static void P_DoFiring(player_t *player, ticcmd_t *cmd)
{ {
INT32 i; INT32 i;
mobj_t *mo = NULL;
I_Assert(player != NULL); I_Assert(player != NULL);
I_Assert(!P_MobjWasRemoved(player->mo)); I_Assert(!P_MobjWasRemoved(player->mo));
if (cmd->buttons & BT_ATTACK || cmd->buttons & BT_FIRENORMAL) if (!(cmd->buttons & (BT_ATTACK|BT_FIRENORMAL)))
{ {
if (!(player->pflags & PF_ATTACKDOWN) && (player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER && !player->climbing) // Not holding any firing buttons anymore.
{ // Release the grenade / whatever.
player->pflags |= PF_ATTACKDOWN; player->pflags &= ~PF_ATTACKDOWN;
P_SpawnPlayerMissile(player->mo, MT_FIREBALL, 0);
S_StartSound(player->mo, sfx_mario7);
}
else if (G_RingSlingerGametype() && (!G_TagGametype() || player->pflags & PF_TAGIT)
&& !player->weapondelay && !player->climbing
&& !(player->pflags & PF_ATTACKDOWN))
{
mobj_t *mo = NULL;
player->pflags |= PF_ATTACKDOWN;
#define TAKE_AMMO(player, power) \
player->powers[power]--; \
if (player->rings < 1) \
{ \
if (player->powers[power] > 0) \
player->powers[power]--; \
} \
else \
player->rings--;
if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring.
goto firenormal; //code repetition sucks.
// Bounce ring
else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering])
{
TAKE_AMMO(player, pw_bouncering);
P_SetWeaponDelay(player, TICRATE/4);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING);
if (mo)
mo->fuse = 3*TICRATE; // Bounce Ring time
}
// Rail ring
else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring])
{
TAKE_AMMO(player, pw_railring);
P_SetWeaponDelay(player, (3*TICRATE)/2);
mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW);
// Rail has no unique thrown object, therefore its sound plays here.
S_StartSound(player->mo, sfx_rail1);
}
// Automatic
else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring])
{
TAKE_AMMO(player, pw_automaticring);
player->pflags &= ~PF_ATTACKDOWN;
P_SetWeaponDelay(player, 2);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNAUTOMATIC, MF2_AUTOMATIC);
}
// Explosion
else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring])
{
TAKE_AMMO(player, pw_explosionring);
P_SetWeaponDelay(player, (3*TICRATE)/2);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION);
}
// Grenade
else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering])
{
TAKE_AMMO(player, pw_grenadering);
P_SetWeaponDelay(player, TICRATE/3);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION);
if (mo)
{
//P_InstaThrust(mo, player->mo->angle, FixedMul(mo->info->speed, player->mo->scale));
mo->fuse = mo->info->mass;
}
}
// Scatter
// Note: Ignores MF2_RAILRING
else if (player->currentweapon == WEP_SCATTER && player->powers[pw_scatterring])
{
fixed_t oldz = player->mo->z;
angle_t shotangle = player->mo->angle;
angle_t oldaiming = player->aiming;
TAKE_AMMO(player, pw_scatterring);
P_SetWeaponDelay(player, (2*TICRATE)/3);
// Center
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNSCATTER, MF2_SCATTER);
if (mo)
shotangle = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y);
// Left
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle-ANG2, true, MF2_SCATTER);
// Right
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle+ANG2, true, MF2_SCATTER);
// Down
player->mo->z += FixedMul(12*FRACUNIT, player->mo->scale);
player->aiming += ANG1;
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER);
// Up
player->mo->z -= FixedMul(24*FRACUNIT, player->mo->scale);
player->aiming -= ANG2;
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER);
player->mo->z = oldz;
player->aiming = oldaiming;
return;
}
// No powers, just a regular ring.
else
{
firenormal:
// Infinity ring was selected.
// Mystic wants this ONLY to happen specifically if it's selected,
// and to not be able to get around it EITHER WAY with firenormal.
// Infinity Ring
if (player->currentweapon == 0
&& player->powers[pw_infinityring])
{
P_SetWeaponDelay(player, TICRATE/4);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNINFINITY, 0);
player->powers[pw_infinityring]--;
}
// Red Ring
else
{
if (player->rings <= 0)
return;
P_SetWeaponDelay(player, TICRATE/4);
mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, 0);
if (mo)
P_ColorTeamMissile(mo, player);
player->rings--;
}
}
#undef TAKE_AMMO
if (mo)
{
if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING)
{
const boolean nblockmap = !(mo->flags & MF_NOBLOCKMAP);
for (i = 0; i < 256; i++)
{
if (nblockmap)
{
P_UnsetThingPosition(mo);
mo->flags |= MF_NOBLOCKMAP;
P_SetThingPosition(mo);
}
if (i&1)
P_SpawnMobj(mo->x, mo->y, mo->z, MT_SPARK);
if (P_RailThinker(mo))
break; // mobj was removed (missile hit a wall) or couldn't move
}
// Other rail sound plays at contact point.
S_StartSound(mo, sfx_rail2);
}
}
}
return; return;
} }
// Not holding any firing buttons anymore. if (player->pflags & PF_ATTACKDOWN || player->climbing || (G_TagGametype() && !(player->pflags & PF_TAGIT)))
// Release the grenade / whatever. return;
player->pflags &= ~PF_ATTACKDOWN;
if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER)
{
player->pflags |= PF_ATTACKDOWN;
mo = P_SpawnPlayerMissile(player->mo, MT_FIREBALL, 0);
P_InstaThrust(mo, player->mo->angle, ((mo->info->speed>>FRACBITS)*player->mo->scale) + player->speed);
S_StartSound(player->mo, sfx_mario7);
return;
}
if (!G_RingSlingerGametype() || player->weapondelay)
return;
player->pflags |= PF_ATTACKDOWN;
#define TAKE_AMMO(player, power) \
player->powers[power]--; \
if (player->rings < 1) \
{ \
if (player->powers[power] > 0) \
player->powers[power]--; \
} \
else \
player->rings--;
if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring.
goto firenormal; //code repetition sucks.
// Bounce ring
else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering])
{
TAKE_AMMO(player, pw_bouncering);
P_SetWeaponDelay(player, TICRATE/4);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING);
if (mo)
mo->fuse = 3*TICRATE; // Bounce Ring time
}
// Rail ring
else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring])
{
TAKE_AMMO(player, pw_railring);
P_SetWeaponDelay(player, (3*TICRATE)/2);
mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW);
// Rail has no unique thrown object, therefore its sound plays here.
S_StartSound(player->mo, sfx_rail1);
}
// Automatic
else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring])
{
TAKE_AMMO(player, pw_automaticring);
player->pflags &= ~PF_ATTACKDOWN;
P_SetWeaponDelay(player, 2);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNAUTOMATIC, MF2_AUTOMATIC);
}
// Explosion
else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring])
{
TAKE_AMMO(player, pw_explosionring);
P_SetWeaponDelay(player, (3*TICRATE)/2);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION);
}
// Grenade
else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering])
{
TAKE_AMMO(player, pw_grenadering);
P_SetWeaponDelay(player, TICRATE/3);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION);
if (mo)
{
//P_InstaThrust(mo, player->mo->angle, FixedMul(mo->info->speed, player->mo->scale));
mo->fuse = mo->info->reactiontime;
}
}
// Scatter
// Note: Ignores MF2_RAILRING
else if (player->currentweapon == WEP_SCATTER && player->powers[pw_scatterring])
{
fixed_t oldz = player->mo->z;
angle_t shotangle = player->mo->angle;
angle_t oldaiming = player->aiming;
TAKE_AMMO(player, pw_scatterring);
P_SetWeaponDelay(player, (2*TICRATE)/3);
// Center
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNSCATTER, MF2_SCATTER);
if (mo)
shotangle = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y);
// Left
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle-ANG2, true, MF2_SCATTER);
// Right
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle+ANG2, true, MF2_SCATTER);
// Down
player->mo->z += FixedMul(12*FRACUNIT, player->mo->scale);
player->aiming += ANG1;
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER);
// Up
player->mo->z -= FixedMul(24*FRACUNIT, player->mo->scale);
player->aiming -= ANG2;
mo = P_SPMAngle(player->mo, MT_THROWNSCATTER, shotangle, true, MF2_SCATTER);
player->mo->z = oldz;
player->aiming = oldaiming;
return;
}
// No powers, just a regular ring.
else
{
firenormal:
// Infinity ring was selected.
// Mystic wants this ONLY to happen specifically if it's selected,
// and to not be able to get around it EITHER WAY with firenormal.
// Infinity Ring
if (player->currentweapon == 0
&& player->powers[pw_infinityring])
{
P_SetWeaponDelay(player, TICRATE/4);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNINFINITY, 0);
player->powers[pw_infinityring]--;
}
// Red Ring
else
{
if (player->rings <= 0)
return;
P_SetWeaponDelay(player, TICRATE/4);
mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, 0);
if (mo)
P_ColorTeamMissile(mo, player);
player->rings--;
}
}
#undef TAKE_AMMO
if (mo)
{
if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING)
{
const boolean nblockmap = !(mo->flags & MF_NOBLOCKMAP);
for (i = 0; i < 256; i++)
{
if (nblockmap)
{
P_UnsetThingPosition(mo);
mo->flags |= MF_NOBLOCKMAP;
P_SetThingPosition(mo);
}
if (i&1)
P_SpawnMobj(mo->x, mo->y, mo->z, MT_SPARK);
if (P_RailThinker(mo))
break; // mobj was removed (missile hit a wall) or couldn't move
}
// Other rail sound plays at contact point.
S_StartSound(mo, sfx_rail2);
}
}
} }
// //
@ -3802,12 +3820,15 @@ static void P_DoSuperStuff(player_t *player)
// //
boolean P_SuperReady(player_t *player) boolean P_SuperReady(player_t *player)
{ {
if ((ALL7EMERALDS(emeralds) && player->rings >= 50) && !player->powers[pw_super] && !player->powers[pw_tailsfly] if (!player->powers[pw_super]
&& !(player->powers[pw_shield] & SH_NOSTACK)
&& !player->powers[pw_invulnerability] && !player->powers[pw_invulnerability]
&& !(maptol & TOL_NIGHTS || (player->powers[pw_carry] == CR_NIGHTSMODE)) // don't turn 'regular super' in nights levels && !player->powers[pw_tailsfly]
&& player->pflags & PF_JUMPED && (player->charflags & SF_SUPER)
&& player->charflags & SF_SUPER) && (player->pflags & PF_JUMPED)
&& !(player->powers[pw_shield] & SH_NOSTACK)
&& !(maptol & TOL_NIGHTS)
&& ALL7EMERALDS(emeralds)
&& (player->rings >= 50))
return true; return true;
return false; return false;
@ -4493,12 +4514,12 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
} }
else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag)) else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag))
; ;
else if (P_SuperReady(player)) /*else if (P_SuperReady(player))
{ {
// If you can turn super and aren't already, // If you can turn super and aren't already,
// and you don't have a shield, do it! // and you don't have a shield, do it!
P_DoSuperTransformation(player, false); P_DoSuperTransformation(player, false);
} }*/
else if (player->pflags & PF_JUMPED) else if (player->pflags & PF_JUMPED)
{ {
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
@ -5962,10 +5983,10 @@ static void P_DoNiGHTSCapsule(player_t *player)
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here! { // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here!
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && (&players[i] != player) && players[i].rings > 0) if (playeringame[i] && (&players[i] != player) && players[i].spheres > 0)
{ {
player->rings += players[i].rings; player->spheres += players[i].spheres;
players[i].rings = 0; players[i].spheres = 0;
} }
} }
@ -5974,9 +5995,9 @@ static void P_DoNiGHTSCapsule(player_t *player)
&& player->mo->y == player->capsule->y && player->mo->y == player->capsule->y
&& player->mo->z == player->capsule->z+(player->capsule->height/3)) && player->mo->z == player->capsule->z+(player->capsule->height/3))
{ {
if (player->rings > 0) if (player->spheres > 0)
{ {
player->rings--; player->spheres--;
player->capsule->health--; player->capsule->health--;
player->capsule->extravalue1++; player->capsule->extravalue1++;
@ -6008,9 +6029,6 @@ static void P_DoNiGHTSCapsule(player_t *player)
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ {
// The Chaos Emerald begins to orbit us!
mobj_t *emmo;
UINT8 em = P_GetNextEmerald();
tic_t lowest_time; tic_t lowest_time;
/*for (i = 0; i < MAXPLAYERS; i++) /*for (i = 0; i < MAXPLAYERS; i++)
@ -6025,8 +6043,10 @@ static void P_DoNiGHTSCapsule(player_t *player)
if (player->powers[pw_carry] == CR_NIGHTSMODE) if (player->powers[pw_carry] == CR_NIGHTSMODE)
{ {
// The Chaos Emerald begins to orbit us!
UINT8 em = P_GetNextEmerald();
// Only give it to ONE person, and THAT player has to get to the goal! // Only give it to ONE person, and THAT player has to get to the goal!
emmo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->info->height, MT_GOTEMERALD); mobj_t *emmo = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height, MT_GOTEMERALD);
P_SetTarget(&emmo->target, player->mo); P_SetTarget(&emmo->target, player->mo);
P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
P_SetTarget(&player->mo->tracer, emmo); P_SetTarget(&player->mo->tracer, emmo);
@ -6044,18 +6064,24 @@ static void P_DoNiGHTSCapsule(player_t *player)
} }
else else
{ {
for (i = 0; i < 16; i++) /*for (i = 0; i < 16; i++)
{ {
mobj_t *flicky = P_InternalFlickySpawn(player->capsule, 0, ((i%4) + 1)*2*FRACUNIT, true); mobj_t *flicky = P_InternalFlickySpawn(player->capsule, 0, ((i%4) + 1)*2*FRACUNIT, true);
flicky->z += player->capsule->height/2; flicky->z += player->capsule->height/2;
flicky->angle = (i*(ANGLE_MAX/16)); flicky->angle = (i*(ANGLE_MAX/16));
P_InstaThrust(flicky, flicky->angle, 8*FRACUNIT); P_InstaThrust(flicky, flicky->angle, 8*FRACUNIT);
} }*/
mobj_t *idya = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height, MT_GOTEMERALD);
idya->extravalue2 = player->mare/5;
P_SetTarget(&idya->target, player->mo);
P_SetMobjState(idya, mobjinfo[MT_GOTEMERALD].missilestate + ((player->mare + 1) % 5));
P_SetTarget(&player->mo->tracer, idya);
} }
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mare == player->mare) if (playeringame[i] && players[i].mare == player->mare)
P_SetTarget(&players[i].capsule, NULL); // Remove capsule from everyone now that it is dead! P_SetTarget(&players[i].capsule, NULL); // Remove capsule from everyone now that it is dead!
S_StartScreamSound(player->mo, sfx_ngdone); S_StartScreamSound(player->mo, sfx_ngdone);
P_SwitchSpheresBonusMode(true);
P_RunNightsBonusTimeExecutors(player->mo); P_RunNightsBonusTimeExecutors(player->mo);
} }
} }
@ -6149,7 +6175,7 @@ static void P_NiGHTSMovement(player_t *player)
} }
else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE) else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE)
// S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH // S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
S_ChangeMusicInternal("_drown",false); S_ChangeMusicInternal((((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)) ? "_ntime" : "_drown"), false);
if (player->mo->z < player->mo->floorz) if (player->mo->z < player->mo->floorz)
@ -6948,12 +6974,17 @@ static void P_MovePlayer(player_t *player)
if ((player->powers[pw_carry] == CR_NIGHTSMODE) if ((player->powers[pw_carry] == CR_NIGHTSMODE)
&& (player->exiting && (player->exiting
|| !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1] || !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state < &states[S_PLAY_NIGHTS_TRANS6]))) && player->mo->state < &states[S_PLAY_NIGHTS_TRANS6]))) // Note the < instead of <=
{ {
skin_t *skin = ((skin_t *)(player->mo->skin)); skin_t *skin = ((skin_t *)(player->mo->skin));
if (skin->flags & SF_SUPER && player->mo->color < MAXSKINCOLORS) if (skin->flags & SF_SUPER)
{
player->mo->color = skin->supercolor
+ ((player->nightstime == player->startedtime)
? 4
: abs((((signed)leveltime >> 1) % 9) - 4)); // This is where super flashing is handled.
G_GhostAddColor(GHC_SUPER); G_GhostAddColor(GHC_SUPER);
player->mo->color = (skin->flags & SF_SUPER) ? skin->supercolor + abs((((signed)(player->startedtime - player->nightstime) >> 1) % 9) - 4) : player->mo->color; // This is where super flashing is handled. }
} }
if (!player->capsule && !player->bonustime) if (!player->capsule && !player->bonustime)
@ -7487,7 +7518,7 @@ static void P_MovePlayer(player_t *player)
#endif #endif
{ {
if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously
&& (!(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped && (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super
{ {
// Force shield activation // Force shield activation
if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
@ -7500,6 +7531,11 @@ static void P_MovePlayer(player_t *player)
{ {
switch (player->powers[pw_shield] & SH_NOSTACK) switch (player->powers[pw_shield] & SH_NOSTACK)
{ {
// Super!
case SH_NONE:
if (P_SuperReady(player))
P_DoSuperTransformation(player, false);
break;
// Whirlwind/Thundercoin shield activation // Whirlwind/Thundercoin shield activation
case SH_WHIRLWIND: case SH_WHIRLWIND:
case SH_THUNDERCOIN: case SH_THUNDERCOIN:
@ -7951,17 +7987,18 @@ static void P_DoRopeHang(player_t *player)
if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
{ {
P_SetTarget(&player->mo->tracer, NULL);
player->pflags |= P_GetJumpFlags(player); player->pflags |= P_GetJumpFlags(player);
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
P_SetTarget(&player->mo->tracer, NULL);
player->powers[pw_carry] = CR_NONE; player->powers[pw_carry] = CR_NONE;
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_JUMP))
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
return; return;
} }
if (player->mo->state-states != S_PLAY_RIDE)
P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
// If not allowed to move, we're done here. // If not allowed to move, we're done here.
if (!speed) if (!speed)
return; return;
@ -8052,10 +8089,7 @@ static void P_DoRopeHang(player_t *player)
if (player->mo->tracer->flags & MF_SLIDEME) if (player->mo->tracer->flags & MF_SLIDEME)
{ {
player->pflags |= P_GetJumpFlags(player); player->pflags |= P_GetJumpFlags(player);
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
&& !(player->panim == PA_JUMP))
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);
} }
P_SetTarget(&player->mo->tracer, NULL); P_SetTarget(&player->mo->tracer, NULL);
@ -8173,7 +8207,6 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
mobj_t *mo; mobj_t *mo;
thinker_t *think; thinker_t *think;
mobj_t *closestmo = NULL; mobj_t *closestmo = NULL;
const UINT32 targetmask = (MF_ENEMY|MF_BOSS|(nonenemies ? (MF_MONITOR|MF_SPRING) : 0));
const fixed_t maxdist = FixedMul((bullet ? RING_DIST*2 : RING_DIST), player->mo->scale); const fixed_t maxdist = FixedMul((bullet ? RING_DIST*2 : RING_DIST), player->mo->scale);
const angle_t span = (bullet ? ANG30 : ANGLE_90); const angle_t span = (bullet ? ANG30 : ANGLE_90);
fixed_t dist, closestdist = 0; fixed_t dist, closestdist = 0;
@ -8184,9 +8217,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
continue; // not a mobj thinker continue; // not a mobj thinker
mo = (mobj_t *)think; mo = (mobj_t *)think;
if (!(mo->flags & targetmask if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
|| mo->type == MT_FAKEMOBILE // hehehehe
|| mo->type == MT_EGGSHIELD))
continue; // not a valid target continue; // not a valid target
if (mo->health <= 0) // dead if (mo->health <= 0) // dead
@ -8201,6 +8232,9 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus) if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus)
continue; continue;
if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING))
continue;
if (!bullet && mo->type == MT_DETON) // Don't be STUPID, Sonic! if (!bullet && mo->type == MT_DETON) // Don't be STUPID, Sonic!
continue; continue;
@ -8238,7 +8272,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
if (closestmo && dist > closestdist) if (closestmo && dist > closestdist)
continue; continue;
if ((R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y) - player->mo->angle + span) > span*2) if ((R_PointToAngle2(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius), mo->x, mo->y) - player->mo->angle + span) > span*2)
continue; // behind back continue; // behind back
if (!P_CheckSight(player->mo, mo)) if (!P_CheckSight(player->mo, mo))
@ -9573,11 +9607,8 @@ void P_PlayerThink(player_t *player)
// If 11 seconds are left on the timer, // If 11 seconds are left on the timer,
// begin the drown music for countdown! // begin the drown music for countdown!
if (countdown == 11*TICRATE - 1) if (countdown == 11*TICRATE - 1 && P_IsLocalPlayer(player))
{ S_ChangeMusicInternal("_drown", false);
if (P_IsLocalPlayer(player))
S_ChangeMusicInternal("_drown", false);
}
// If you've hit the countdown and you haven't made // If you've hit the countdown and you haven't made
// it to the exit, you're a goner! // it to the exit, you're a goner!
@ -9677,7 +9708,7 @@ void P_PlayerThink(player_t *player)
if (gametype != GT_COOP) if (gametype != GT_COOP)
player->score = 0; player->score = 0;
player->mo->health = 1; player->mo->health = 1;
player->rings = 0; player->rings = player->spheres = 0;
} }
else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP) else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP)
{ {
@ -9730,8 +9761,9 @@ void P_PlayerThink(player_t *player)
mo2 = (mobj_t *)th; mo2 = (mobj_t *)th;
if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN if (!(mo2->type == MT_RING || mo2->type == MT_COIN
|| mo2->type == MT_BLUEBALL)) || mo2->type == MT_BLUESPHERE || mo2->type == MT_BOMBSPHERE
|| mo2->type == MT_NIGHTSCHIP || mo2->type == MT_NIGHTSSTAR))
continue; continue;
if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > FixedMul(128*FRACUNIT, player->mo->scale)) if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > FixedMul(128*FRACUNIT, player->mo->scale))
@ -9767,8 +9799,6 @@ void P_PlayerThink(player_t *player)
ticmiss++; ticmiss++;
P_DoRopeHang(player); P_DoRopeHang(player);
if (player->mo->state-states != S_PLAY_RIDE)
P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
P_DoJumpStuff(player, &player->cmd); P_DoJumpStuff(player, &player->cmd);
} }
else //if (player->powers[pw_carry] == CR_ZOOMTUBE) else //if (player->powers[pw_carry] == CR_ZOOMTUBE)
@ -9884,7 +9914,8 @@ void P_PlayerThink(player_t *player)
if (!player->powers[pw_carry] if (!player->powers[pw_carry]
&& ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) && ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE))
&& !(cmd->forwardmove || cmd->sidemove) && !(cmd->forwardmove || cmd->sidemove)
&& (player->rmomx || player->rmomy)) && (player->rmomx || player->rmomy)
&& (!player->capsule || (player->capsule->reactiontime != (player-players)+1)))
{ {
fixed_t acceleration = (player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration) * player->thrustfactor * 20; fixed_t acceleration = (player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration) * player->thrustfactor * 20;
angle_t moveAngle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); angle_t moveAngle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);
@ -9906,7 +9937,7 @@ void P_PlayerThink(player_t *player)
|| player->climbing || player->climbing
|| player->pflags & (PF_SPINNING|PF_SLIDING)) || player->pflags & (PF_SPINNING|PF_SLIDING))
player->pflags &= ~PF_APPLYAUTOBRAKE; player->pflags &= ~PF_APPLYAUTOBRAKE;
else if (currentlyonground) else if (currentlyonground || player->powers[pw_tailsfly])
player->pflags |= PF_APPLYAUTOBRAKE; player->pflags |= PF_APPLYAUTOBRAKE;
} }
} }
@ -10220,7 +10251,7 @@ void P_PlayerAfterThink(player_t *player)
if (player->followmobj) if (player->followmobj)
{ {
P_RemoveMobj(player->followmobj); P_RemoveMobj(player->followmobj);
player->followmobj = NULL; P_SetTarget(&player->followmobj, NULL);
} }
return; return;
} }
@ -10338,7 +10369,7 @@ void P_PlayerAfterThink(player_t *player)
if (P_IsLocalPlayer(player) && (player->pflags & PF_WPNDOWN) && player->currentweapon != oldweapon) if (P_IsLocalPlayer(player) && (player->pflags & PF_WPNDOWN) && player->currentweapon != oldweapon)
S_StartSound(NULL, sfx_wepchg); S_StartSound(NULL, sfx_wepchg);
if (player->pflags & PF_SLIDING) if ((player->pflags & PF_SLIDING) && ((player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE)) != PF_JUMPED))
P_SetPlayerMobjState(player->mo, player->mo->info->painstate); P_SetPlayerMobjState(player->mo, player->mo->info->painstate);
/* if (player->powers[pw_carry] == CR_NONE && player->mo->tracer && !player->homing) /* if (player->powers[pw_carry] == CR_NONE && player->mo->tracer && !player->homing)
@ -10454,21 +10485,10 @@ void P_PlayerAfterThink(player_t *player)
player->secondjump = 0; player->secondjump = 0;
player->pflags &= ~PF_THOKKED; player->pflags &= ~PF_THOKKED;
if (cmd->forwardmove > 0)
{
if ((player->mo->tracer->tracer->lastlook += 2) > player->mo->tracer->tracer->friction)
player->mo->tracer->tracer->lastlook = player->mo->tracer->tracer->friction;
}
else if (cmd->forwardmove < 0)
{
if ((player->mo->tracer->tracer->lastlook -= 2) < player->mo->tracer->tracer->movecount)
player->mo->tracer->tracer->lastlook = player->mo->tracer->tracer->movecount;
}
if ((player->mo->tracer->tracer->flags & MF_SLIDEME) // Noclimb on chain parameters gives this if ((player->mo->tracer->tracer->flags & MF_SLIDEME) // Noclimb on chain parameters gives this
&& !(twodlevel || player->mo->flags2 & MF2_TWOD)) // why on earth would you want to turn them in 2D mode? && !(twodlevel || player->mo->flags2 & MF2_TWOD)) // why on earth would you want to turn them in 2D mode?
{ {
player->mo->tracer->tracer->health += cmd->sidemove; player->mo->tracer->tracer->angle += cmd->sidemove<<ANGLETOFINESHIFT;
player->mo->angle += cmd->sidemove<<ANGLETOFINESHIFT; // 2048 --> ANGLE_MAX player->mo->angle += cmd->sidemove<<ANGLETOFINESHIFT; // 2048 --> ANGLE_MAX
if (!demoplayback || P_AnalogMove(player)) if (!demoplayback || P_AnalogMove(player))
@ -10516,14 +10536,14 @@ void P_PlayerAfterThink(player_t *player)
if (player->followmobj && (player->spectator || player->mo->health <= 0 || player->followmobj->type != player->followitem)) if (player->followmobj && (player->spectator || player->mo->health <= 0 || player->followmobj->type != player->followitem))
{ {
P_RemoveMobj(player->followmobj); P_RemoveMobj(player->followmobj);
player->followmobj = NULL; P_SetTarget(&player->followmobj, NULL);
} }
if (!player->spectator && player->mo->health && player->followitem) if (!player->spectator && player->mo->health && player->followitem)
{ {
if (!player->followmobj || P_MobjWasRemoved(player->followmobj)) if (!player->followmobj || P_MobjWasRemoved(player->followmobj))
{ {
player->followmobj = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem); P_SetTarget(&player->followmobj, P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem));
P_SetTarget(&player->followmobj->tracer, player->mo); P_SetTarget(&player->followmobj->tracer, player->mo);
player->followmobj->flags2 |= MF2_LINKDRAW; player->followmobj->flags2 |= MF2_LINKDRAW;
} }

View File

@ -257,7 +257,7 @@ const UINT8 Color_Index[MAXTRANSLATIONS-1][16] = {
{0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, // SKINCOLOR_SUPERTAN2 {0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, // SKINCOLOR_SUPERTAN2
{0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, // SKINCOLOR_SUPERTAN3 {0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, // SKINCOLOR_SUPERTAN3
{0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, // SKINCOLOR_SUPERTAN4 {0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, // SKINCOLOR_SUPERTAN4
{0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef} // SKINCOLOR_SUPERTAN5 {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef} // SKINCOLOR_SUPERTAN5
}; };
// See also the enum skincolors_t // See also the enum skincolors_t

View File

@ -717,7 +717,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
colfunc = basecolfunc; // hack: this isn't resetting properly somewhere. colfunc = basecolfunc; // hack: this isn't resetting properly somewhere.
dc_colormap = vis->colormap; dc_colormap = vis->colormap;
if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash" if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
{ {
// translate certain pixels to white // translate certain pixels to white
colfunc = transcolfunc; colfunc = transcolfunc;
@ -2673,7 +2673,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
if (player->followmobj) if (player->followmobj)
{ {
P_RemoveMobj(player->followmobj); P_RemoveMobj(player->followmobj);
player->followmobj = NULL; P_SetTarget(&player->followmobj, NULL);
} }
if (player->mo) if (player->mo)

View File

@ -446,10 +446,11 @@ void SCR_ClosedCaptions(void)
{ {
if (splitscreen) if (splitscreen)
basey -= 8; basey -= 8;
else if (((maptol & TOL_NIGHTS) && (modeattacking == ATTACKING_NIGHTS)) else if ((modeattacking == ATTACKING_NIGHTS)
|| (cv_powerupdisplay.value == 2) || (!(maptol & TOL_NIGHTS)
&& ((cv_powerupdisplay.value == 2)
|| (cv_powerupdisplay.value == 1 && ((stplyr == &players[displayplayer] && !camera.chase) || (cv_powerupdisplay.value == 1 && ((stplyr == &players[displayplayer] && !camera.chase)
|| ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)))) || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase))))))
basey -= 16; basey -= 16;
} }

View File

@ -658,6 +658,14 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type)
SDL_memset(&event, 0, sizeof(event_t)); SDL_memset(&event, 0, sizeof(event_t));
// Ignore the event if the mouse is not actually focused on the window.
// This can happen if you used the mouse to restore keyboard focus;
// this apparently makes a mouse button down event but not a mouse button up event,
// resulting in whatever key was pressed down getting "stuck" if we don't ignore it.
// -- Monster Iestyn (28/05/18)
if (SDL_GetMouseFocus() != window)
return;
/// \todo inputEvent.button.which /// \todo inputEvent.button.which
if (USE_MOUSEINPUT) if (USE_MOUSEINPUT)
{ {

View File

@ -66,6 +66,7 @@ static boolean midimode;
static Mix_Music *music; static Mix_Music *music;
static UINT8 music_volume, midi_volume, sfx_volume; static UINT8 music_volume, midi_volume, sfx_volume;
static float loop_point; static float loop_point;
static boolean songpaused;
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
static Music_Emu *gme; static Music_Emu *gme;
@ -102,6 +103,7 @@ void I_StartupSound(void)
} }
sound_started = true; sound_started = true;
songpaused = false;
Mix_AllocateChannels(256); Mix_AllocateChannels(256);
} }
@ -450,7 +452,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
(void)udata; (void)udata;
// no gme? no music. // no gme? no music.
if (!gme || gme_track_ended(gme)) if (!gme || gme_track_ended(gme) || songpaused)
return; return;
// play gme into stream // play gme into stream
@ -458,7 +460,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
// apply volume to stream // apply volume to stream
for (i = 0, p = (short *)stream; i < len/2; i++, p++) for (i = 0, p = (short *)stream; i < len/2; i++, p++)
*p = ((INT32)*p) * music_volume / 31; *p = ((INT32)*p) * music_volume*2 / 42;
} }
#endif #endif
@ -476,12 +478,14 @@ void I_PauseSong(INT32 handle)
{ {
(void)handle; (void)handle;
Mix_PauseMusic(); Mix_PauseMusic();
songpaused = true;
} }
void I_ResumeSong(INT32 handle) void I_ResumeSong(INT32 handle)
{ {
(void)handle; (void)handle;
Mix_ResumeMusic(); Mix_ResumeMusic();
songpaused = false;
} }
// //

View File

@ -1180,12 +1180,6 @@ void I_StartupSound(void)
audio.callback = I_UpdateStream; audio.callback = I_UpdateStream;
audio.userdata = &localdata; audio.userdata = &localdata;
if (dedicated)
{
nosound = nomidimusic = nodigimusic = true;
return;
}
// Configure sound device // Configure sound device
CONS_Printf("I_StartupSound:\n"); CONS_Printf("I_StartupSound:\n");
@ -1481,9 +1475,6 @@ void I_InitMusic(void)
I_AddExitFunc(I_ShutdownGMEMusic); I_AddExitFunc(I_ShutdownGMEMusic);
#endif #endif
if ((nomidimusic && nodigimusic) || dedicated)
return;
#ifdef HAVE_MIXER #ifdef HAVE_MIXER
MIX_VERSION(&MIXcompiled) MIX_VERSION(&MIXcompiled)
MIXlinked = Mix_Linked_Version(); MIXlinked = Mix_Linked_Version();

View File

@ -65,7 +65,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"buzz1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric zap"}, {"buzz1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric zap"},
{"buzz2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric zap"}, {"buzz2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric zap"},
{"buzz3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wacky worksurface"}, {"buzz3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wacky worksurface"},
{"buzz4", false, 8, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Buzz"}, {"buzz4", true, 8, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Buzz"},
{"crumbl", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"}, // Platform Crumble Tails 03-16-2001 {"crumbl", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"}, // Platform Crumble Tails 03-16-2001
{"fire", false, 8, 32, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"}, {"fire", false, 8, 32, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"},
{"grind", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic grinding"}, {"grind", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic grinding"},
@ -76,6 +76,8 @@ sfxinfo_t S_sfx[NUMSFX] =
{"steam1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001 {"steam1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001
{"steam2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001 {"steam2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Steam jet"}, // Tails 06-19-2001
{"wbreak", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wood breaking"}, {"wbreak", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wood breaking"},
{"ambmac", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machinery"},
{"spsmsh", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy impact"},
{"rainin", true, 24, 4, -1, NULL, 0, -1, -1, LUMPERROR, "Rain"}, {"rainin", true, 24, 4, -1, NULL, 0, -1, -1, LUMPERROR, "Rain"},
{"litng1", false, 16, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning"}, {"litng1", false, 16, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning"},
@ -139,14 +141,14 @@ sfxinfo_t S_sfx[NUMSFX] =
{"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing! {"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing!
{"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing! {"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing!
{"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"}, {"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"},
{"cgot" , true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Chaos Emerald"}, // Got Emerald! Tails 09-02-2001 {"cgot" , true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Emerald"}, // Got Emerald! Tails 09-02-2001
{"cybdth", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Explosion"}, {"cybdth", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Explosion"},
{"deton", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous beeping"}, {"deton", true, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Threatening beeping"},
{"ding", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Ding"}, {"ding", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Ding"},
{"dmpain", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machine damage"}, {"dmpain", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Machine damage"},
{"drown", false, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drowning"}, {"drown", false, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drowning"},
{"fizzle", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Electric fizzle"}, {"fizzle", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Electric fizzle"},
{"gbeep", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous beeping"}, // Grenade beep {"gbeep", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Threatening beeping"}, // Grenade beep
{"wepfir", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing weapon"}, // defaults to thok {"wepfir", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing weapon"}, // defaults to thok
{"ghit" , false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Goop splash"}, {"ghit" , false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Goop splash"},
{"gloop", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Splash"}, {"gloop", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Splash"},
@ -177,15 +179,17 @@ sfxinfo_t S_sfx[NUMSFX] =
{"spring", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spring"}, {"spring", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spring"},
{"statu1", true, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Pushing a statue"}, {"statu1", true, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Pushing a statue"},
{"statu2", true, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Pushing a statue"}, {"statu2", true, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Pushing a statue"},
{"strpst", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, // Starpost Sound Tails 07-04-2002 {"strpst", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"},
{"supert", true, 127, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"}, {"supert", true, 127, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"},
{"telept", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dash"}, {"telept", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dash"},
{"tink" , false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Tink"}, {"tink" , false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Tink"},
{"token" , true, 224, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Token"}, // SS token {"token" , true, 224, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got Token"},
{"trfire", true, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Laser fired"}, {"trfire", true, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Laser fired"},
{"trpowr", true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, {"trpowr", true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"},
{"turhit", false, 40, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Laser hit"}, {"turhit", false, 40, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Laser hit"},
{"wdjump", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Whirlwind jump"}, {"wdjump", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Whirlwind jump"},
{"shrpsp", true, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spincushion"},
{"shrpgo", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Launch"},
{"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Spinning out"}, {"mswarp", false, 60, 16, -1, NULL, 0, -1, -1, LUMPERROR, "Spinning out"},
{"mspogo", false, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Breaking through"}, {"mspogo", false, 60, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Breaking through"},
{"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"}, {"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"},
@ -210,11 +214,12 @@ sfxinfo_t S_sfx[NUMSFX] =
{"xideya", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Success"}, // Xmas {"xideya", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Success"}, // Xmas
{"nbmper", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, {"nbmper", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"},
{"nxbump", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, // Xmas {"nxbump", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, // Xmas
{"ncchip", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got chip"},
{"ncitem", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got special"}, {"ncitem", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got special"},
{"nxitem", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got special"}, // Xmas {"nxitem", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got special"}, // Xmas
{"ngdone", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonus time start"}, {"ngdone", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonus time start"},
{"nxdone", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonus time start"}, // Xmas {"nxdone", true, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonus time start"}, // Xmas
{"drill1", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drill start"}, {"drill1", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drill"},
{"drill2", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drill"}, {"drill2", false, 48, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drill"},
{"ncspec", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power-up"}, // Tails 12-15-2003 {"ncspec", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power-up"}, // Tails 12-15-2003
{"nghurt", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"}, {"nghurt", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"},
@ -224,19 +229,26 @@ sfxinfo_t S_sfx[NUMSFX] =
{"hoop3", false, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hoop++"}, {"hoop3", false, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hoop++"},
{"hidden", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"}, {"hidden", false, 204, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"},
{"prloop", false, 104, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gust of wind"}, {"prloop", false, 104, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Gust of wind"},
{"timeup", true, 256, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous Countdown"}, {"ngjump", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"},
{"peww", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pew"},
// Halloween
{"lntsit", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cacolantern awake"},
{"lntdie", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cacolantern death"},
{"pumpkn", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pumpkin smash"}, // idspispopd
{"ghosty", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Laughter"},
// Mario // Mario
{"koopfr" , true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"}, {"koopfr" , true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"},
{"mario1", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hitting a ceiling"}, {"mario1", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Hit"},
{"mario2", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Koopa shell"}, {"mario2", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bonk"},
{"mario3", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power-up"}, {"mario3", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power-up"},
{"mario4", true, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got coin"}, {"mario4", true, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got coin"},
{"mario5", false, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boot"}, {"mario5", false, 78, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boot-stomp"},
{"mario6", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"}, {"mario6", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"},
{"mario7", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"}, {"mario7", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Fire"},
{"mario8", false, 48, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"}, {"mario8", false, 48, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Hurt"},
{"mario9", true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Emerging"}, {"mario9", true, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Emerging power-up"},
{"marioa", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "One-up"}, {"marioa", true, 192, 0, -1, NULL, 0, -1, -1, LUMPERROR, "One-up"},
{"thwomp", true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Thwomp"}, {"thwomp", true, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Thwomp"},
@ -287,7 +299,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k3d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pop"}, {"s3k3d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pop"},
{"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"}, {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"},
{"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"}, {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"},
{"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction shot"}, {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction blast"},
{"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"}, {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"},
{"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"}, {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"},
{"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"}, {"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"},
@ -295,22 +307,22 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning zap"}, {"s3k45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning zap"},
{"s3k46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"}, {"s3k46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Transformation"},
{"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising dust"}, {"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising dust"},
{"s3k48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Metallic clink"}, {"s3k48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pulse"},
{"s3k49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling rock"}, {"s3k49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"},
{"s3k4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Grab"}, {"s3k4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Grab"},
{"s3k4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Water splash"}, {"s3k4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Water splash"},
{"s3k4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"}, {"s3k4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"},
{"s3k4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing bullet"}, {"s3k4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing bullet"},
{"s3k4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bomb explosion"}, {"s3k4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Big explosion"},
{"s3k4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"}, {"s3k4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flamethrower"},
{"s3k50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Siren"}, {"s3k50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Siren"},
{"s3k51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling bomb"}, {"s3k51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling hazard"},
{"s3k52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, {"s3k52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"},
{"s3k53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"}, {"s3k53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powering up"},
{"s3k54", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Firing"}, // MetalSonic shot fire {"s3k54", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Firing"}, // MetalSonic shot fire
{"s3k55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"}, {"s3k55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"},
{"s3k56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy landing"}, {"s3k56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy landing"},
{"s3k57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Splash"}, {"s3k57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"},
{"s3k58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"}, {"s3k58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"},
{"s3k59", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"}, {"s3k59", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"},
{"s3k5a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, {"s3k5a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"},
@ -324,13 +336,13 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"}, {"s3k62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"},
{"s3k63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, {"s3k63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"},
{"s3k64", false, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Clatter"}, {"s3k64", false, 64, 2, -1, NULL, 0, -1, -1, LUMPERROR, "Clatter"},
{"s3k65", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got blue sphere"}, // Blue Spheres {"s3k65", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Got sphere"}, // Blue Spheres
{"s3k66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage clear"}, {"s3k66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage end"},
{"s3k67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing missile"}, {"s3k67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing missile"},
{"s3k68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Unknown possibilities"}, {"s3k68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Discovery"},
{"s3k69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Switch click"}, {"s3k69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Switch click"},
{"s3k6a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage clear"}, {"s3k6a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Special stage clear"},
{"s3k6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3k6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Punch"},
{"s3k6c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, {"s3k6c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"},
{"s3k6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3k6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s3k6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical damage"}, {"s3k6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical damage"},
@ -363,16 +375,16 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k89", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Advanced technology"}, {"s3k89", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Advanced technology"},
{"s3k8a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boing"}, {"s3k8a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Boing"},
{"s3k8b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful hit"}, {"s3k8b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful hit"},
{"s3k8c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3k8c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Humming power"},
{"s3k8d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3k8d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s3k8e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3k8e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accelerating"},
{"s3k8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Opening"}, {"s3k8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Opening"},
{"s3k90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"}, {"s3k90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Impact"},
{"s3k91", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Closed"}, {"s3k91", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Closed"},
{"s3k92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ghost"}, {"s3k92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ghost"},
{"s3k93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rebuilding"}, {"s3k93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rebuilding"},
{"s3k94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"}, {"s3k94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spike"},
{"s3k95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Rising from lava"}, {"s3k95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lava burst"},
{"s3k96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling object"}, {"s3k96", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling object"},
{"s3k97", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind"}, {"s3k97", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind"},
{"s3k98", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling spike"}, {"s3k98", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling spike"},
@ -429,8 +441,8 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3kc3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Levitation"}, // ditto {"s3kc3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Levitation"}, // ditto
{"s3kc4s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"}, {"s3kc4s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"},
{"s3kc4l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"}, // ditto {"s3kc4l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"}, // ditto
{"s3kc5s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3kc5s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Revving up"},
{"s3kc5l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto {"s3kc5l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Revving up"}, // ditto
{"s3kc6s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, {"s3kc6s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"},
{"s3kc6l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, // ditto {"s3kc6l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Orbiting"}, // ditto
{"s3kc7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"}, {"s3kc7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"},
@ -455,7 +467,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3kd1s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3kd1s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s3kd1l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto {"s3kd1l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto
{"s3kd2s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turning"}, {"s3kd2s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turning"},
{"s3kd2l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turning"}, // ditto {"s3kd2l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Moving chain"}, // ditto
{"s3kd3s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"s3kd3s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"s3kd3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto {"s3kd3l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // ditto
{"s3kd4s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Engine"}, {"s3kd4s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Engine"},

View File

@ -142,6 +142,8 @@ typedef enum
sfx_steam1, sfx_steam1,
sfx_steam2, sfx_steam2,
sfx_wbreak, sfx_wbreak,
sfx_ambmac,
sfx_spsmsh,
sfx_rainin, sfx_rainin,
sfx_litng1, sfx_litng1,
@ -252,6 +254,8 @@ typedef enum
sfx_trpowr, sfx_trpowr,
sfx_turhit, sfx_turhit,
sfx_wdjump, sfx_wdjump,
sfx_shrpsp,
sfx_shrpgo,
sfx_mswarp, sfx_mswarp,
sfx_mspogo, sfx_mspogo,
sfx_boingf, sfx_boingf,
@ -276,6 +280,7 @@ typedef enum
sfx_xideya, // Xmas sfx_xideya, // Xmas
sfx_nbmper, sfx_nbmper,
sfx_nxbump, // Xmas sfx_nxbump, // Xmas
sfx_ncchip,
sfx_ncitem, sfx_ncitem,
sfx_nxitem, // Xmas sfx_nxitem, // Xmas
sfx_ngdone, sfx_ngdone,
@ -290,7 +295,14 @@ typedef enum
sfx_hoop3, sfx_hoop3,
sfx_hidden, sfx_hidden,
sfx_prloop, sfx_prloop,
sfx_timeup, // Was gonna be played when less than ten seconds are on the clock; uncomment uses of this to see it in-context sfx_ngjump,
sfx_peww,
// Halloween
sfx_lntsit,
sfx_lntdie,
sfx_pumpkn,
sfx_ghosty,
// Mario // Mario
sfx_koopfr, sfx_koopfr,

View File

@ -27,6 +27,8 @@
#include "i_system.h" #include "i_system.h"
#include "m_menu.h" #include "m_menu.h"
#include "m_cheat.h" #include "m_cheat.h"
#include "m_misc.h" // moviemode
#include "m_anigif.h" // cv_gif_downscale
#include "p_setup.h" // NiGHTS grading #include "p_setup.h" // NiGHTS grading
//random index //random index
@ -110,6 +112,8 @@ static patch_t *yelstat;
static patch_t *nbracket; static patch_t *nbracket;
static patch_t *nhud[12]; static patch_t *nhud[12];
static patch_t *nsshud; static patch_t *nsshud;
static patch_t *nbon[12];
static patch_t *nssbon;
static patch_t *narrow[9]; static patch_t *narrow[9];
static patch_t *nredar[8]; // Red arrow static patch_t *nredar[8]; // Red arrow
static patch_t *drillbar; static patch_t *drillbar;
@ -200,17 +204,17 @@ void ST_doPaletteStuff(void)
else else
palette = 0; palette = 0;
#ifdef HWRENDER
if (rendermode == render_opengl)
palette = 0; // No flashpals here in OpenGL
#endif
palette = min(max(palette, 0), 13); palette = min(max(palette, 0), 13);
if (palette != st_palette) if (palette != st_palette)
{ {
st_palette = palette; st_palette = palette;
#ifdef HWRENDER
if (rendermode == render_opengl)
HWR_SetPaletteColor(0);
else
#endif
if (rendermode != render_none) if (rendermode != render_none)
{ {
V_SetPaletteLump(GetPalette()); // Reset the palette V_SetPaletteLump(GetPalette()); // Reset the palette
@ -307,8 +311,12 @@ void ST_LoadGraphics(void)
yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX); yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX);
nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX); nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX);
for (i = 0; i < 12; ++i) for (i = 0; i < 12; ++i)
{
nhud[i] = W_CachePatchName(va("NHUD%d", i+1), PU_HUDGFX); nhud[i] = W_CachePatchName(va("NHUD%d", i+1), PU_HUDGFX);
nbon[i] = W_CachePatchName(va("NBON%d", i+1), PU_HUDGFX);
}
nsshud = W_CachePatchName("NSSHUD", PU_HUDGFX); nsshud = W_CachePatchName("NSSHUD", PU_HUDGFX);
nssbon = W_CachePatchName("NSSBON", PU_HUDGFX);
minicaps = W_CachePatchName("MINICAPS", PU_HUDGFX); minicaps = W_CachePatchName("MINICAPS", PU_HUDGFX);
for (i = 0; i < 8; ++i) for (i = 0; i < 8; ++i)
@ -460,7 +468,7 @@ static void ST_drawDebugInfo(void)
#define VFLAGS V_MONOSPACE|V_SNAPTOTOP|V_SNAPTORIGHT #define VFLAGS V_MONOSPACE|V_SNAPTOTOP|V_SNAPTORIGHT
if (vid.dupx == 1) if ((moviemode == MM_GIF && cv_gif_downscale.value) || vid.dupx == 1)
{ {
if (cv_debug & DBG_BASIC) if (cv_debug & DBG_BASIC)
{ {
@ -657,9 +665,9 @@ static void ST_drawTime(void)
else else
{ {
// Counting down the hidetime? // Counting down the hidetime?
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (leveltime <= (hidetime*TICRATE))) if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime <= (hidetime*TICRATE)))
{ {
tics = (hidetime*TICRATE - leveltime); tics = (hidetime*TICRATE - stplyr->realtime);
if (tics < 3*TICRATE) if (tics < 3*TICRATE)
ST_drawRaceNum(tics); ST_drawRaceNum(tics);
downwards = true; downwards = true;
@ -667,15 +675,15 @@ static void ST_drawTime(void)
else else
{ {
// Hidetime finish! // Hidetime finish!
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (leveltime < ((hidetime+1)*TICRATE))) if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (stplyr->realtime < ((hidetime+1)*TICRATE)))
ST_drawRaceNum(hidetime*TICRATE - leveltime); ST_drawRaceNum(hidetime*TICRATE - stplyr->realtime);
// Time limit? // Time limit?
if (gametype != GT_RACE && gametype != GT_COMPETITION && gametype != GT_COOP && cv_timelimit.value && timelimitintics > 0) if (gametype != GT_COOP && gametype != GT_RACE && gametype != GT_COMPETITION && cv_timelimit.value && timelimitintics > 0)
{ {
if (timelimitintics >= leveltime) if (timelimitintics >= stplyr->realtime)
{ {
tics = (timelimitintics - leveltime); tics = (timelimitintics - stplyr->realtime);
if (tics < 3*TICRATE) if (tics < 3*TICRATE)
ST_drawRaceNum(tics); ST_drawRaceNum(tics);
} }
@ -733,18 +741,7 @@ static inline void ST_drawRings(void)
ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS));
if (objectplacing) ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0));
ringnum = op_currentdoomednum;
else if (!useNightsSS && G_IsSpecialStage(gamemap))
{
INT32 i;
ringnum = 0;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && players[i].rings > 0)
ringnum += players[i].rings;
}
else
ringnum = max(stplyr->rings, 0);
if (cv_timetic.value == 2) // Yes, even in modeattacking if (cv_timetic.value == 2) // Yes, even in modeattacking
ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS));
@ -1096,7 +1093,8 @@ static void ST_drawInput(void)
((!stplyr->powers[pw_carry] ((!stplyr->powers[pw_carry]
&& (stplyr->pflags & PF_APPLYAUTOBRAKE) && (stplyr->pflags & PF_APPLYAUTOBRAKE)
&& !(stplyr->cmd.sidemove || stplyr->cmd.forwardmove) && !(stplyr->cmd.sidemove || stplyr->cmd.forwardmove)
&& (stplyr->rmomx || stplyr->rmomy)) && (stplyr->rmomx || stplyr->rmomy)
&& (!stplyr->capsule || (stplyr->capsule->reactiontime != (stplyr-players)+1)))
? 0 : V_GRAYMAP), ? 0 : V_GRAYMAP),
"AUTOBRAKE"); "AUTOBRAKE");
y -= 8; y -= 8;
@ -1392,17 +1390,17 @@ static void ST_drawNightsRecords(void)
V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag, V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag,
va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health, va(M_GetText("\x80GET\x82 %d\x80 %s%s%s!"), stplyr->capsule->health,
(stplyr->textvar == 3) ? M_GetText("MORE ") : "", (stplyr->textvar == 3) ? M_GetText("MORE ") : "",
(G_IsSpecialStage(gamemap)) ? "SPHERE" : "RING", (G_IsSpecialStage(gamemap)) ? "SPHERE" : "CHIP",
(stplyr->capsule->health > 1) ? "S" : "")); (stplyr->capsule->health > 1) ? "S" : ""));
} }
// End Bonus // End Bonus
else if (stplyr->textvar == 4) else if (stplyr->textvar == 4)
{ {
V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "RINGS:"); V_DrawString(BASEVIDWIDTH/2 - 56, 140, aflag, (G_IsSpecialStage(gamemap)) ? "SPHERES:" : "CHIPS:");
V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:"); V_DrawString(BASEVIDWIDTH/2 - 56, 148, aflag, "BONUS:");
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings)); V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres));
V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 140, V_ORANGEMAP|aflag, va("%d", stplyr->finishedrings * 50)); V_DrawRightAlignedString(BASEVIDWIDTH/2 + 56, 148, V_ORANGEMAP|aflag, va("%d", stplyr->finishedspheres * 50));
ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE); ST_DrawNightsOverlayNum((BASEVIDWIDTH/2 + 56)<<FRACBITS, 160<<FRACBITS, FRACUNIT, aflag, stplyr->lastmarescore, nightsnum, SKINCOLOR_AZURE);
// If new record, say so! // If new record, say so!
@ -1460,15 +1458,15 @@ static void ST_drawNiGHTSHUD(void)
{ {
INT32 origamount; INT32 origamount;
INT32 minlink = 1; INT32 minlink = 1;
INT32 total_ringcount; INT32 total_spherecount;
const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS));
// When debugging, show "0 Link".
if (cv_debug & DBG_NIGHTSBASIC)
minlink = 0;
// Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional) // Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
if (stplyr->texttimer && stplyr->textvar == 4) if (oldspecialstage || (stplyr->texttimer && stplyr->textvar == 4))
minlink = INT32_MAX; minlink = INT32_MAX;
// When debugging, show "0 Link".
else if (cv_debug & DBG_NIGHTSBASIC)
minlink = 0;
// Drill meter // Drill meter
if ( if (
@ -1574,25 +1572,37 @@ static void ST_drawNiGHTSHUD(void)
// Begin drawing brackets/chip display // Begin drawing brackets/chip display
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_nightsrings)) if (LUA_HudEnabled(hud_nightsspheres))
{ {
#endif #endif
ST_DrawTopLeftOverlayPatch(16, 8, nbracket); ST_DrawTopLeftOverlayPatch(16, 8, nbracket);
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
ST_DrawTopLeftOverlayPatch(24, 16, nsshud); ST_DrawTopLeftOverlayPatch(24, 16, (
#ifdef MANIASPHERES
(stplyr->bonustime && (leveltime & 4)) ? nssbon :
#endif
nsshud));
else else
ST_DrawTopLeftOverlayPatch(24, 16, nhud[(leveltime/2)%12]); ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12)));
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ {
INT32 i; INT32 i;
total_ringcount = 0; total_spherecount = 0;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/ && players[i].rings) if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/ && players[i].spheres)
total_ringcount += players[i].rings; total_spherecount += players[i].spheres;
} }
else else
total_ringcount = stplyr->rings; total_spherecount = stplyr->spheres;
/*if (oldspecialstage)
{
if (total_spherecount < ssspheres)
total_spherecount = ssspheres - total_spherecount;
else
total_spherecount = 0;
}*/
if (stplyr->capsule) if (stplyr->capsule)
{ {
@ -1648,28 +1658,48 @@ static void ST_drawNiGHTSHUD(void)
amount = (origamount - stplyr->capsule->health); amount = (origamount - stplyr->capsule->health);
amount = (amount * length)/origamount; amount = (amount * length)/origamount;
for (cfill = 0; cfill < amount && cfill < 88; ++cfill) for (cfill = 0; cfill < amount && cfill < length; ++cfill)
V_DrawScaledPatch(15 + cfill + 1, 8 + 35, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill); V_DrawScaledPatch(15 + cfill + 1, 8 + 35, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill);
} }
if (total_ringcount >= stplyr->capsule->health) if (total_spherecount >= stplyr->capsule->health)
ST_DrawTopLeftOverlayPatch(40, 8 + 5, nredar[leveltime%8]); ST_DrawTopLeftOverlayPatch(40, 8 + 5, nredar[leveltime&7]);
else else
ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)%8]); ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)&7]);
}
else if (oldspecialstage && total_spherecount < (INT32)ssspheres)
{
INT32 cfill, amount;
const INT32 length = 88;
UINT8 em = P_GetNextEmerald();
ST_DrawTopLeftOverlayPatch(72, 8, nbracket);
if (em <= 7)
ST_DrawTopLeftOverlayPatch(80, 8 + 8, emeraldpics[0][em]);
ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[(leveltime/2)&7]);
// Lil' white box!
V_DrawScaledPatch(15, 8 + 34, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulebar);
amount = (total_spherecount * length)/ssspheres;
for (cfill = 0; cfill < amount && cfill < length; ++cfill)
V_DrawScaledPatch(15 + cfill + 1, 8 + 35, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOTOP|V_HUDTRANS, capsulefill);
} }
else else
ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]); ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]);
if (total_ringcount >= 100) if (total_spherecount >= 100)
V_DrawTallNum((total_ringcount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_ringcount); V_DrawTallNum((total_spherecount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount);
else else
V_DrawTallNum(68, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_ringcount); V_DrawTallNum(68, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount);
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
} }
#endif #endif
// Score // Score
if (!stplyr->exiting if (!stplyr->exiting && !oldspecialstage
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_nightsscore) && LUA_HudEnabled(hud_nightsscore)
#endif #endif
@ -1712,6 +1742,7 @@ static void ST_drawNiGHTSHUD(void)
{ {
INT32 realnightstime = stplyr->nightstime/TICRATE; INT32 realnightstime = stplyr->nightstime/TICRATE;
INT32 numbersize; INT32 numbersize;
UINT8 col = ((realnightstime < 10) ? SKINCOLOR_RED : SKINCOLOR_SUPERGOLD4);
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ {
@ -1742,46 +1773,66 @@ static void ST_drawNiGHTSHUD(void)
else else
numbersize = 48/2; numbersize = 48/2;
ST_DrawNightsOverlayNum((160 + numbersize)<<FRACBITS, 14<<FRACBITS, FRACUNIT, V_PERPLAYER|V_SNAPTOTOP, realnightstime, nightsnum, if ((oldspecialstage && leveltime & 2)
((realnightstime < 10) ? SKINCOLOR_RED : SKINCOLOR_SUPERGOLD4)); && (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)))
col = SKINCOLOR_ORANGE;
ST_DrawNightsOverlayNum((160 + numbersize)<<FRACBITS, 14<<FRACBITS, FRACUNIT, V_PERPLAYER|V_SNAPTOTOP, realnightstime, nightsnum, col);
// Show exact time in debug // Show exact time in debug
if (cv_debug & DBG_NIGHTSBASIC) if (cv_debug & DBG_NIGHTSBASIC)
V_DrawString(160 + numbersize + 8, 24, V_SNAPTOTOP|((realnightstime < 10) ? V_REDMAP : V_YELLOWMAP), va("%02d", G_TicsToCentiseconds(stplyr->nightstime))); V_DrawString(160 + numbersize + 8, 24, V_SNAPTOTOP|((realnightstime < 10) ? V_REDMAP : V_YELLOWMAP), va("%02d", G_TicsToCentiseconds(stplyr->nightstime)));
} }
// Show pickup durations if (oldspecialstage)
if (cv_debug & DBG_NIGHTSBASIC)
{ {
UINT16 pwr; if (leveltime < 5*TICRATE)
if (stplyr->powers[pw_nights_superloop])
{ {
pwr = stplyr->powers[pw_nights_superloop]; INT32 aflag = V_PERPLAYER;
V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_CACHE)); tic_t drawtime = (5*TICRATE) - leveltime;
V_DrawThinString(106, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); if (drawtime < TICRATE/2)
} aflag |= (9 - 9*drawtime/(TICRATE/2)) << V_ALPHASHIFT;
// This one, not quite as much so.
if (stplyr->powers[pw_nights_helper]) V_DrawCenteredString(BASEVIDWIDTH/2, 60, aflag,
{ va(M_GetText("\x80GET\x82 %d\x80 SPHERE%s!"), ssspheres,
pwr = stplyr->powers[pw_nights_helper]; (ssspheres > 1) ? "S" : ""));
V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_CACHE));
V_DrawThinString(146, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
}
if (stplyr->powers[pw_nights_linkfreeze])
{
pwr = stplyr->powers[pw_nights_linkfreeze];
V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_CACHE));
V_DrawThinString(186, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
} }
} }
else
{
// Show pickup durations
if (cv_debug & DBG_NIGHTSBASIC)
{
UINT16 pwr;
// Records/extra text if (stplyr->powers[pw_nights_superloop])
{
pwr = stplyr->powers[pw_nights_superloop];
V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_CACHE));
V_DrawThinString(106, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
}
if (stplyr->powers[pw_nights_helper])
{
pwr = stplyr->powers[pw_nights_helper];
V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_CACHE));
V_DrawThinString(146, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
}
if (stplyr->powers[pw_nights_linkfreeze])
{
pwr = stplyr->powers[pw_nights_linkfreeze];
V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_CACHE));
V_DrawThinString(186, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr)));
}
}
// Records/extra text
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_nightsrecords)) if (LUA_HudEnabled(hud_nightsrecords))
#endif #endif
ST_drawNightsRecords(); ST_drawNightsRecords();
}
} }
static inline void ST_drawWeaponSelect(INT32 xoffs, INT32 y) static inline void ST_drawWeaponSelect(INT32 xoffs, INT32 y)
@ -1950,7 +2001,7 @@ static void ST_drawTextHUD(void)
} }
else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE)) else if (stplyr->spectator && (gametype != GT_COOP || stplyr->playerstate == PST_LIVE))
{ {
if (G_IsSpecialStage(gamemap) && useNightsSS) if (G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS))
textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) textHUDdraw(M_GetText("\x82""Wait for the stage to end..."))
else if (gametype == GT_COOP) else if (gametype == GT_COOP)
{ {
@ -2068,22 +2119,22 @@ num:
#undef SEP #undef SEP
} }
static void ST_drawSpecialStageHUD(void) /*static void ST_drawSpecialStageHUD(void)
{ {
if (totalrings > 0) if (ssspheres > 0)
{ {
if (hudinfo[HUD_SS_TOTALRINGS].x) if (hudinfo[HUD_SS_TOTALRINGS].x)
ST_DrawNumFromHud(HUD_SS_TOTALRINGS, totalrings, V_HUDTRANS); ST_DrawNumFromHud(HUD_SS_TOTALRINGS, ssspheres, V_HUDTRANS);
else if (cv_timetic.value == 2) else if (cv_timetic.value == 2)
V_DrawTallNum(hudinfo[HUD_RINGSNUMTICS].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUMTICS].f|V_PERPLAYER|V_HUDTRANS, totalrings); V_DrawTallNum(hudinfo[HUD_RINGSNUMTICS].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUMTICS].f|V_PERPLAYER|V_HUDTRANS, ssspheres);
else else
V_DrawTallNum(hudinfo[HUD_RINGSNUM].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUM].f|V_PERPLAYER|V_HUDTRANS, totalrings); V_DrawTallNum(hudinfo[HUD_RINGSNUM].x, hudinfo[HUD_SS_TOTALRINGS].y, hudinfo[HUD_RINGSNUM].f|V_PERPLAYER|V_HUDTRANS, ssspheres);
} }
if (leveltime < 5*TICRATE && totalrings > 0) if (leveltime < 5*TICRATE && ssspheres > 0)
{ {
ST_DrawPatchFromHud(HUD_GETRINGS, getall, V_HUDTRANS); ST_DrawPatchFromHud(HUD_GETRINGS, getall, V_HUDTRANS);
ST_DrawNumFromHud(HUD_GETRINGSNUM, totalrings, V_HUDTRANS); ST_DrawNumFromHud(HUD_GETRINGSNUM, ssspheres, V_HUDTRANS);
} }
if (sstimer) if (sstimer)
@ -2093,7 +2144,7 @@ static void ST_drawSpecialStageHUD(void)
} }
else else
ST_DrawPatchFromHud(HUD_TIMEUP, timeup, V_HUDTRANS); ST_DrawPatchFromHud(HUD_TIMEUP, timeup, V_HUDTRANS);
} }*/
static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offset) static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offset)
{ {
@ -2229,7 +2280,7 @@ static void ST_overlayDrawer(void)
//hu_showscores = auto hide score/time/rings when tab rankings are shown //hu_showscores = auto hide score/time/rings when tab rankings are shown
if (!(hu_showscores && (netgame || multiplayer))) if (!(hu_showscores && (netgame || multiplayer)))
{ {
if (maptol & TOL_NIGHTS) if (maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap))
ST_drawNiGHTSHUD(); ST_drawNiGHTSHUD();
else else
{ {
@ -2338,10 +2389,6 @@ static void ST_overlayDrawer(void)
if (gametype == GT_RACE || gametype == GT_COMPETITION) if (gametype == GT_RACE || gametype == GT_COMPETITION)
ST_drawRaceHUD(); ST_drawRaceHUD();
// Special Stage HUD
if (!useNightsSS && G_IsSpecialStage(gamemap) && stplyr == &players[displayplayer])
ST_drawSpecialStageHUD();
// Emerald Hunt Indicators // Emerald Hunt Indicators
if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER)) if (cv_itemfinder.value && M_SecretUnlocked(SECRET_ITEMFINDER))
ST_doItemFinderIconsAndSound(); ST_doItemFinderIconsAndSound();
@ -2360,15 +2407,18 @@ static void ST_overlayDrawer(void)
} }
// This is where we draw all the fun cheese if you have the chasecam off! // This is where we draw all the fun cheese if you have the chasecam off!
if ((stplyr == &players[displayplayer] && !camera.chase) if (!(maptol & TOL_NIGHTS))
|| ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase))
{ {
ST_drawFirstPersonHUD(); if ((stplyr == &players[displayplayer] && !camera.chase)
if (cv_powerupdisplay.value) || ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase))
{
ST_drawFirstPersonHUD();
if (cv_powerupdisplay.value)
ST_drawPowerupHUD();
}
else if (cv_powerupdisplay.value == 2)
ST_drawPowerupHUD(); ST_drawPowerupHUD();
} }
else if (cv_powerupdisplay.value == 2)
ST_drawPowerupHUD();
} }
#ifdef HAVE_BLUA #ifdef HAVE_BLUA

View File

@ -1624,7 +1624,7 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
{ {
INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0; INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0;
const char *ch = string; const char *ch = string;
INT32 charflags = 0; INT32 charflags = (option & V_CHARCOLORMASK);
const UINT8 *colormap = NULL; const UINT8 *colormap = NULL;
INT32 spacewidth = 4, charwidth = 0; INT32 spacewidth = 4, charwidth = 0;
@ -1644,8 +1644,6 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
left = (scrwidth - BASEVIDWIDTH)/2; left = (scrwidth - BASEVIDWIDTH)/2;
} }
charflags = (option & V_CHARCOLORMASK);
switch (option & V_SPACINGMASK) switch (option & V_SPACINGMASK)
{ {
case V_MONOSPACE: case V_MONOSPACE:
@ -2154,8 +2152,10 @@ INT32 V_CreditStringWidth(const char *string)
// //
void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string) void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
{ {
INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH; INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0;
const char *ch = string; const char *ch = string;
INT32 charflags = (option & V_CHARCOLORMASK);
const UINT8 *colormap = NULL;
if (option & V_NOSCALESTART) if (option & V_NOSCALESTART)
{ {
@ -2164,21 +2164,31 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
scrwidth = vid.width; scrwidth = vid.width;
} }
else else
dupx = dupy = 1;
for (;;)
{ {
c = *ch++; dupx = dupy = 1;
if (!c) scrwidth = vid.width/vid.dupx;
left = (scrwidth - BASEVIDWIDTH)/2;
}
for (;;ch++)
{
if (!*ch)
break; break;
if (c == '\n') if (*ch & 0x80) //color parsing -x 2.16.09
{
// manually set flags override color codes
if (!(option & V_CHARCOLORMASK))
charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
continue;
}
if (*ch == '\n')
{ {
cx = x; cx = x;
cy += 12*dupy; cy += 12*dupy;
continue; continue;
} }
c = toupper(c) - LT_FONTSTART; c = toupper(*ch) - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
{ {
cx += 16*dupx; cx += 16*dupx;
@ -2186,17 +2196,19 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string)
} }
w = SHORT(lt_font[c]->width) * dupx; w = SHORT(lt_font[c]->width) * dupx;
if (cx + w > scrwidth)
break;
if (cx+left > scrwidth)
break;
//left boundary check //left boundary check
if (cx < 0) if (cx+left + w < 0)
{ {
cx += w; cx += w;
continue; continue;
} }
V_DrawScaledPatch(cx, cy, option, lt_font[c]); colormap = V_GetStringColormap(charflags);
V_DrawFixedPatch(cx<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, lt_font[c], colormap);
cx += w; cx += w;
} }
} }
@ -2210,6 +2222,8 @@ INT32 V_LevelNameWidth(const char *string)
for (i = 0; i < strlen(string); i++) for (i = 0; i < strlen(string); i++)
{ {
if (string[i] & 0x80)
continue;
c = toupper(string[i]) - LT_FONTSTART; c = toupper(string[i]) - LT_FONTSTART;
if (c < 0 || c >= LT_FONTSIZE || !lt_font[c]) if (c < 0 || c >= LT_FONTSIZE || !lt_font[c])
w += 16; w += 16;
@ -2265,11 +2279,9 @@ INT32 V_StringWidth(const char *string, INT32 option)
for (i = 0; i < strlen(string); i++) for (i = 0; i < strlen(string); i++)
{ {
c = string[i]; if (string[i] & 0x80)
if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09
continue; continue;
c = toupper(string[i]) - HU_FONTSTART;
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
w += spacewidth; w += spacewidth;
else else
@ -2307,11 +2319,9 @@ INT32 V_SmallStringWidth(const char *string, INT32 option)
for (i = 0; i < strlen(string); i++) for (i = 0; i < strlen(string); i++)
{ {
c = string[i]; if (string[i] & 0x80)
if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09
continue; continue;
c = toupper(string[i]) - HU_FONTSTART;
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !hu_font[c]) if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
w += spacewidth; w += spacewidth;
else else
@ -2346,11 +2356,9 @@ INT32 V_ThinStringWidth(const char *string, INT32 option)
for (i = 0; i < strlen(string); i++) for (i = 0; i < strlen(string); i++)
{ {
c = string[i]; if (string[i] & 0x80)
if ((UINT8)c >= 0x80 && (UINT8)c <= 0x89) //color parsing! -Inuyasha 2.16.09
continue; continue;
c = toupper(string[i]) - HU_FONTSTART;
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !tny_font[c]) if (c < 0 || c >= HU_FONTSIZE || !tny_font[c])
w += spacewidth; w += spacewidth;
else else

View File

@ -194,11 +194,11 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum)
for (; posStart < posEnd; posStart++) for (; posStart < posEnd; posStart++)
LUA_LoadLump(wadnum, posStart); LUA_LoadLump(wadnum, posStart);
} }
posStart = W_CheckNumForFolderStartPK3("SOCs/", wadnum, 0); posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0);
if (posStart != INT16_MAX) if (posStart != INT16_MAX)
{ {
posEnd = W_CheckNumForFolderEndPK3("SOCs/", wadnum, posStart); posEnd = W_CheckNumForFolderEndPK3("SOC/", wadnum, posStart);
posStart++; // first "lump" will be "SOCs/" folder itself, so ignore it posStart++; // first "lump" will be "SOC/" folder itself, so ignore it
for(; posStart < posEnd; posStart++) for(; posStart < posEnd; posStart++)
{ {
lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart]; lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart];

View File

@ -77,8 +77,8 @@ typedef union
struct struct
{ {
char passed1[29]; // KNUCKLES GOT / CRAWLA HONCHO char passed1[29]; // KNUCKLES GOT / CRAWLA HONCHO
char passed2[17]; // A CHAOS EMERALD / GOT THEM ALL! char passed2[17]; // A CHAOS EMERALD? / GOT THEM ALL!
char passed3[15]; // CAN NOW BECOME char passed3[15]; // CAN NOW BECOME
char passed4[SKINNAMESIZE+7]; // SUPER CRAWLA HONCHO char passed4[SKINNAMESIZE+7]; // SUPER CRAWLA HONCHO
INT32 passedx1; INT32 passedx1;
@ -315,6 +315,9 @@ void Y_IntermissionDrawer(void)
INT32 xoffset1 = 0; // Line 1 x offset INT32 xoffset1 = 0; // Line 1 x offset
INT32 xoffset2 = 0; // Line 2 x offset INT32 xoffset2 = 0; // Line 2 x offset
INT32 xoffset3 = 0; // Line 3 x offset INT32 xoffset3 = 0; // Line 3 x offset
INT32 xoffset4 = 0; // Line 4 x offset
INT32 xoffset5 = 0; // Line 5 x offset
INT32 xoffset6 = 0; // Line 6 x offset
UINT8 drawsection = 0; UINT8 drawsection = 0;
if (gottoken) // first to be behind everything else if (gottoken) // first to be behind everything else
@ -324,71 +327,130 @@ void Y_IntermissionDrawer(void)
if (intertic <= 2*TICRATE) if (intertic <= 2*TICRATE)
animatetic = 0; animatetic = 0;
else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0') else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0')
animatetic = intertic; animatetic = intertic + TICRATE;
if (animatetic) if (animatetic && (tic_t)intertic >= animatetic)
{ {
const INT32 scradjust = (vid.width/vid.dupx)>>3; // 40 for BASEVIDWIDTH
INT32 animatetimer = (intertic - animatetic); INT32 animatetimer = (intertic - animatetic);
if (animatetimer <= 8) if (animatetimer <= 14)
{ {
xoffset1 = -(animatetimer * 40); xoffset1 = -(animatetimer * scradjust);
xoffset2 = -((animatetimer-2) * 40); xoffset2 = -((animatetimer-2) * scradjust);
xoffset3 = -((animatetimer-4) * scradjust);
xoffset4 = -((animatetimer-6) * scradjust);
xoffset5 = -((animatetimer-8) * scradjust);
if (xoffset2 > 0) xoffset2 = 0; if (xoffset2 > 0) xoffset2 = 0;
if (xoffset3 > 0) xoffset3 = 0;
if (xoffset4 > 0) xoffset4 = 0;
if (xoffset5 > 0) xoffset5 = 0;
} }
else if (animatetimer <= 19) else if (animatetimer < 32)
{ {
drawsection = 1; drawsection = 1;
xoffset1 = (16-animatetimer) * 40; xoffset1 = (22-animatetimer) * scradjust;
xoffset2 = (18-animatetimer) * 40; xoffset2 = (24-animatetimer) * scradjust;
xoffset3 = (20-animatetimer) * 40; xoffset3 = (26-animatetimer) * scradjust;
xoffset4 = (28-animatetimer) * scradjust;
xoffset5 = (30-animatetimer) * scradjust;
xoffset6 = (32-animatetimer) * scradjust;
if (xoffset1 < 0) xoffset1 = 0; if (xoffset1 < 0) xoffset1 = 0;
if (xoffset2 < 0) xoffset2 = 0; if (xoffset2 < 0) xoffset2 = 0;
if (xoffset3 < 0) xoffset3 = 0;
if (xoffset4 < 0) xoffset4 = 0;
if (xoffset5 < 0) xoffset5 = 0;
} }
else else
{
drawsection = 1; drawsection = 1;
if (animatetimer == 32)
S_StartSound(NULL, sfx_s3k68);
}
} }
if (drawsection == 1) if (drawsection == 1)
{ {
const char *ringtext = "\x86" "50 RINGS, NO SHIELD";
const char *tut1text = "\x86" "PRESS " "\x82" "SPIN";
const char *tut2text = "\x86" "MID-" "\x82" "JUMP";
ttheight = 16; ttheight = 16;
V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
ttheight += V_LevelNameHeight(data.spec.passed3) + 2; ttheight += V_LevelNameHeight(data.spec.passed3) + 2;
V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3); V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3);
ttheight += V_LevelNameHeight(data.spec.passed4) + 2; ttheight += V_LevelNameHeight(data.spec.passed4) + 2;
V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4); V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4);
}
else if (data.spec.passed1[0] != '\0') ttheight = 108;
{ V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset4 - (V_LevelNameWidth(ringtext)/2), ttheight, 0, ringtext);
ttheight = 24; ttheight += V_LevelNameHeight(ringtext) + 2;
V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text);
ttheight += V_LevelNameHeight(data.spec.passed2) + 2; ttheight += V_LevelNameHeight(tut1text) + 2;
V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2); V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset6 - (V_LevelNameWidth(tut2text)/2), ttheight, 0, tut2text);
} }
else else
{ {
ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2; if (data.spec.passed1[0] != '\0')
V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); {
ttheight = 24;
V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
ttheight += V_LevelNameHeight(data.spec.passed2) + 2;
V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2);
}
else
{
ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2;
V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2);
}
V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatch);
V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonus.points);
V_DrawScaledPatch(152 + xoffset4, 124, 0, data.spec.pscore);
V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125, 0, data.spec.score);
// Draw continues!
if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay
{
UINT8 continues = data.spec.continues & 0x7F;
V_DrawScaledPatch(152 + xoffset5, 150, 0, data.spec.pcontinues);
for (i = 0; i < continues; ++i)
{
if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10))
break;
V_DrawContinueIcon(246 + xoffset5 - (i*12), 162, 0, *data.spec.playerchar, *data.spec.playercolor);
}
}
} }
// draw the emeralds // draw the emeralds
//if (intertic & 1) //if (intertic & 1)
{ {
boolean drawthistic = !(ALL7EMERALDS(emeralds) && (intertic & 1));
INT32 emeraldx = 152 - 3*28; INT32 emeraldx = 152 - 3*28;
INT32 em = (gamemap - sstage_start); INT32 em = P_GetNextEmerald();
for (i = 0; i < 7; ++i) if (em == 7)
{ {
if ((i != em) && !(intertic & 1) && (emeralds & (1 << i))) if (!stagefailed)
V_DrawScaledPatch(emeraldx, 74, 0, emeraldpics[0][i]); {
emeraldx += 28; fixed_t adjust = 2*(FINESINE(FixedAngle((intertic + 1)<<(FRACBITS-4)) & FINEMASK));
V_DrawFixedPatch(152<<FRACBITS, (74<<FRACBITS) - adjust, FRACUNIT, 0, emeraldpics[0][em], NULL);
}
} }
else if (em < 7)
if (em < 7)
{ {
static UINT8 emeraldbounces = 0; static UINT8 emeraldbounces = 0;
static INT32 emeraldmomy = 20; static INT32 emeraldmomy = 20;
static INT32 emeraldy = -40; static INT32 emeraldy = -40;
if (drawthistic)
for (i = 0; i < 7; ++i)
{
if ((i != em) && (emeralds & (1 << i)))
V_DrawScaledPatch(emeraldx, 74, 0, emeraldpics[0][i]);
emeraldx += 28;
}
emeraldx = 152 + (em-3)*28; emeraldx = 152 + (em-3)*28;
if (intertic <= 1) if (intertic <= 1)
@ -399,7 +461,7 @@ void Y_IntermissionDrawer(void)
} }
else else
{ {
if (emeralds & (1 << em)) if (!stagefailed)
{ {
if (emeraldbounces < 3) if (emeraldbounces < 3)
{ {
@ -427,29 +489,11 @@ void Y_IntermissionDrawer(void)
emeraldy = 74; emeraldy = 74;
} }
} }
V_DrawScaledPatch(emeraldx, emeraldy, 0, emeraldpics[0][em]); if (drawthistic)
V_DrawScaledPatch(emeraldx, emeraldy, 0, emeraldpics[0][em]);
} }
} }
} }
V_DrawScaledPatch(152, 108, 0, data.spec.bonuspatch);
V_DrawTallNum(BASEVIDWIDTH - 68, 109, 0, data.spec.bonus.points);
V_DrawScaledPatch(152, 124, 0, data.spec.pscore);
V_DrawTallNum(BASEVIDWIDTH - 68, 125, 0, data.spec.score);
// Draw continues!
if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay
{
UINT8 continues = data.spec.continues & 0x7F;
V_DrawScaledPatch(152, 150, 0, data.spec.pcontinues);
for (i = 0; i < continues; ++i)
{
if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10))
break;
V_DrawContinueIcon(246 - (i*12), 162, 0, *data.spec.playerchar, *data.spec.playercolor);
}
}
} }
else if (intertype == int_match || intertype == int_race) else if (intertype == int_match || intertype == int_race)
{ {
@ -831,7 +875,7 @@ void Y_Ticker(void)
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && !demoplayback) if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && !demoplayback)
{ {
if (M_UpdateUnlockablesAndExtraEmblems()) if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_ncitem); S_StartSound(NULL, sfx_s3k68);
G_SaveGameData(); G_SaveGameData();
} }
@ -850,7 +894,7 @@ void Y_Ticker(void)
{ {
INT32 i; INT32 i;
UINT32 oldscore = data.spec.score; UINT32 oldscore = data.spec.score;
boolean skip = false; boolean skip = false, super = false;
if (!intertic) // first time only if (!intertic) // first time only
{ {
@ -862,15 +906,22 @@ void Y_Ticker(void)
return; return;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && (players[i].cmd.buttons & BT_USE)) if (playeringame[i])
skip = true; {
if (players[i].cmd.buttons & BT_USE)
skip = true;
if (players[i].charflags & SF_SUPER)
super = true;
}
if ((data.spec.continues & 0x80) && tallydonetic != -1) if (tallydonetic != -1 && ((data.spec.continues & 0x80) || (super && ALL7EMERALDS(emeralds))))
{ {
if ((intertic - tallydonetic) > (3*TICRATE)/2) if ((intertic - tallydonetic) > (3*TICRATE)/2)
{ {
endtic = intertic + 4*TICRATE; // 4 second pause after end of tally endtic = intertic + 4*TICRATE; // 4 second pause after end of tally
S_StartSound(NULL, sfx_s3kac); // bingly-bingly-bing! if (data.spec.continues & 0x80)
S_StartSound(NULL, sfx_s3kac); // bingly-bingly-bing!
} }
return; return;
} }
@ -887,7 +938,7 @@ void Y_Ticker(void)
if (!data.spec.bonus.points) if (!data.spec.bonus.points)
{ {
tallydonetic = intertic; tallydonetic = intertic;
if (!(data.spec.continues & 0x80)) // don't set endtic yet! if (!((data.spec.continues & 0x80) || (super && ALL7EMERALDS(emeralds)))) // don't set endtic yet!
endtic = intertic + 4*TICRATE; // 4 second pause after end of tally endtic = intertic + 4*TICRATE; // 4 second pause after end of tally
S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching! S_StartSound(NULL, (gottoken ? sfx_token : sfx_chchng)); // cha-ching!
@ -896,7 +947,7 @@ void Y_Ticker(void)
if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && !demoplayback) if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && !demoplayback)
{ {
if (M_UpdateUnlockablesAndExtraEmblems()) if (M_UpdateUnlockablesAndExtraEmblems())
S_StartSound(NULL, sfx_ncitem); S_StartSound(NULL, sfx_s3k68);
G_SaveGameData(); G_SaveGameData();
} }
@ -1286,7 +1337,7 @@ void Y_StartIntermission(void)
data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0'; data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
strcpy(data.spec.passed2, "GOT THEM ALL!"); strcpy(data.spec.passed2, "GOT THEM ALL!");
if (skins[players[consoleplayer].skin].flags & SF_SUPER) if (players[consoleplayer].charflags & SF_SUPER)
{ {
strcpy(data.spec.passed3, "CAN NOW BECOME"); strcpy(data.spec.passed3, "CAN NOW BECOME");
snprintf(data.spec.passed4, snprintf(data.spec.passed4,
@ -1307,6 +1358,11 @@ void Y_StartIntermission(void)
else else
strcpy(data.spec.passed1, "YOU GOT"); strcpy(data.spec.passed1, "YOU GOT");
strcpy(data.spec.passed2, "A CHAOS EMERALD"); strcpy(data.spec.passed2, "A CHAOS EMERALD");
if (P_GetNextEmerald() > 6)
{
data.spec.passed2[15] = '?';
data.spec.passed2[16] = '\0';
}
} }
data.spec.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed1))/2; data.spec.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed1))/2;
data.spec.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed2))/2; data.spec.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed2))/2;
@ -1745,7 +1801,7 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct)
if (!playeringame[i]) continue; if (!playeringame[i]) continue;
sharedringtotal += players[i].rings; sharedringtotal += players[i].rings;
} }
if (!sharedringtotal || sharedringtotal < nummaprings) if (!sharedringtotal || nummaprings == -1 || sharedringtotal < nummaprings)
data.coop.gotperfbonus = 0; data.coop.gotperfbonus = 0;
else else
data.coop.gotperfbonus = 1; data.coop.gotperfbonus = 1;
@ -1857,7 +1913,7 @@ static void Y_AwardSpecialStageBonus(void)
if (!playeringame[i] || players[i].lives < 1) // not active or game over if (!playeringame[i] || players[i].lives < 1) // not active or game over
Y_SetNullBonus(&players[i], &localbonus); Y_SetNullBonus(&players[i], &localbonus);
else if (useNightsSS) // Link instead of Score else if (maptol & TOL_NIGHTS) // Link instead of Rings
Y_SetLinkBonus(&players[i], &localbonus); Y_SetLinkBonus(&players[i], &localbonus);
else else
Y_SetRingBonus(&players[i], &localbonus); Y_SetRingBonus(&players[i], &localbonus);