Merge branch 'musicplus-core' into musicplus-sdlmixerx

This commit is contained in:
mazmazz 2018-11-13 14:34:28 -05:00
commit f2bfed7892
78 changed files with 3135 additions and 711 deletions

View file

@ -13,8 +13,6 @@
- libupnp (Linux/OS X only) - libupnp (Linux/OS X only)
- libgme (Linux/OS X only) - libgme (Linux/OS X only)
Warning: 64-bit builds are not netgame compatible with 32-bit builds. Use at your own risk.
## Compiling ## Compiling
See [SRB2 Wiki/Source code compiling](http://wiki.srb2.org/wiki/Source_code_compiling) See [SRB2 Wiki/Source code compiling](http://wiki.srb2.org/wiki/Source_code_compiling)

View file

@ -64,6 +64,7 @@
# Compile without 3D sound support, add 'NOHS=1' # Compile without 3D sound support, add 'NOHS=1'
# Compile with GDBstubs, add 'RDB=1' # Compile with GDBstubs, add 'RDB=1'
# Compile without PNG, add 'NOPNG=1' # Compile without PNG, add 'NOPNG=1'
# Compile without zlib, add 'NOZLIB=1'
# #
# Addon for SDL: # Addon for SDL:
# To Cross-Compile, add 'SDL_CONFIG=/usr/*/bin/sdl-config' # To Cross-Compile, add 'SDL_CONFIG=/usr/*/bin/sdl-config'
@ -109,6 +110,7 @@ include Makefile.cfg
ifdef DUMMY ifdef DUMMY
NOPNG=1 NOPNG=1
NOZLIB=1
NONET=1 NONET=1
NOHW=1 NOHW=1
NOHS=1 NOHS=1
@ -271,13 +273,6 @@ LIBS+=$(PNG_LDFLAGS)
CFLAGS+=$(PNG_CFLAGS) CFLAGS+=$(PNG_CFLAGS)
endif endif
ZLIB_PKGCONFIG?=zlib
ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
LIBS+=$(ZLIB_LDFLAGS)
CFLAGS+=$(ZLIB_CFLAGS)
ifdef HAVE_LIBGME ifdef HAVE_LIBGME
OPTS+=-DHAVE_LIBGME OPTS+=-DHAVE_LIBGME
@ -289,6 +284,18 @@ LIBS+=$(LIBGME_LDFLAGS)
CFLAGS+=$(LIBGME_CFLAGS) CFLAGS+=$(LIBGME_CFLAGS)
endif endif
ifndef NOZLIB
OPTS+=-DHAVE_ZLIB
ZLIB_PKGCONFIG?=zlib
ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
LIBS+=$(ZLIB_LDFLAGS)
CFLAGS+=$(ZLIB_CFLAGS)
else
NOPNG=1
endif
ifdef STATIC ifdef STATIC
LIBS:=-static $(LIBS) LIBS:=-static $(LIBS)
endif endif

View file

@ -21,13 +21,14 @@ void I_ShutdownSound(void){}
// SFX I/O // SFX I/O
// //
INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority) INT32 I_StartSound(sfxenum_t id, INT32 vol, INT32 sep, INT32 pitch, INT32 priority, INT32 channel)
{ {
(void)id; (void)id;
(void)vol; (void)vol;
(void)sep; (void)sep;
(void)pitch; (void)pitch;
(void)priority; (void)priority;
(void)channel;
return -1; return -1;
} }

View file

@ -15,7 +15,9 @@
#define DEALIGNED #define DEALIGNED
#endif #endif
#ifndef _BIG_ENDIAN #include "endian.h"
#ifndef SRB2_BIG_ENDIAN
// //
// Little-endian machines // Little-endian machines
// //
@ -75,7 +77,7 @@
#define READANGLE(p) *((angle_t *)p)++ #define READANGLE(p) *((angle_t *)p)++
#endif #endif
#else //_BIG_ENDIAN #else //SRB2_BIG_ENDIAN
// //
// definitions for big-endian machines with alignment constraints. // definitions for big-endian machines with alignment constraints.
// //
@ -144,7 +146,7 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr)
#define READCHAR(p) ({ char *p_tmp = ( char *)p; char b = *p_tmp; p_tmp++; p = (void *)p_tmp; b; }) #define READCHAR(p) ({ char *p_tmp = ( char *)p; char b = *p_tmp; p_tmp++; p = (void *)p_tmp; b; })
#define READFIXED(p) ({ fixed_t *p_tmp = (fixed_t *)p; fixed_t b = readlong(p); p_tmp++; p = (void *)p_tmp; b; }) #define READFIXED(p) ({ fixed_t *p_tmp = (fixed_t *)p; fixed_t b = readlong(p); p_tmp++; p = (void *)p_tmp; b; })
#define READANGLE(p) ({ angle_t *p_tmp = (angle_t *)p; angle_t b = readulong(p); p_tmp++; p = (void *)p_tmp; b; }) #define READANGLE(p) ({ angle_t *p_tmp = (angle_t *)p; angle_t b = readulong(p); p_tmp++; p = (void *)p_tmp; b; })
#endif //_BIG_ENDIAN #endif //SRB2_BIG_ENDIAN
#undef DEALIGNED #undef DEALIGNED

View file

@ -63,6 +63,7 @@ CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}};
CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
#define COM_BUF_SIZE 8192 // command buffer size #define COM_BUF_SIZE 8192 // command buffer size
#define MAX_ALIAS_RECURSION 100 // max recursion allowed for aliases
static INT32 com_wait; // one command per frame (for cmd sequences) static INT32 com_wait; // one command per frame (for cmd sequences)
@ -485,6 +486,7 @@ static void COM_ExecuteString(char *ptext)
{ {
xcommand_t *cmd; xcommand_t *cmd;
cmdalias_t *a; cmdalias_t *a;
static INT32 recursion = 0; // detects recursion and stops it if it goes too far
COM_TokenizeString(ptext); COM_TokenizeString(ptext);
@ -497,6 +499,7 @@ static void COM_ExecuteString(char *ptext)
{ {
if (!stricmp(com_argv[0], cmd->name)) //case insensitive now that we have lower and uppercase! if (!stricmp(com_argv[0], cmd->name)) //case insensitive now that we have lower and uppercase!
{ {
recursion = 0;
cmd->function(); cmd->function();
return; return;
} }
@ -507,11 +510,20 @@ static void COM_ExecuteString(char *ptext)
{ {
if (!stricmp(com_argv[0], a->name)) if (!stricmp(com_argv[0], a->name))
{ {
if (recursion > MAX_ALIAS_RECURSION)
{
CONS_Alert(CONS_WARNING, M_GetText("Alias recursion cycle detected!\n"));
recursion = 0;
return;
}
recursion++;
COM_BufInsertText(a->value); COM_BufInsertText(a->value);
return; return;
} }
} }
recursion = 0;
// check cvars // check cvars
// Hurdler: added at Ebola's request ;) // Hurdler: added at Ebola's request ;)
// (don't flood the console in software mode with bad gr_xxx command) // (don't flood the console in software mode with bad gr_xxx command)

View file

@ -232,18 +232,20 @@ UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *orangem
// Console BG color // Console BG color
UINT8 *consolebgmap = NULL; UINT8 *consolebgmap = NULL;
UINT8 *promptbgmap = NULL;
static UINT8 promptbgcolor = UINT8_MAX;
void CON_SetupBackColormap(void) void CON_SetupBackColormapEx(INT32 color, boolean prompt)
{ {
UINT16 i, palsum; UINT16 i, palsum;
UINT8 j, palindex, shift; UINT8 j, palindex, shift;
UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE); UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
if (!consolebgmap) if (color == INT32_MAX)
consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); color = cons_backcolor.value;
shift = 6; // 12 colors -- shift of 7 means 6 colors shift = 6; // 12 colors -- shift of 7 means 6 colors
switch (cons_backcolor.value) switch (color)
{ {
case 0: palindex = 15; break; // White case 0: palindex = 15; break; // White
case 1: palindex = 31; break; // Gray case 1: palindex = 31; break; // Gray
@ -257,20 +259,42 @@ void CON_SetupBackColormap(void)
case 9: palindex = 187; break; // Magenta case 9: palindex = 187; break; // Magenta
case 10: palindex = 139; break; // Aqua case 10: palindex = 139; break; // Aqua
// Default green // Default green
default: palindex = 175; break; default: palindex = 175; color = 11; break;
} }
if (prompt)
{
if (!promptbgmap)
promptbgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
if (color == promptbgcolor)
return;
else
promptbgcolor = color;
}
else if (!consolebgmap)
consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
// setup background colormap // setup background colormap
for (i = 0, j = 0; i < 768; i += 3, j++) for (i = 0, j = 0; i < 768; i += 3, j++)
{ {
palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift; palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift;
consolebgmap[j] = (UINT8)(palindex - palsum); if (prompt)
promptbgmap[j] = (UINT8)(palindex - palsum);
else
consolebgmap[j] = (UINT8)(palindex - palsum);
} }
} }
void CON_SetupBackColormap(void)
{
CON_SetupBackColormapEx(cons_backcolor.value, false);
CON_SetupBackColormapEx(1, true); // default to gray
}
static void CONS_backcolor_Change(void) static void CONS_backcolor_Change(void)
{ {
CON_SetupBackColormap(); CON_SetupBackColormapEx(cons_backcolor.value, false);
} }
static void CON_SetupColormaps(void) static void CON_SetupColormaps(void)

View file

@ -38,7 +38,9 @@ extern UINT8 *yellowmap, *magentamap, *lgreenmap, *bluemap, *graymap, *redmap, *
// Console bg color (auto updated to match) // Console bg color (auto updated to match)
extern UINT8 *consolebgmap; extern UINT8 *consolebgmap;
extern UINT8 *promptbgmap;
void CON_SetupBackColormapEx(INT32 color, boolean prompt);
void CON_SetupBackColormap(void); void CON_SetupBackColormap(void);
void CON_ClearHUD(void); // clear heads up messages void CON_ClearHUD(void); // clear heads up messages

View file

@ -2353,7 +2353,7 @@ void CL_ClearPlayer(INT32 playernum)
// //
// Removes a player from the current game // Removes a player from the current game
// //
static void CL_RemovePlayer(INT32 playernum) static void CL_RemovePlayer(INT32 playernum, INT32 reason)
{ {
// Sanity check: exceptional cases (i.e. c-fails) can cause multiple // Sanity check: exceptional cases (i.e. c-fails) can cause multiple
// kick commands to be issued for the same player. // kick commands to be issued for the same player.
@ -2407,6 +2407,10 @@ static void CL_RemovePlayer(INT32 playernum)
} }
} }
} }
#ifdef HAVE_BLUA
LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting
#endif
// Reset player data // Reset player data
CL_ClearPlayer(playernum); CL_ClearPlayer(playernum);
@ -2683,6 +2687,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
INT32 pnum, msg; INT32 pnum, msg;
char buf[3 + MAX_REASONLENGTH]; char buf[3 + MAX_REASONLENGTH];
char *reason = buf; char *reason = buf;
kickreason_t kickreason = KR_KICK;
pnum = READUINT8(*p); pnum = READUINT8(*p);
msg = READUINT8(*p); msg = READUINT8(*p);
@ -2765,14 +2770,17 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
{ {
case KICK_MSG_GO_AWAY: case KICK_MSG_GO_AWAY:
CONS_Printf(M_GetText("has been kicked (Go away)\n")); CONS_Printf(M_GetText("has been kicked (Go away)\n"));
kickreason = KR_KICK;
break; break;
#ifdef NEWPING #ifdef NEWPING
case KICK_MSG_PING_HIGH: case KICK_MSG_PING_HIGH:
CONS_Printf(M_GetText("left the game (Broke ping limit)\n")); CONS_Printf(M_GetText("left the game (Broke ping limit)\n"));
kickreason = KR_PINGLIMIT;
break; break;
#endif #endif
case KICK_MSG_CON_FAIL: case KICK_MSG_CON_FAIL:
CONS_Printf(M_GetText("left the game (Synch failure)\n")); CONS_Printf(M_GetText("left the game (Synch failure)\n"));
kickreason = KR_SYNCH;
if (M_CheckParm("-consisdump")) // Helps debugging some problems if (M_CheckParm("-consisdump")) // Helps debugging some problems
{ {
@ -2809,21 +2817,26 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
break; break;
case KICK_MSG_TIMEOUT: case KICK_MSG_TIMEOUT:
CONS_Printf(M_GetText("left the game (Connection timeout)\n")); CONS_Printf(M_GetText("left the game (Connection timeout)\n"));
kickreason = KR_TIMEOUT;
break; break;
case KICK_MSG_PLAYER_QUIT: case KICK_MSG_PLAYER_QUIT:
if (netgame) // not splitscreen/bots if (netgame) // not splitscreen/bots
CONS_Printf(M_GetText("left the game\n")); CONS_Printf(M_GetText("left the game\n"));
kickreason = KR_LEAVE;
break; break;
case KICK_MSG_BANNED: case KICK_MSG_BANNED:
CONS_Printf(M_GetText("has been banned (Don't come back)\n")); CONS_Printf(M_GetText("has been banned (Don't come back)\n"));
kickreason = KR_BAN;
break; break;
case KICK_MSG_CUSTOM_KICK: case KICK_MSG_CUSTOM_KICK:
READSTRINGN(*p, reason, MAX_REASONLENGTH+1); READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
CONS_Printf(M_GetText("has been kicked (%s)\n"), reason); CONS_Printf(M_GetText("has been kicked (%s)\n"), reason);
kickreason = KR_KICK;
break; break;
case KICK_MSG_CUSTOM_BAN: case KICK_MSG_CUSTOM_BAN:
READSTRINGN(*p, reason, MAX_REASONLENGTH+1); READSTRINGN(*p, reason, MAX_REASONLENGTH+1);
CONS_Printf(M_GetText("has been banned (%s)\n"), reason); CONS_Printf(M_GetText("has been banned (%s)\n"), reason);
kickreason = KR_BAN;
break; break;
} }
@ -2851,7 +2864,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING);
} }
else else
CL_RemovePlayer(pnum); CL_RemovePlayer(pnum, kickreason);
} }
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL };

View file

@ -454,6 +454,17 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_KICK 7 #define KICK_MSG_CUSTOM_KICK 7
#define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_CUSTOM_BAN 8
typedef enum
{
KR_KICK = 1, //Kicked by server
KR_PINGLIMIT = 2, //Broke Ping Limit
KR_SYNCH = 3, //Synch Failure
KR_TIMEOUT = 4, //Connection Timeout
KR_BAN = 5, //Banned by server
KR_LEAVE = 6, //Quit the game
} kickreason_t;
extern boolean server; extern boolean server;
#define client (!server) #define client (!server)
extern boolean dedicated; // For dedicated server extern boolean dedicated; // For dedicated server

View file

@ -71,6 +71,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#include "fastcmp.h" #include "fastcmp.h"
#include "keys.h" #include "keys.h"
#include "filesrch.h" // refreshdirmenu, mainwadstally #include "filesrch.h" // refreshdirmenu, mainwadstally
#include "g_input.h" // tutorial mode control scheming
#ifdef CMAKECONFIG #ifdef CMAKECONFIG
#include "config.h" #include "config.h"
@ -151,7 +152,7 @@ void D_PostEvent(const event_t *ev)
eventhead = (eventhead+1) & (MAXEVENTS-1); eventhead = (eventhead+1) & (MAXEVENTS-1);
} }
// just for lock this function // just for lock this function
#ifndef DOXYGEN #if defined (PC_DOS) && !defined (DOXYGEN)
void D_PostEvent_end(void) {}; void D_PostEvent_end(void) {};
#endif #endif
@ -424,6 +425,7 @@ static void D_Display(void)
if (gamestate == GS_LEVEL) if (gamestate == GS_LEVEL)
{ {
ST_Drawer(); ST_Drawer();
F_TextPromptDrawer();
HU_Drawer(); HU_Drawer();
} }
else else
@ -733,6 +735,19 @@ void D_StartTitle(void)
// Reset the palette // Reset the palette
if (rendermode != render_none) if (rendermode != render_none)
V_SetPaletteLump("PLAYPAL"); V_SetPaletteLump("PLAYPAL");
// The title screen is obviously not a tutorial! (Unless I'm mistaken)
if (tutorialmode && tutorialgcs)
{
G_CopyControls(gamecontrol, gamecontroldefault[gcs_custom], gcl_tutorial_full, num_gcl_tutorial_full); // using gcs_custom as temp storage
CV_SetValue(&cv_usemouse, tutorialusemouse);
CV_SetValue(&cv_alwaysfreelook, tutorialfreelook);
CV_SetValue(&cv_mousemove, tutorialmousemove);
CV_SetValue(&cv_analog, tutorialanalog);
M_StartMessage("Do you want to \x82save the recommended \x82movement controls?\x80\n\nPress 'Y' or 'Enter' to confirm\nPress 'N' or any key to keep \nyour current controls",
M_TutorialSaveControlResponse, MM_YESNO);
}
tutorialmode = false;
} }
// //
@ -766,10 +781,6 @@ static inline void D_CleanFile(void)
} }
} }
#ifndef _MAX_PATH
#define _MAX_PATH MAX_WADPATH
#endif
// ========================================================================== // ==========================================================================
// Identify the SRB2 version, and IWAD file to use. // Identify the SRB2 version, and IWAD file to use.
// ========================================================================== // ==========================================================================

View file

@ -40,8 +40,8 @@ void D_SRB2Main(void);
// Called by IO functions when input is detected. // Called by IO functions when input is detected.
void D_PostEvent(const event_t *ev); void D_PostEvent(const event_t *ev);
#ifndef DOXYGEN #if defined (PC_DOS) && !defined (DOXYGEN)
FUNCMATH void D_PostEvent_end(void); // delimiter for locking memory void D_PostEvent_end(void); // delimiter for locking memory
#endif #endif
void D_ProcessEvents(void); void D_ProcessEvents(void);

View file

@ -126,8 +126,6 @@ FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void);
static void Command_Playintro_f(void); static void Command_Playintro_f(void);
static void Command_Displayplayer_f(void); static void Command_Displayplayer_f(void);
static void Command_Tunes_f(void);
static void Command_RestartAudio_f(void);
static void Command_ExitLevel_f(void); static void Command_ExitLevel_f(void);
static void Command_Showmap_f(void); static void Command_Showmap_f(void);
@ -315,8 +313,6 @@ consvar_t cv_timetic = {"timerres", "Classic", CV_SAVE, timetic_cons_t, NULL, 0,
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};
consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}}; static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}};
consvar_t cv_pointlimit = {"pointlimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, consvar_t cv_pointlimit = {"pointlimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t,
PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL}; PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL};
@ -685,14 +681,6 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_ghost_guest); CV_RegisterVar(&cv_ghost_guest);
COM_AddCommand("displayplayer", Command_Displayplayer_f); COM_AddCommand("displayplayer", Command_Displayplayer_f);
COM_AddCommand("tunes", Command_Tunes_f);
COM_AddCommand("restartaudio", Command_RestartAudio_f);
CV_RegisterVar(&cv_resetmusic);
#ifdef HAVE_MIXERX
CV_RegisterVar(&cv_midiplayer);
CV_RegisterVar(&cv_midisoundfontpath);
CV_RegisterVar(&cv_miditimiditypath);
#endif
// FIXME: not to be here.. but needs be done for config loading // FIXME: not to be here.. but needs be done for config loading
CV_RegisterVar(&cv_globalgamma); CV_RegisterVar(&cv_globalgamma);
@ -724,6 +712,7 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_crosshair2); CV_RegisterVar(&cv_crosshair2);
CV_RegisterVar(&cv_alwaysfreelook); CV_RegisterVar(&cv_alwaysfreelook);
CV_RegisterVar(&cv_alwaysfreelook2); CV_RegisterVar(&cv_alwaysfreelook2);
CV_RegisterVar(&cv_tutorialprompt);
// g_input.c // g_input.c
CV_RegisterVar(&cv_sideaxis); CV_RegisterVar(&cv_sideaxis);
@ -1820,6 +1809,16 @@ static void Command_Map_f(void)
else else
fromlevelselect = ((netgame || multiplayer) && ((gametype == newgametype) && (newgametype == GT_COOP))); fromlevelselect = ((netgame || multiplayer) && ((gametype == newgametype) && (newgametype == GT_COOP)));
if (tutorialmode && tutorialgcs)
{
G_CopyControls(gamecontrol, gamecontroldefault[gcs_custom], gcl_tutorial_full, num_gcl_tutorial_full); // using gcs_custom as temp storage
CV_SetValue(&cv_usemouse, tutorialusemouse);
CV_SetValue(&cv_alwaysfreelook, tutorialfreelook);
CV_SetValue(&cv_mousemove, tutorialmousemove);
CV_SetValue(&cv_analog, tutorialanalog);
}
tutorialmode = false; // warping takes us out of tutorial mode
D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect); D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect);
} }
@ -3992,100 +3991,6 @@ static void Command_Displayplayer_f(void)
CONS_Printf(M_GetText("Displayplayer is %d\n"), displayplayer); CONS_Printf(M_GetText("Displayplayer is %d\n"), displayplayer);
} }
static void Command_Tunes_f(void)
{
const char *tunearg;
UINT16 tunenum, track = 0;
UINT32 position = 0;
const size_t argc = COM_Argc();
if (argc < 2) //tunes slot ...
{
CONS_Printf("tunes <name/num> [track] [speed] [position] / <-show> / <-default> / <-none>:\n");
CONS_Printf(M_GetText("Play an arbitrary music lump. If a map number is used, 'MAP##M' is played.\n"));
CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n\n"));
CONS_Printf(M_GetText("* With \"-show\", shows the currently playing tune and track.\n"));
CONS_Printf(M_GetText("* With \"-default\", returns to the default music for the map.\n"));
CONS_Printf(M_GetText("* With \"-none\", any music playing will be stopped.\n"));
return;
}
tunearg = COM_Argv(1);
tunenum = (UINT16)atoi(tunearg);
track = 0;
if (!strcasecmp(tunearg, "-show"))
{
CONS_Printf(M_GetText("The current tune is: %s [track %d]\n"),
mapmusname, (mapmusflags & MUSIC_TRACKMASK));
return;
}
if (!strcasecmp(tunearg, "-none"))
{
S_StopMusic();
return;
}
else if (!strcasecmp(tunearg, "-default"))
{
tunearg = mapheaderinfo[gamemap-1]->musname;
track = mapheaderinfo[gamemap-1]->mustrack;
}
else if (!tunearg[2] && toupper(tunearg[0]) >= 'A' && toupper(tunearg[0]) <= 'Z')
tunenum = (UINT16)M_MapNumber(tunearg[0], tunearg[1]);
if (tunenum && tunenum >= 1036)
{
CONS_Alert(CONS_NOTICE, M_GetText("Valid music slots are 1 to 1035.\n"));
return;
}
if (!tunenum && strlen(tunearg) > 6) // This is automatic -- just show the error just in case
CONS_Alert(CONS_NOTICE, M_GetText("Music name too long - truncated to six characters.\n"));
if (argc > 2)
track = (UINT16)atoi(COM_Argv(2))-1;
if (tunenum)
snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum));
else
strncpy(mapmusname, tunearg, 7);
if (argc > 4)
position = (UINT32)atoi(COM_Argv(4));
mapmusname[6] = 0;
mapmusflags = (track & MUSIC_TRACKMASK);
mapmusposition = position;
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
if (argc > 3)
{
float speed = (float)atof(COM_Argv(3));
if (speed > 0.0f)
S_SpeedMusic(speed);
}
}
static void Command_RestartAudio_f(void)
{
if (dedicated) // No point in doing anything if game is a dedicated server.
return;
S_StopMusic();
S_StopSounds();
I_ShutdownMusic();
I_ShutdownSound();
I_StartupSound();
I_InitMusic();
// These must be called or no sound and music until manually set.
I_SetSfxVolume(cv_soundvolume.value);
S_SetMusicVolume(cv_digmusicvolume.value, cv_midimusicvolume.value);
if (Playing()) // Gotta make sure the player is in a level
P_RestoreMusic(&players[consoleplayer]);
}
/** Quits a game and returns to the title screen. /** Quits a game and returns to the title screen.
* *
*/ */

View file

@ -103,8 +103,6 @@ extern consvar_t cv_startinglives;
// for F_finale.c // for F_finale.c
extern consvar_t cv_rollingdemos; extern consvar_t cv_rollingdemos;
extern consvar_t cv_resetmusic;
extern consvar_t cv_ringslinger, cv_soundtest; extern consvar_t cv_ringslinger, cv_soundtest;
extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes; extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes;
@ -202,6 +200,4 @@ void D_SetPassword(const char *pw);
// used for the player setup menu // used for the player setup menu
UINT8 CanChangeSkin(INT32 playernum); UINT8 CanChangeSkin(INT32 playernum);
#endif #endif

View file

@ -32,6 +32,7 @@
#include "fastcmp.h" #include "fastcmp.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "d_clisrv.h"
#include "m_cond.h" #include "m_cond.h"
@ -165,9 +166,14 @@ static char *myhashfgets(char *buf, size_t bufsize, MYFILE *f)
if (c == '\n') // Ensure debug line is right... if (c == '\n') // Ensure debug line is right...
dbg_line++; dbg_line++;
if (c == '#') if (c == '#')
{
if (i > 0) // don't let i wrap past 0
i--; // don't include hash char in string
break; break;
}
} }
i++; if (buf[i] != '#') // don't include hash char in string
i++;
buf[i] = '\0'; buf[i] = '\0';
return buf; return buf;
@ -914,7 +920,10 @@ static void readlevelheader(MYFILE *f, INT32 num)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -1551,6 +1560,365 @@ static void readcutscene(MYFILE *f, INT32 num)
Z_Free(s); Z_Free(s);
} }
static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum)
{
char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
INT32 i;
UINT16 usi;
UINT8 picid;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
if (fastcmp(word, "PAGETEXT"))
{
char *pagetext = NULL;
char *buffer;
const int bufferlen = 4096;
for (i = 0; i < MAXLINELEN; i++)
{
if (s[i] == '=')
{
pagetext = &s[i+2];
break;
}
}
if (!pagetext)
{
Z_Free(textprompts[num]->page[pagenum].text);
textprompts[num]->page[pagenum].text = NULL;
continue;
}
for (i = 0; i < MAXLINELEN; i++)
{
if (s[i] == '\0')
{
s[i] = '\n';
s[i+1] = '\0';
break;
}
}
buffer = Z_Malloc(4096, PU_STATIC, NULL);
strcpy(buffer, pagetext);
// \todo trim trailing whitespace before the #
// and also support # at the end of a PAGETEXT with no line break
strcat(buffer,
myhashfgets(pagetext, bufferlen
- strlen(buffer) - 1, f));
// A text prompt overwriting another one...
Z_Free(textprompts[num]->page[pagenum].text);
textprompts[num]->page[pagenum].text = Z_StrDup(buffer);
Z_Free(buffer);
continue;
}
word2 = strtok(NULL, " = ");
if (word2)
strupr(word2);
else
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
i = atoi(word2);
usi = (UINT16)i;
// copypasta from readcutscenescene
if (fastcmp(word, "NUMBEROFPICS"))
{
textprompts[num]->page[pagenum].numpics = (UINT8)i;
}
else if (fastcmp(word, "PICMODE"))
{
UINT8 picmode = 0; // PROMPT_PIC_PERSIST
if (usi == 1 || word2[0] == 'L') picmode = PROMPT_PIC_LOOP;
else if (usi == 2 || word2[0] == 'D' || word2[0] == 'H') picmode = PROMPT_PIC_DESTROY;
textprompts[num]->page[pagenum].picmode = picmode;
}
else if (fastcmp(word, "PICTOLOOP"))
textprompts[num]->page[pagenum].pictoloop = (UINT8)i;
else if (fastcmp(word, "PICTOSTART"))
textprompts[num]->page[pagenum].pictostart = (UINT8)i;
else if (fastcmp(word, "PICSMETAPAGE"))
{
if (usi && usi <= textprompts[num]->numpages)
{
UINT8 metapagenum = usi - 1;
textprompts[num]->page[pagenum].numpics = textprompts[num]->page[metapagenum].numpics;
textprompts[num]->page[pagenum].picmode = textprompts[num]->page[metapagenum].picmode;
textprompts[num]->page[pagenum].pictoloop = textprompts[num]->page[metapagenum].pictoloop;
textprompts[num]->page[pagenum].pictostart = textprompts[num]->page[metapagenum].pictostart;
for (picid = 0; picid < MAX_PROMPT_PICS; picid++)
{
strncpy(textprompts[num]->page[pagenum].picname[picid], textprompts[num]->page[metapagenum].picname[picid], 8);
textprompts[num]->page[pagenum].pichires[picid] = textprompts[num]->page[metapagenum].pichires[picid];
textprompts[num]->page[pagenum].picduration[picid] = textprompts[num]->page[metapagenum].picduration[picid];
textprompts[num]->page[pagenum].xcoord[picid] = textprompts[num]->page[metapagenum].xcoord[picid];
textprompts[num]->page[pagenum].ycoord[picid] = textprompts[num]->page[metapagenum].ycoord[picid];
}
}
}
else if (fastncmp(word, "PIC", 3))
{
picid = (UINT8)atoi(word + 3);
if (picid > MAX_PROMPT_PICS || picid == 0)
{
deh_warning("textpromptscene %d: unknown word '%s'", num, word);
continue;
}
--picid;
if (fastcmp(word+4, "NAME"))
{
strncpy(textprompts[num]->page[pagenum].picname[picid], word2, 8);
}
else if (fastcmp(word+4, "HIRES"))
{
textprompts[num]->page[pagenum].pichires[picid] = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
}
else if (fastcmp(word+4, "DURATION"))
{
textprompts[num]->page[pagenum].picduration[picid] = usi;
}
else if (fastcmp(word+4, "XCOORD"))
{
textprompts[num]->page[pagenum].xcoord[picid] = usi;
}
else if (fastcmp(word+4, "YCOORD"))
{
textprompts[num]->page[pagenum].ycoord[picid] = usi;
}
else
deh_warning("textpromptscene %d: unknown word '%s'", num, word);
}
else if (fastcmp(word, "MUSIC"))
{
strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7);
textprompts[num]->page[pagenum].musswitch[6] = 0;
}
#ifdef MUSICSLOT_COMPATIBILITY
else if (fastcmp(word, "MUSICSLOT"))
{
i = get_mus(word2, true);
if (i && i <= 1035)
snprintf(textprompts[num]->page[pagenum].musswitch, 7, "%sM", G_BuildMapName(i));
else if (i && i <= 1050)
strncpy(textprompts[num]->page[pagenum].musswitch, compat_special_music_slots[i - 1036], 7);
else
textprompts[num]->page[pagenum].musswitch[0] = 0; // becomes empty string
textprompts[num]->page[pagenum].musswitch[6] = 0;
}
#endif
else if (fastcmp(word, "MUSICTRACK"))
{
textprompts[num]->page[pagenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK;
}
else if (fastcmp(word, "MUSICLOOP"))
{
textprompts[num]->page[pagenum].musicloop = (UINT8)(i || word2[0] == 'T' || word2[0] == 'Y');
}
// end copypasta from readcutscenescene
else if (fastcmp(word, "NAME"))
{
INT32 j;
// HACK: Add yellow control char now
// so the drawing function doesn't call it repeatedly
char name[34];
name[0] = '\x82'; // color yellow
name[1] = 0;
strncat(name, word2, 33);
name[33] = 0;
// Replace _ with ' '
for (j = 0; j < 32 && name[j]; j++)
{
if (name[j] == '_')
name[j] = ' ';
}
strncpy(textprompts[num]->page[pagenum].name, name, 32);
}
else if (fastcmp(word, "ICON"))
strncpy(textprompts[num]->page[pagenum].iconname, word2, 8);
else if (fastcmp(word, "ICONALIGN"))
textprompts[num]->page[pagenum].rightside = (i || word2[0] == 'R');
else if (fastcmp(word, "ICONFLIP"))
textprompts[num]->page[pagenum].iconflip = (i || word2[0] == 'T' || word2[0] == 'Y');
else if (fastcmp(word, "LINES"))
textprompts[num]->page[pagenum].lines = usi;
else if (fastcmp(word, "BACKCOLOR"))
{
INT32 backcolor;
if (i == 0 || fastcmp(word2, "WHITE")) backcolor = 0;
else if (i == 1 || fastcmp(word2, "GRAY") || fastcmp(word2, "GREY") ||
fastcmp(word2, "BLACK")) backcolor = 1;
else if (i == 2 || fastcmp(word2, "BROWN")) backcolor = 2;
else if (i == 3 || fastcmp(word2, "RED")) backcolor = 3;
else if (i == 4 || fastcmp(word2, "ORANGE")) backcolor = 4;
else if (i == 5 || fastcmp(word2, "YELLOW")) backcolor = 5;
else if (i == 6 || fastcmp(word2, "GREEN")) backcolor = 6;
else if (i == 7 || fastcmp(word2, "BLUE")) backcolor = 7;
else if (i == 8 || fastcmp(word2, "PURPLE")) backcolor = 8;
else if (i == 9 || fastcmp(word2, "MAGENTA")) backcolor = 9;
else if (i == 10 || fastcmp(word2, "AQUA")) backcolor = 10;
else if (i < 0) backcolor = INT32_MAX; // CONS_BACKCOLOR user-configured
else backcolor = 1; // default gray
textprompts[num]->page[pagenum].backcolor = backcolor;
}
else if (fastcmp(word, "ALIGN"))
{
UINT8 align = 0; // left
if (usi == 1 || word2[0] == 'R') align = 1;
else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2;
textprompts[num]->page[pagenum].align = align;
}
else if (fastcmp(word, "VERTICALALIGN"))
{
UINT8 align = 0; // top
if (usi == 1 || word2[0] == 'B') align = 1;
else if (usi == 2 || word2[0] == 'C' || word2[0] == 'M') align = 2;
textprompts[num]->page[pagenum].verticalalign = align;
}
else if (fastcmp(word, "TEXTSPEED"))
textprompts[num]->page[pagenum].textspeed = get_number(word2);
else if (fastcmp(word, "TEXTSFX"))
textprompts[num]->page[pagenum].textsfx = get_number(word2);
else if (fastcmp(word, "HIDEHUD"))
{
UINT8 hidehud = 0;
if ((word2[0] == 'F' && (word2[1] == 'A' || !word2[1])) || word2[0] == 'N') hidehud = 0; // false
else if (usi == 1 || word2[0] == 'T' || word2[0] == 'Y') hidehud = 1; // true (hide appropriate HUD elements)
else if (usi == 2 || word2[0] == 'A' || (word2[0] == 'F' && word2[1] == 'O')) hidehud = 2; // force (hide all HUD elements)
textprompts[num]->page[pagenum].hidehud = hidehud;
}
else if (fastcmp(word, "METAPAGE"))
{
if (usi && usi <= textprompts[num]->numpages)
{
UINT8 metapagenum = usi - 1;
strncpy(textprompts[num]->page[pagenum].name, textprompts[num]->page[metapagenum].name, 32);
strncpy(textprompts[num]->page[pagenum].iconname, textprompts[num]->page[metapagenum].iconname, 8);
textprompts[num]->page[pagenum].rightside = textprompts[num]->page[metapagenum].rightside;
textprompts[num]->page[pagenum].iconflip = textprompts[num]->page[metapagenum].iconflip;
textprompts[num]->page[pagenum].lines = textprompts[num]->page[metapagenum].lines;
textprompts[num]->page[pagenum].backcolor = textprompts[num]->page[metapagenum].backcolor;
textprompts[num]->page[pagenum].align = textprompts[num]->page[metapagenum].align;
textprompts[num]->page[pagenum].verticalalign = textprompts[num]->page[metapagenum].verticalalign;
textprompts[num]->page[pagenum].textspeed = textprompts[num]->page[metapagenum].textspeed;
textprompts[num]->page[pagenum].textsfx = textprompts[num]->page[metapagenum].textsfx;
textprompts[num]->page[pagenum].hidehud = textprompts[num]->page[metapagenum].hidehud;
// music: don't copy, else each page change may reset the music
}
}
else if (fastcmp(word, "TAG"))
strncpy(textprompts[num]->page[pagenum].tag, word2, 33);
else if (fastcmp(word, "NEXTPROMPT"))
textprompts[num]->page[pagenum].nextprompt = usi;
else if (fastcmp(word, "NEXTPAGE"))
textprompts[num]->page[pagenum].nextpage = usi;
else if (fastcmp(word, "NEXTTAG"))
strncpy(textprompts[num]->page[pagenum].nexttag, word2, 33);
else if (fastcmp(word, "TIMETONEXT"))
textprompts[num]->page[pagenum].timetonext = get_number(word2);
else
deh_warning("PromptPage %d: unknown word '%s'", num, word);
}
} while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
static void readtextprompt(MYFILE *f, INT32 num)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 value;
// Allocate memory for this prompt if we don't yet have any
if (!textprompts[num])
textprompts[num] = Z_Calloc(sizeof (textprompt_t), PU_STATIC, NULL);
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " ");
if (word2)
value = atoi(word2);
else
{
deh_warning("No value for token %s", word);
continue;
}
if (fastcmp(word, "NUMPAGES"))
{
textprompts[num]->numpages = min(max(value, 0), MAX_PAGES);
}
else if (fastcmp(word, "PAGE"))
{
if (1 <= value && value <= MAX_PAGES)
{
textprompts[num]->page[value - 1].backcolor = 1; // default to gray
textprompts[num]->page[value - 1].hidehud = 1; // hide appropriate HUD elements
readtextpromptpage(f, num, value - 1);
}
else
deh_warning("Page number %d out of range (1 - %d)", value, MAX_PAGES);
}
else
deh_warning("Prompt %d: unknown word '%s', Page <num> expected.", num, word);
}
} while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
static void readhuditem(MYFILE *f, INT32 num) static void readhuditem(MYFILE *f, INT32 num)
{ {
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -1579,7 +1947,10 @@ static void readhuditem(MYFILE *f, INT32 num)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -2085,7 +2456,10 @@ static void reademblemdata(MYFILE *f, INT32 num)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -2220,7 +2594,10 @@ static void readextraemblemdata(MYFILE *f, INT32 num)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -2295,7 +2672,10 @@ static void readunlockable(MYFILE *f, INT32 num)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -2582,7 +2962,10 @@ static void readconditionset(MYFILE *f, UINT8 setnum)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -2643,7 +3026,10 @@ static void readmaincfg(MYFILE *f)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -2876,6 +3262,19 @@ static void readmaincfg(MYFILE *f)
startchar = (INT16)value; startchar = (INT16)value;
char_on = -1; char_on = -1;
} }
else if (fastcmp(word, "TUTORIALMAP"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
value = M_MapNumber(word2[0], word2[1]);
else
value = get_number(word2);
tutorialmap = (INT16)value;
}
else else
deh_warning("Maincfg: unknown word '%s'", word); deh_warning("Maincfg: unknown word '%s'", word);
} }
@ -2914,7 +3313,10 @@ static void readwipes(MYFILE *f)
// Get the part before the " = " // Get the part before the " = "
tmp = strchr(s, '='); tmp = strchr(s, '=');
*(tmp-1) = '\0'; if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word); strupr(word);
// Now get the part after // Now get the part after
@ -3220,6 +3622,16 @@ static void DEH_LoadDehackedFile(MYFILE *f)
ignorelines(f); ignorelines(f);
} }
} }
else if (fastcmp(word, "PROMPT"))
{
if (i > 0 && i < MAX_PROMPTS)
readtextprompt(f, i - 1);
else
{
deh_warning("Prompt number %d out of range (1 - %d)", i, MAX_PROMPTS);
ignorelines(f);
}
}
else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE")) else if (fastcmp(word, "FRAME") || fastcmp(word, "STATE"))
{ {
if (i == 0 && word2[0] != '0') // If word2 isn't a number if (i == 0 && word2[0] != '0') // If word2 isn't a number
@ -6943,6 +7355,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_PULL", "MT_PULL",
"MT_GHOST", "MT_GHOST",
"MT_OVERLAY", "MT_OVERLAY",
"MT_ANGLEMAN",
"MT_POLYANCHOR", "MT_POLYANCHOR",
"MT_POLYSPAWN", "MT_POLYSPAWN",
"MT_POLYSPAWNCRUSH", "MT_POLYSPAWNCRUSH",
@ -7754,6 +8167,13 @@ struct {
// Node flags // Node flags
{"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf. {"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf.
#endif #endif
#ifdef ESLOPE
// Slope flags
{"SL_NOPHYSICS",SL_NOPHYSICS}, // Don't do momentum adjustment with this slope
{"SL_NODYNAMIC",SL_NODYNAMIC}, // Slope will never need to move during the level, so don't fuss with recalculating it
{"SL_ANCHORVERTEX",SL_ANCHORVERTEX},// Slope is using a Slope Vertex Thing to anchor its position
{"SL_VERTEXSLOPE",SL_VERTEXSLOPE}, // Slope is built from three Slope Vertex Things
#endif
// Angles // Angles
{"ANG1",ANG1}, {"ANG1",ANG1},
@ -7886,6 +8306,14 @@ struct {
{"V_CHARCOLORSHIFT",V_CHARCOLORSHIFT}, {"V_CHARCOLORSHIFT",V_CHARCOLORSHIFT},
{"V_ALPHASHIFT",V_ALPHASHIFT}, {"V_ALPHASHIFT",V_ALPHASHIFT},
//Kick Reasons
{"KR_KICK",KR_KICK},
{"KR_PINGLIMIT",KR_PINGLIMIT},
{"KR_SYNCH",KR_SYNCH},
{"KR_TIMEOUT",KR_TIMEOUT},
{"KR_BAN",KR_BAN},
{"KR_LEAVE",KR_LEAVE},
#endif #endif
{NULL,0} {NULL,0}
@ -8274,7 +8702,7 @@ fixed_t get_number(const char *word)
#endif #endif
} }
void FUNCMATH DEH_Check(void) void DEH_Check(void)
{ {
#if defined(_DEBUG) || defined(PARANOIA) #if defined(_DEBUG) || defined(PARANOIA)
const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*); const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*);
@ -8750,6 +9178,9 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"maptol")) { } else if (fastcmp(word,"maptol")) {
lua_pushinteger(L, maptol); lua_pushinteger(L, maptol);
return 1; return 1;
} else if (fastcmp(word,"ultimatemode")) {
lua_pushboolean(L, ultimatemode != 0);
return 1;
} else if (fastcmp(word,"mariomode")) { } else if (fastcmp(word,"mariomode")) {
lua_pushboolean(L, mariomode != 0); lua_pushboolean(L, mariomode != 0);
return 1; return 1;
@ -8879,17 +9310,17 @@ static int lib_getActionName(lua_State *L)
{ {
lua_settop(L, 1); // set top of stack to 1 (removing any extra args, which there shouldn't be) lua_settop(L, 1); // set top of stack to 1 (removing any extra args, which there shouldn't be)
// get the name for this action, if possible. // get the name for this action, if possible.
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_ACTIONS); lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS);
lua_pushnil(gL); lua_pushnil(L);
// Lua stack at this point: // Lua stack at this point:
// 1 ... -2 -1 // 1 ... -2 -1
// arg ... LREG_ACTIONS nil // arg ... LREG_ACTIONS nil
while (lua_next(gL, -2)) while (lua_next(L, -2))
{ {
// Lua stack at this point: // Lua stack at this point:
// 1 ... -3 -2 -1 // 1 ... -3 -2 -1
// arg ... LREG_ACTIONS "A_ACTION" function // arg ... LREG_ACTIONS "A_ACTION" function
if (lua_rawequal(gL, -1, 1)) // is this the same as the arg? if (lua_rawequal(L, -1, 1)) // is this the same as the arg?
{ {
// make sure the key (i.e. "A_ACTION") is a string first // make sure the key (i.e. "A_ACTION") is a string first
// (note: we don't use lua_isstring because it also returns true for numbers) // (note: we don't use lua_isstring because it also returns true for numbers)
@ -8898,12 +9329,12 @@ static int lib_getActionName(lua_State *L)
lua_pushvalue(L, -2); // push "A_ACTION" string to top of stack lua_pushvalue(L, -2); // push "A_ACTION" string to top of stack
return 1; return 1;
} }
lua_pop(gL, 2); // pop the name and function lua_pop(L, 2); // pop the name and function
break; // probably should have succeeded but we didn't, so end the loop break; // probably should have succeeded but we didn't, so end the loop
} }
lua_pop(gL, 1); lua_pop(L, 1);
} }
lua_pop(gL, 1); // pop LREG_ACTIONS lua_pop(L, 1); // pop LREG_ACTIONS
return 0; // return nothing (don't error) return 0; // return nothing (don't error)
} }

View file

@ -156,9 +156,11 @@ INT32 I_StartSound ( sfxenum_t id,
INT32 vol, INT32 vol,
INT32 sep, INT32 sep,
INT32 pitch, INT32 pitch,
INT32 priority ) INT32 priority,
INT32 channel)
{ {
int voice; int voice;
(void)channel;
if (sound_disabled) if (sound_disabled)
return 0; return 0;
@ -548,6 +550,7 @@ void I_ResumeSong (INT32 handle)
songpaused = false; songpaused = false;
} }
void I_SetMusicVolume(INT32 volume) void I_SetMusicVolume(INT32 volume)
{ {
if (midi_disabled) if (midi_disabled)
@ -563,18 +566,6 @@ boolean I_SetSongTrack(INT32 track)
return false; return false;
} }
// Is the song playing?
#if 0
int I_QrySongPlaying(int handle)
{
if (midi_disabled)
return 0;
//return islooping || musicdies > gametic;
return (midi_pos==-1);
}
#endif
/// ------------------------ /// ------------------------
// MUSIC FADING // MUSIC FADING
/// ------------------------ /// ------------------------
@ -614,4 +605,14 @@ boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
(void)ms; (void)ms;
(void)looping; (void)looping;
return false; return false;
// Is the song playing?
#if 0
int I_QrySongPlaying(int handle)
{
if (midi_disabled)
return 0;
//return islooping || musicdies > gametic;
return (midi_pos==-1);
} }
#endif

View file

@ -573,4 +573,11 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// \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
/// FINALLY some real clipping that doesn't make walls dissappear AND speeds the game up
/// (that was the original comment from SRB2CB, sadly it is a lie and actually slows game down)
/// on the bright side it fixes some weird issues with translucent walls
/// \note SRB2CB port.
/// SRB2CB itself ported this from PrBoom+
#define NEWCLIP
#endif // __DOOMDEF__ #endif // __DOOMDEF__

View file

@ -131,6 +131,14 @@ 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 INT16 tutorialmap; // map to load for tutorial
extern boolean tutorialmode; // are we in a tutorial right now?
extern INT32 tutorialgcs; // which control scheme is loaded?
extern INT32 tutorialusemouse; // store cv_usemouse user value
extern INT32 tutorialfreelook; // store cv_alwaysfreelook user value
extern INT32 tutorialmousemove; // store cv_mousemove user value
extern INT32 tutorialanalog; // store cv_analog user value
extern boolean looptitle; extern boolean looptitle;
// CTF colors. // CTF colors.
@ -169,6 +177,60 @@ typedef struct
extern cutscene_t *cutscenes[128]; extern cutscene_t *cutscenes[128];
// Reserve prompt space for tutorials
#define TUTORIAL_PROMPT 201 // one-based
#define TUTORIAL_AREAS 6
#define TUTORIAL_AREA_PROMPTS 5
#define MAX_PROMPTS (TUTORIAL_PROMPT+TUTORIAL_AREAS*TUTORIAL_AREA_PROMPTS*3) // 3 control modes
#define MAX_PAGES 128
#define PROMPT_PIC_PERSIST 0
#define PROMPT_PIC_LOOP 1
#define PROMPT_PIC_DESTROY 2
#define MAX_PROMPT_PICS 8
typedef struct
{
UINT8 numpics;
UINT8 picmode; // sequence mode after displaying last pic, 0 = persist, 1 = loop, 2 = destroy
UINT8 pictoloop; // if picmode == loop, which pic to loop to?
UINT8 pictostart; // initial pic number to show
char picname[MAX_PROMPT_PICS][8];
UINT8 pichires[MAX_PROMPT_PICS];
UINT16 xcoord[MAX_PROMPT_PICS]; // gfx
UINT16 ycoord[MAX_PROMPT_PICS]; // gfx
UINT16 picduration[MAX_PROMPT_PICS];
char musswitch[7];
UINT16 musswitchflags;
UINT8 musicloop;
char tag[33]; // page tag
char name[34]; // narrator name, extra char for color
char iconname[8]; // narrator icon lump
boolean rightside; // narrator side, false = left, true = right
boolean iconflip; // narrator flip icon horizontally
UINT8 hidehud; // hide hud, 0 = show all, 1 = hide depending on prompt position (top/bottom), 2 = hide all
UINT8 lines; // # of lines to show. If name is specified, name takes one of the lines. If 0, defaults to 4.
INT32 backcolor; // see CON_SetupBackColormap: 0-11, INT32_MAX for user-defined (CONS_BACKCOLOR)
UINT8 align; // text alignment, 0 = left, 1 = right, 2 = center
UINT8 verticalalign; // vertical text alignment, 0 = top, 1 = bottom, 2 = middle
UINT8 textspeed; // text speed, delay in tics between characters.
sfxenum_t textsfx; // sfx_ id for printing text
UINT8 nextprompt; // next prompt to jump to, one-based. 0 = current prompt
UINT8 nextpage; // next page to jump to, one-based. 0 = next page within prompt->numpages
char nexttag[33]; // next tag to jump to. If set, this overrides nextprompt and nextpage.
INT32 timetonext; // time in tics to jump to next page automatically. 0 = don't jump automatically
char *text;
} textpage_t;
typedef struct
{
textpage_t page[MAX_PAGES];
INT32 numpages; // Number of pages in this prompt
} textprompt_t;
extern textprompt_t *textprompts[MAX_PROMPTS];
// For the Custom Exit linedef. // For the Custom Exit linedef.
extern INT16 nextmapoverride; extern INT16 nextmapoverride;
extern boolean skipstats; extern boolean skipstats;

View file

@ -40,12 +40,13 @@
typedef long ssize_t; typedef long ssize_t;
/* Older Visual C++ headers don't have the Win64-compatible typedefs... */ /* Older Visual C++ headers don't have the Win64-compatible typedefs... */
#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR))) #if (_MSC_VER <= 1200)
#define DWORD_PTR DWORD #ifndef DWORD_PTR
#endif #define DWORD_PTR DWORD
#endif
#if ((_MSC_VER <= 1200) && (!defined(PDWORD_PTR))) #ifndef PDWORD_PTR
#define PDWORD_PTR PDWORD #define PDWORD_PTR PDWORD
#endif
#endif #endif
#elif defined (__DJGPP__) #elif defined (__DJGPP__)
#define UINT8 unsigned char #define UINT8 unsigned char
@ -80,11 +81,13 @@ typedef long ssize_t;
#define NOIPX #define NOIPX
#endif #endif
/* Strings and some misc platform specific stuff */
#ifdef _MSC_VER #ifdef _MSC_VER
// Microsoft VisualC++ // Microsoft VisualC++
#if (_MSC_VER <= 1800) // MSVC 2013 and back #if (_MSC_VER <= 1800) // MSVC 2013 and back
#define snprintf _snprintf #define snprintf _snprintf
#if (_MSC_VER <= 1200) // MSVC 2012 and back #if (_MSC_VER <= 1200) // MSVC 6.0 and back
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#endif #endif
#endif #endif
@ -148,6 +151,8 @@ size_t strlcpy(char *dst, const char *src, size_t siz);
// not the number of bytes in the buffer. // not the number of bytes in the buffer.
#define STRBUFCPY(dst,src) strlcpy(dst, src, sizeof dst) #define STRBUFCPY(dst,src) strlcpy(dst, src, sizeof dst)
/* Boolean type definition */
// \note __BYTEBOOL__ used to be set above if "macintosh" was defined, // \note __BYTEBOOL__ used to be set above if "macintosh" was defined,
// if macintosh's version of boolean type isn't needed anymore, then isn't this macro pointless now? // if macintosh's version of boolean type isn't needed anymore, then isn't this macro pointless now?
#ifndef __BYTEBOOL__ #ifndef __BYTEBOOL__
@ -155,7 +160,7 @@ size_t strlcpy(char *dst, const char *src, size_t siz);
//faB: clean that up !! //faB: clean that up !!
#if defined( _MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 and forward #if defined( _MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 and forward
#include "stdbool.h" #include "stdbool.h"
#elif defined (_WIN32) #elif defined (_WIN32)
#define false FALSE // use windows types #define false FALSE // use windows types
#define true TRUE #define true TRUE
@ -205,89 +210,65 @@ size_t strlcpy(char *dst, const char *src, size_t siz);
#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ #define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
#endif #endif
union FColorRGBA /* Compiler-specific attributes and other macros */
{
UINT32 rgba;
struct
{
UINT8 red;
UINT8 green;
UINT8 blue;
UINT8 alpha;
} s;
} ATTRPACK;
typedef union FColorRGBA RGBA_t;
typedef enum
{
postimg_none,
postimg_water,
postimg_motion,
postimg_flip,
postimg_heat
} postimg_t;
typedef UINT32 lumpnum_t; // 16 : 16 unsigned long (wad num: lump num)
#define LUMPERROR UINT32_MAX
typedef UINT32 tic_t;
#define INFTICS UINT32_MAX
#ifdef _BIG_ENDIAN
#define UINT2RGBA(a) a
#else
#define UINT2RGBA(a) (UINT32)((a&0xff)<<24)|((a&0xff00)<<8)|((a&0xff0000)>>8)|(((UINT32)a&0xff000000)>>24)
#endif
#ifdef __GNUC__ // __attribute__ ((X)) #ifdef __GNUC__ // __attribute__ ((X))
#define FUNCNORETURN __attribute__ ((noreturn)) #define FUNCNORETURN __attribute__ ((noreturn))
#if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && defined (__MINGW32__)
#include "inttypes.h" #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && defined (__MINGW32__) // MinGW, >= GCC 4.1
#if 0 //defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO > 0 #include "inttypes.h"
#define FUNCPRINTF __attribute__ ((format(gnu_printf, 1, 2))) #if 0 //defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO > 0
#define FUNCDEBUG __attribute__ ((format(gnu_printf, 2, 3))) #define FUNCPRINTF __attribute__ ((format(gnu_printf, 1, 2)))
#define FUNCIERROR __attribute__ ((format(gnu_printf, 1, 2),noreturn)) #define FUNCDEBUG __attribute__ ((format(gnu_printf, 2, 3)))
#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) #define FUNCIERROR __attribute__ ((format(gnu_printf, 1, 2),noreturn))
#define FUNCPRINTF __attribute__ ((format(ms_printf, 1, 2))) #elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) // >= GCC 4.4
#define FUNCDEBUG __attribute__ ((format(ms_printf, 2, 3))) #define FUNCPRINTF __attribute__ ((format(ms_printf, 1, 2)))
#define FUNCIERROR __attribute__ ((format(ms_printf, 1, 2),noreturn)) #define FUNCDEBUG __attribute__ ((format(ms_printf, 2, 3)))
#else #define FUNCIERROR __attribute__ ((format(ms_printf, 1, 2),noreturn))
#define FUNCPRINTF __attribute__ ((format(printf, 1, 2))) #else
#define FUNCDEBUG __attribute__ ((format(printf, 2, 3))) #define FUNCPRINTF __attribute__ ((format(printf, 1, 2)))
#define FUNCIERROR __attribute__ ((format(printf, 1, 2),noreturn)) #define FUNCDEBUG __attribute__ ((format(printf, 2, 3)))
#endif #define FUNCIERROR __attribute__ ((format(printf, 1, 2),noreturn))
#else #endif
#define FUNCPRINTF __attribute__ ((format(printf, 1, 2))) #else
#define FUNCDEBUG __attribute__ ((format(printf, 2, 3))) #define FUNCPRINTF __attribute__ ((format(printf, 1, 2)))
#define FUNCIERROR __attribute__ ((format(printf, 1, 2),noreturn)) #define FUNCDEBUG __attribute__ ((format(printf, 2, 3)))
#endif #define FUNCIERROR __attribute__ ((format(printf, 1, 2),noreturn))
#ifndef FUNCIERROR #endif
#define FUNCIERROR __attribute__ ((noreturn))
#endif #ifndef FUNCIERROR
#define FUNCMATH __attribute__((const)) #define FUNCIERROR __attribute__ ((noreturn))
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) #endif
#define FUNCDEAD __attribute__ ((deprecated))
#define FUNCINLINE __attribute__((always_inline)) #define FUNCMATH __attribute__((const))
#define FUNCNONNULL __attribute__((nonnull))
#endif #if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) // >= GCC 3.1
#define FUNCNOINLINE __attribute__((noinline)) #define FUNCDEAD __attribute__ ((deprecated))
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) #define FUNCINLINE __attribute__((always_inline))
#ifdef __i386__ // i386 only #define FUNCNONNULL __attribute__((nonnull))
#define FUNCTARGET(X) __attribute__ ((__target__ (X))) #endif
#endif
#endif #define FUNCNOINLINE __attribute__((noinline))
#if defined (__MINGW32__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
#define ATTRPACK __attribute__((packed, gcc_struct)) #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) // >= GCC 4.4
#else #ifdef __i386__ // i386 only
#define ATTRPACK __attribute__((packed)) #define FUNCTARGET(X) __attribute__ ((__target__ (X)))
#endif #endif
#define ATTRUNUSED __attribute__((unused)) #endif
#if defined (__MINGW32__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) // MinGW, >= GCC 3.4
#define ATTRPACK __attribute__((packed, gcc_struct))
#else
#define ATTRPACK __attribute__((packed))
#endif
#define ATTRUNUSED __attribute__((unused))
#elif defined (_MSC_VER) #elif defined (_MSC_VER)
#define ATTRNORETURN __declspec(noreturn) #define ATTRNORETURN __declspec(noreturn)
#define ATTRINLINE __forceinline #define ATTRINLINE __forceinline
#if _MSC_VER > 1200 #if _MSC_VER > 1200 // >= MSVC 6.0
#define ATTRNOINLINE __declspec(noinline) #define ATTRNOINLINE __declspec(noinline)
#endif #endif
#endif #endif
#ifndef FUNCPRINTF #ifndef FUNCPRINTF
@ -335,4 +316,43 @@ typedef UINT32 tic_t;
#ifndef ATTRNOINLINE #ifndef ATTRNOINLINE
#define ATTRNOINLINE #define ATTRNOINLINE
#endif #endif
/* Miscellaneous types that don't fit anywhere else (Can this be changed?) */
union FColorRGBA
{
UINT32 rgba;
struct
{
UINT8 red;
UINT8 green;
UINT8 blue;
UINT8 alpha;
} s;
} ATTRPACK;
typedef union FColorRGBA RGBA_t;
typedef enum
{
postimg_none,
postimg_water,
postimg_motion,
postimg_flip,
postimg_heat
} postimg_t;
typedef UINT32 lumpnum_t; // 16 : 16 unsigned long (wad num: lump num)
#define LUMPERROR UINT32_MAX
typedef UINT32 tic_t;
#define INFTICS UINT32_MAX
#include "endian.h" // This is needed to make sure the below macro acts correctly in big endian builds
#ifdef SRB2_BIG_ENDIAN
#define UINT2RGBA(a) a
#else
#define UINT2RGBA(a) (UINT32)((a&0xff)<<24)|((a&0xff00)<<8)|((a&0xff0000)>>8)|(((UINT32)a&0xff000000)>>24)
#endif
#endif //__DOOMTYPE__ #endif //__DOOMTYPE__

View file

@ -23,13 +23,14 @@ void I_UpdateSound(void){};
// SFX I/O // SFX I/O
// //
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
{ {
(void)id; (void)id;
(void)vol; (void)vol;
(void)sep; (void)sep;
(void)pitch; (void)pitch;
(void)priority; (void)priority;
(void)channel;
return -1; return -1;
} }
@ -144,13 +145,13 @@ void I_UnloadSong(void)
boolean I_PlaySong(boolean looping) boolean I_PlaySong(boolean looping)
{ {
(void)handle; (void)handle;
(void)looping;
return false;
} }
void I_StopSong(void) void I_StopSong(void)
{ {
(void)handle; (void)handle;
(void)looping;
return false;
} }
void I_PauseSong(void) void I_PauseSong(void)
@ -180,7 +181,7 @@ boolean I_SetSongTrack(int track)
void I_SetInternalMusicVolume(UINT8 volume) void I_SetInternalMusicVolume(UINT8 volume)
{ {
(void)volume; (void)handle;
} }
void I_StopFadingSong(void) void I_StopFadingSong(void)

View file

@ -33,6 +33,8 @@
#include "m_cond.h" #include "m_cond.h"
#include "p_local.h" #include "p_local.h"
#include "p_setup.h" #include "p_setup.h"
#include "st_stuff.h" // hud hiding
#include "fastcmp.h"
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
#include "lua_hud.h" #include "lua_hud.h"
@ -48,6 +50,7 @@ static INT32 timetonext; // Delay between screen changes
static INT32 continuetime; // Short delay when continuing static INT32 continuetime; // Short delay when continuing
static tic_t animtimer; // Used for some animation timings static tic_t animtimer; // Used for some animation timings
static INT16 skullAnimCounter; // Chevron animation
static INT32 roidtics; // Asteroid spinning static INT32 roidtics; // Asteroid spinning
static INT32 deplete; static INT32 deplete;
@ -78,6 +81,18 @@ static patch_t *ttspop7;
static void F_SkyScroll(INT32 scrollspeed); static void F_SkyScroll(INT32 scrollspeed);
//
// PROMPT STATE
//
static boolean promptactive = false;
static mobj_t *promptmo;
static INT16 promptpostexectag;
static boolean promptblockcontrols;
static char *promptpagetext = NULL;
static INT32 callpromptnum = INT32_MAX;
static INT32 callpagenum = INT32_MAX;
static INT32 callplayer = INT32_MAX;
// //
// CUTSCENE TEXT WRITING // CUTSCENE TEXT WRITING
// //
@ -1414,6 +1429,7 @@ void F_StartGameEnd(void)
// //
void F_GameEndDrawer(void) void F_GameEndDrawer(void)
{ {
// this function does nothing
} }
// //
@ -1808,7 +1824,7 @@ boolean F_ContinueResponder(event_t *event)
// CUSTOM CUTSCENES // CUSTOM CUTSCENES
// ================== // ==================
static INT32 scenenum, cutnum; static INT32 scenenum, cutnum;
static INT32 picxpos, picypos, picnum, pictime; static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop;
static INT32 textxpos, textypos; static INT32 textxpos, textypos;
static boolean dofadenow = false, cutsceneover = false; static boolean dofadenow = false, cutsceneover = false;
static boolean runningprecutscene = false, precutresetplayer = false; static boolean runningprecutscene = false, precutresetplayer = false;
@ -2017,3 +2033,617 @@ boolean F_CutsceneResponder(event_t *event)
return false; return false;
} }
// ==================
// TEXT PROMPTS
// ==================
static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *boxh, INT32 *texth, INT32 *texty, INT32 *namey, INT32 *chevrony, INT32 *textx, INT32 *textr)
{
// reuse:
// cutnum -> promptnum
// scenenum -> pagenum
lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
*pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4;
*rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside);
// Vertical calculations
*boxh = *pagelines*2;
*texth = textprompts[cutnum]->page[scenenum].name[0] ? (*pagelines-1)*2 : *pagelines*2; // name takes up first line if it exists
*texty = BASEVIDHEIGHT - ((*texth * 4) + (*texth/2)*4);
*namey = BASEVIDHEIGHT - ((*boxh * 4) + (*boxh/2)*4);
*chevrony = BASEVIDHEIGHT - (((1*2) * 4) + ((1*2)/2)*4); // force on last line
// Horizontal calculations
// Shift text to the right if we have a character icon on the left side
// Add 4 margin against icon
*textx = (iconlump != LUMPERROR && !*rightside) ? ((*boxh * 4) + (*boxh/2)*4) + 4 : 4;
*textr = *rightside ? BASEVIDWIDTH - (((*boxh * 4) + (*boxh/2)*4) + 4) : BASEVIDWIDTH-4;
}
static fixed_t F_GetPromptHideHudBound(void)
{
UINT8 pagelines;
boolean rightside;
INT32 boxh, texth, texty, namey, chevrony;
INT32 textx, textr;
if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages ||
!textprompts[cutnum]->page[scenenum].hidehud ||
(splitscreen && textprompts[cutnum]->page[scenenum].hidehud != 2)) // don't hide on splitscreen, unless hide all is forced
return 0;
else if (textprompts[cutnum]->page[scenenum].hidehud == 2) // hide all
return BASEVIDHEIGHT;
F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
// calc boxheight (see V_DrawPromptBack)
boxh *= vid.dupy;
boxh = (boxh * 4) + (boxh/2)*5; // 4 lines of space plus gaps between and some leeway
// return a coordinate to check
// if negative: don't show hud elements below this coordinate (visually)
// if positive: don't show hud elements above this coordinate (visually)
return 0 - boxh; // \todo: if prompt at top of screen (someday), make this return positive
}
boolean F_GetPromptHideHudAll(void)
{
if (cutnum == INT32_MAX || scenenum == INT32_MAX || !textprompts[cutnum] || scenenum >= textprompts[cutnum]->numpages ||
!textprompts[cutnum]->page[scenenum].hidehud ||
(splitscreen && textprompts[cutnum]->page[scenenum].hidehud != 2)) // don't hide on splitscreen, unless hide all is forced
return false;
else if (textprompts[cutnum]->page[scenenum].hidehud == 2) // hide all
return true;
else
return false;
}
boolean F_GetPromptHideHud(fixed_t y)
{
INT32 ybound;
boolean fromtop;
fixed_t ytest;
if (!promptactive)
return false;
ybound = F_GetPromptHideHudBound();
fromtop = (ybound >= 0);
ytest = (fromtop ? ybound : BASEVIDHEIGHT + ybound);
return (fromtop ? y < ytest : y >= ytest); // true means hide
}
static void F_PreparePageText(char *pagetext)
{
UINT8 pagelines;
boolean rightside;
INT32 boxh, texth, texty, namey, chevrony;
INT32 textx, textr;
F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
if (promptpagetext)
Z_Free(promptpagetext);
promptpagetext = (pagetext && pagetext[0]) ? V_WordWrap(textx, textr, 0, pagetext) : Z_StrDup("");
F_NewCutscene(promptpagetext);
cutscene_textspeed = textprompts[cutnum]->page[scenenum].textspeed ? textprompts[cutnum]->page[scenenum].textspeed : TICRATE/5;
cutscene_textcount = 0; // no delay in beginning
cutscene_boostspeed = 0; // don't print 8 characters to start
// \todo update control hot strings on re-config
// and somehow don't reset cutscene text counters
}
static void F_AdvanceToNextPage(void)
{
INT32 nextprompt = textprompts[cutnum]->page[scenenum].nextprompt ? textprompts[cutnum]->page[scenenum].nextprompt - 1 : INT32_MAX,
nextpage = textprompts[cutnum]->page[scenenum].nextpage ? textprompts[cutnum]->page[scenenum].nextpage - 1 : INT32_MAX,
oldcutnum = cutnum;
if (textprompts[cutnum]->page[scenenum].nexttag[0])
F_GetPromptPageByNamedTag(textprompts[cutnum]->page[scenenum].nexttag, &nextprompt, &nextpage);
// determine next prompt
if (nextprompt != INT32_MAX)
{
if (nextprompt <= MAX_PROMPTS && textprompts[nextprompt])
cutnum = nextprompt;
else
cutnum = INT32_MAX;
}
// determine next page
if (nextpage != INT32_MAX)
{
if (cutnum != INT32_MAX)
{
scenenum = nextpage;
if (scenenum >= MAX_PAGES || scenenum > textprompts[cutnum]->numpages-1)
scenenum = INT32_MAX;
}
}
else
{
if (cutnum != oldcutnum)
scenenum = 0;
else if (scenenum + 1 < MAX_PAGES && scenenum < textprompts[cutnum]->numpages-1)
scenenum++;
else
scenenum = INT32_MAX;
}
// close the prompt if either num is invalid
if (cutnum == INT32_MAX || scenenum == INT32_MAX)
F_EndTextPrompt(false, false);
else
{
// on page mode, number of tics before allowing boost
// on timer mode, number of tics until page advances
timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10;
F_PreparePageText(textprompts[cutnum]->page[scenenum].text);
// gfx
picnum = textprompts[cutnum]->page[scenenum].pictostart;
numpics = textprompts[cutnum]->page[scenenum].numpics;
picmode = textprompts[cutnum]->page[scenenum].picmode;
pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0;
picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum];
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
// music change
if (textprompts[cutnum]->page[scenenum].musswitch[0])
S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch,
textprompts[cutnum]->page[scenenum].musswitchflags,
textprompts[cutnum]->page[scenenum].musicloop);
}
}
void F_EndTextPrompt(boolean forceexec, boolean noexec)
{
boolean promptwasactive = promptactive;
promptactive = false;
callpromptnum = callpagenum = callplayer = INT32_MAX;
if (promptwasactive)
{
if (promptmo && promptmo->player && promptblockcontrols)
promptmo->reactiontime = TICRATE/4; // prevent jumping right away // \todo account freeze realtime for this)
// \todo reset frozen realtime?
}
// \todo net safety, maybe loop all player thinkers?
if ((promptwasactive || forceexec) && !noexec && promptpostexectag)
{
if (tmthing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail
P_LinedefExecute(promptpostexectag, promptmo, NULL);
else
{
P_MapStart();
P_LinedefExecute(promptpostexectag, promptmo, NULL);
P_MapEnd();
}
}
}
void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime)
{
INT32 i;
// if splitscreen and we already have a prompt active, ignore.
// \todo Proper per-player splitscreen support (individual prompts)
if (promptactive && splitscreen && promptnum == callpromptnum && pagenum == callpagenum)
return;
// \todo proper netgame support
if (netgame)
{
F_EndTextPrompt(true, false); // run the post-effects immediately
return;
}
// We share vars, so no starting text prompts over cutscenes or title screens!
keypressed = false;
finalecount = 0;
timetonext = 0;
animtimer = 0;
stoptimer = 0;
skullAnimCounter = 0;
// Set up state
promptmo = mo;
promptpostexectag = postexectag;
promptblockcontrols = blockcontrols;
(void)freezerealtime; // \todo freeze player->realtime, maybe this needs to cycle through player thinkers
// Initialize current prompt and scene
callpromptnum = promptnum;
callpagenum = pagenum;
cutnum = (promptnum < MAX_PROMPTS && textprompts[promptnum]) ? promptnum : INT32_MAX;
scenenum = (cutnum != INT32_MAX && pagenum < MAX_PAGES && pagenum <= textprompts[cutnum]->numpages-1) ? pagenum : INT32_MAX;
promptactive = (cutnum != INT32_MAX && scenenum != INT32_MAX);
if (promptactive)
{
// on page mode, number of tics before allowing boost
// on timer mode, number of tics until page advances
timetonext = textprompts[cutnum]->page[scenenum].timetonext ? textprompts[cutnum]->page[scenenum].timetonext : TICRATE/10;
F_PreparePageText(textprompts[cutnum]->page[scenenum].text);
// gfx
picnum = textprompts[cutnum]->page[scenenum].pictostart;
numpics = textprompts[cutnum]->page[scenenum].numpics;
picmode = textprompts[cutnum]->page[scenenum].picmode;
pictoloop = textprompts[cutnum]->page[scenenum].pictoloop > 0 ? textprompts[cutnum]->page[scenenum].pictoloop - 1 : 0;
picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum];
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
animtimer = pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
// music change
if (textprompts[cutnum]->page[scenenum].musswitch[0])
S_ChangeMusic(textprompts[cutnum]->page[scenenum].musswitch,
textprompts[cutnum]->page[scenenum].musswitchflags,
textprompts[cutnum]->page[scenenum].musicloop);
// get the calling player
if (promptblockcontrols && mo && mo->player)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (players[i].mo == mo)
{
callplayer = i;
break;
}
}
}
}
else
F_EndTextPrompt(true, false); // run the post-effects immediately
}
static boolean F_GetTextPromptTutorialTag(char *tag, INT32 length)
{
INT32 gcs = gcs_custom;
boolean suffixed = true;
if (!tag || !tag[0] || !tutorialmode)
return false;
if (!strncmp(tag, "TAM", 3)) // Movement
gcs = G_GetControlScheme(gamecontrol, gcl_movement, num_gcl_movement);
else if (!strncmp(tag, "TAC", 3)) // Camera
{
// Check for gcl_movement so we can differentiate between FPS and Platform schemes.
gcs = G_GetControlScheme(gamecontrol, gcl_movement, num_gcl_movement);
if (gcs == gcs_custom) // try again, maybe we'll get a match
gcs = G_GetControlScheme(gamecontrol, gcl_camera, num_gcl_camera);
if (gcs == gcs_fps && !cv_usemouse.value)
gcs = gcs_platform; // Platform (arrow) scheme is stand-in for no mouse
}
else if (!strncmp(tag, "TAD", 3)) // Movement and Camera
gcs = G_GetControlScheme(gamecontrol, gcl_movement_camera, num_gcl_movement_camera);
else if (!strncmp(tag, "TAJ", 3)) // Jump
gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
else if (!strncmp(tag, "TAS", 3)) // Spin
gcs = G_GetControlScheme(gamecontrol, gcl_use, num_gcl_use);
else if (!strncmp(tag, "TAA", 3)) // Char ability
gcs = G_GetControlScheme(gamecontrol, gcl_jump, num_gcl_jump);
else if (!strncmp(tag, "TAW", 3)) // Shield ability
gcs = G_GetControlScheme(gamecontrol, gcl_jump_use, num_gcl_jump_use);
else
gcs = G_GetControlScheme(gamecontrol, gcl_tutorial_used, num_gcl_tutorial_used);
switch (gcs)
{
case gcs_fps:
// strncat(tag, "FPS", length);
suffixed = false;
break;
case gcs_platform:
strncat(tag, "PLATFORM", length);
break;
default:
strncat(tag, "CUSTOM", length);
break;
}
return suffixed;
}
void F_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum)
{
INT32 nosuffixpromptnum = INT32_MAX, nosuffixpagenum = INT32_MAX;
INT32 tutorialpromptnum = (tutorialmode) ? TUTORIAL_PROMPT-1 : 0;
boolean suffixed = false, found = false;
char suffixedtag[33];
*promptnum = *pagenum = INT32_MAX;
if (!tag || !tag[0])
return;
strncpy(suffixedtag, tag, 33);
suffixedtag[32] = 0;
if (tutorialmode)
suffixed = F_GetTextPromptTutorialTag(suffixedtag, 33);
for (*promptnum = 0 + tutorialpromptnum; *promptnum < MAX_PROMPTS; (*promptnum)++)
{
if (!textprompts[*promptnum])
continue;
for (*pagenum = 0; *pagenum < textprompts[*promptnum]->numpages && *pagenum < MAX_PAGES; (*pagenum)++)
{
if (suffixed && fastcmp(suffixedtag, textprompts[*promptnum]->page[*pagenum].tag))
{
// this goes first because fastcmp ends early if first string is shorter
found = true;
break;
}
else if (nosuffixpromptnum == INT32_MAX && nosuffixpagenum == INT32_MAX && fastcmp(tag, textprompts[*promptnum]->page[*pagenum].tag))
{
if (suffixed)
{
nosuffixpromptnum = *promptnum;
nosuffixpagenum = *pagenum;
// continue searching for the suffixed tag
}
else
{
found = true;
break;
}
}
}
if (found)
break;
}
if (suffixed && !found && nosuffixpromptnum != INT32_MAX && nosuffixpagenum != INT32_MAX)
{
found = true;
*promptnum = nosuffixpromptnum;
*pagenum = nosuffixpagenum;
}
if (!found)
CONS_Debug(DBG_GAMELOGIC, "Text prompt: Can't find a page with named tag %s or suffixed tag %s\n", tag, suffixedtag);
}
void F_TextPromptDrawer(void)
{
// reuse:
// cutnum -> promptnum
// scenenum -> pagenum
lumpnum_t iconlump;
UINT8 pagelines;
boolean rightside;
INT32 boxh, texth, texty, namey, chevrony;
INT32 textx, textr;
// Data
patch_t *patch;
if (!promptactive)
return;
iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname);
F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr);
// Draw gfx first
if (picnum >= 0 && picnum < numpics && textprompts[cutnum]->page[scenenum].picname[picnum][0] != '\0')
{
if (textprompts[cutnum]->page[scenenum].pichires[picnum])
V_DrawSmallScaledPatch(picxpos, picypos, 0,
W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_CACHE));
else
V_DrawScaledPatch(picxpos,picypos, 0,
W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_CACHE));
}
// Draw background
V_DrawPromptBack(boxh, textprompts[cutnum]->page[scenenum].backcolor);
// Draw narrator icon
if (iconlump != LUMPERROR)
{
INT32 iconx, icony, scale, scaledsize;
patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_CACHE);
// scale and center
if (patch->width > patch->height)
{
scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->width);
scaledsize = FixedMul(patch->height, scale);
iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS;
icony = ((namey-4) << FRACBITS) + FixedDiv(BASEVIDHEIGHT - namey + 4 - scaledsize, 2); // account for 4 margin
}
else if (patch->height > patch->width)
{
scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->height);
scaledsize = FixedMul(patch->width, scale);
iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS;
icony = namey << FRACBITS;
iconx += FixedDiv(FixedMul(patch->height, scale) - scaledsize, 2);
}
else
{
scale = FixedDiv(((boxh * 4) + (boxh/2)*4) - 4, patch->width);
iconx = (rightside ? BASEVIDWIDTH - (((boxh * 4) + (boxh/2)*4)) : 4) << FRACBITS;
icony = namey << FRACBITS;
}
if (textprompts[cutnum]->page[scenenum].iconflip)
iconx += FixedMul(patch->width, scale) << FRACBITS;
V_DrawFixedPatch(iconx, icony, scale, (V_SNAPTOBOTTOM|(textprompts[cutnum]->page[scenenum].iconflip ? V_FLIP : 0)), patch, NULL);
W_UnlockCachedPatch(patch);
}
// Draw text
V_DrawString(textx, texty, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), cutscene_disptext);
// Draw name
// Don't use V_YELLOWMAP here so that the name color can be changed with control codes
if (textprompts[cutnum]->page[scenenum].name[0])
V_DrawString(textx, namey, (V_SNAPTOBOTTOM|V_ALLOWLOWERCASE), textprompts[cutnum]->page[scenenum].name);
// Draw chevron
if (promptblockcontrols && !timetonext)
V_DrawString(textr-8, chevrony + (skullAnimCounter/5), (V_SNAPTOBOTTOM|V_YELLOWMAP), "\x1B"); // down arrow
}
void F_TextPromptTicker(void)
{
INT32 i;
if (!promptactive || paused || P_AutoPause())
return;
// advance animation
finalecount++;
cutscene_boostspeed = 0;
// for the chevron
if (--skullAnimCounter <= 0)
skullAnimCounter = 8;
// button handling
if (textprompts[cutnum]->page[scenenum].timetonext)
{
if (promptblockcontrols) // same procedure as below, just without the button handling
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (netgame && i != serverplayer && i != adminplayer)
continue;
else if (splitscreen) {
// Both players' controls are locked,
// But only consoleplayer can advance the prompt.
// \todo Proper per-player splitscreen support (individual prompts)
if (i == consoleplayer || i == secondarydisplayplayer)
players[i].powers[pw_nocontrol] = 1;
}
else if (i == consoleplayer)
players[i].powers[pw_nocontrol] = 1;
if (!splitscreen)
break;
}
}
if (timetonext >= 1)
timetonext--;
if (!timetonext)
F_AdvanceToNextPage();
F_WriteText();
}
else
{
if (promptblockcontrols)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (netgame && i != serverplayer && i != adminplayer)
continue;
else if (splitscreen) {
// Both players' controls are locked,
// But only the triggering player can advance the prompt.
if (i == consoleplayer || i == secondarydisplayplayer)
{
players[i].powers[pw_nocontrol] = 1;
if (callplayer == consoleplayer || callplayer == secondarydisplayplayer)
{
if (i != callplayer)
continue;
}
else if (i != consoleplayer)
continue;
}
else
continue;
}
else if (i == consoleplayer)
players[i].powers[pw_nocontrol] = 1;
else
continue;
if ((players[i].cmd.buttons & BT_USE) || (players[i].cmd.buttons & BT_JUMP))
{
if (timetonext > 1)
timetonext--;
else if (cutscene_baseptr) // don't set boost if we just reset the string
cutscene_boostspeed = 1; // only after a slight delay
if (keypressed)
{
if (!splitscreen)
break;
else
continue;
}
if (!timetonext) // is 0 when finished generating text
{
F_AdvanceToNextPage();
if (promptactive)
S_StartSound(NULL, sfx_menu1);
}
keypressed = true; // prevent repeat events
}
else if (!(players[i].cmd.buttons & BT_USE) && !(players[i].cmd.buttons & BT_JUMP))
keypressed = false;
if (!splitscreen)
break;
}
}
// generate letter-by-letter text
if (scenenum >= MAX_PAGES ||
!textprompts[cutnum]->page[scenenum].text ||
!textprompts[cutnum]->page[scenenum].text[0] ||
!F_WriteText())
timetonext = !promptblockcontrols; // never show the chevron if we can't toggle pages
}
// gfx
if (picnum >= 0 && picnum < numpics)
{
if (animtimer <= 0)
{
boolean persistanimtimer = false;
if (picnum < numpics-1 && textprompts[cutnum]->page[scenenum].picname[picnum+1][0] != '\0')
picnum++;
else if (picmode == PROMPT_PIC_LOOP)
picnum = pictoloop;
else if (picmode == PROMPT_PIC_DESTROY)
picnum = -1;
else // if (picmode == PROMPT_PIC_PERSIST)
persistanimtimer = true;
if (!persistanimtimer && picnum >= 0)
{
picxpos = textprompts[cutnum]->page[scenenum].xcoord[picnum];
picypos = textprompts[cutnum]->page[scenenum].ycoord[picnum];
pictime = textprompts[cutnum]->page[scenenum].picduration[picnum];
animtimer = pictime;
}
}
else
animtimer--;
}
}

View file

@ -17,6 +17,7 @@
#include "doomtype.h" #include "doomtype.h"
#include "d_event.h" #include "d_event.h"
#include "p_mobj.h"
// //
// FINALE // FINALE
@ -33,9 +34,10 @@ void F_IntroTicker(void);
void F_TitleScreenTicker(boolean run); void F_TitleScreenTicker(boolean run);
void F_CutsceneTicker(void); void F_CutsceneTicker(void);
void F_TitleDemoTicker(void); void F_TitleDemoTicker(void);
void F_TextPromptTicker(void);
// Called by main loop. // Called by main loop.
FUNCMATH void F_GameEndDrawer(void); void F_GameEndDrawer(void);
void F_IntroDrawer(void); void F_IntroDrawer(void);
void F_TitleScreenDrawer(void); void F_TitleScreenDrawer(void);
@ -50,6 +52,13 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
void F_CutsceneDrawer(void); void F_CutsceneDrawer(void);
void F_EndCutScene(void); void F_EndCutScene(void);
void F_StartTextPrompt(INT32 promptnum, INT32 pagenum, mobj_t *mo, UINT16 postexectag, boolean blockcontrols, boolean freezerealtime);
void F_GetPromptPageByNamedTag(const char *tag, INT32 *promptnum, INT32 *pagenum);
void F_TextPromptDrawer(void);
void F_EndTextPrompt(boolean forceexec, boolean noexec);
boolean F_GetPromptHideHudAll(void);
boolean F_GetPromptHideHud(fixed_t y);
void F_StartGameEnd(void); void F_StartGameEnd(void);
void F_StartIntro(void); void F_StartIntro(void);
void F_StartTitleScreen(void); void F_StartTitleScreen(void);

View file

@ -128,6 +128,14 @@ 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
INT16 tutorialmap = 0; // map to load for tutorial
boolean tutorialmode = false; // are we in a tutorial right now?
INT32 tutorialgcs = gcs_custom; // which control scheme is loaded?
INT32 tutorialusemouse = 0; // store cv_usemouse user value
INT32 tutorialfreelook = 0; // store cv_alwaysfreelook user value
INT32 tutorialmousemove = 0; // store cv_mousemove user value
INT32 tutorialanalog = 0; // store cv_analog user value
boolean looptitle = false; boolean looptitle = false;
UINT8 skincolor_redteam = SKINCOLOR_RED; UINT8 skincolor_redteam = SKINCOLOR_RED;
@ -139,6 +147,7 @@ tic_t countdowntimer = 0;
boolean countdowntimeup = false; boolean countdowntimeup = false;
cutscene_t *cutscenes[128]; cutscene_t *cutscenes[128];
textprompt_t *textprompts[MAX_PROMPTS];
INT16 nextmapoverride; INT16 nextmapoverride;
boolean skipstats; boolean skipstats;
@ -1934,6 +1943,7 @@ void G_Ticker(boolean run)
F_TitleDemoTicker(); F_TitleDemoTicker();
P_Ticker(run); // tic the game P_Ticker(run); // tic the game
ST_Ticker(); ST_Ticker();
F_TextPromptTicker();
AM_Ticker(); AM_Ticker();
HU_Ticker(); HU_Ticker();
break; break;

View file

@ -55,6 +55,7 @@ extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard di
extern INT16 rw_maximums[NUM_WEAPONS]; extern INT16 rw_maximums[NUM_WEAPONS];
// used in game menu // used in game menu
extern consvar_t cv_tutorialprompt;
extern consvar_t cv_crosshair, cv_crosshair2; extern consvar_t cv_crosshair, cv_crosshair2;
extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_mousemove; extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_mousemove;
extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_mousemove2; extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_mousemove2;

View file

@ -45,6 +45,47 @@ UINT8 gamekeydown[NUMINPUTS];
// two key codes (or virtual key) per game control // two key codes (or virtual key) per game control
INT32 gamecontrol[num_gamecontrols][2]; INT32 gamecontrol[num_gamecontrols][2];
INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player
INT32 gamecontroldefault[num_gamecontrolschemes][num_gamecontrols][2]; // default control storage, use 0 (gcs_custom) for memory retention
// lists of GC codes for selective operation
const INT32 gcl_tutorial_check[num_gcl_tutorial_check] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight,
gc_turnleft, gc_turnright
};
const INT32 gcl_tutorial_used[num_gcl_tutorial_used] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight,
gc_turnleft, gc_turnright,
gc_jump, gc_use
};
const INT32 gcl_tutorial_full[num_gcl_tutorial_full] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight,
gc_lookup, gc_lookdown, gc_turnleft, gc_turnright, gc_centerview,
gc_jump, gc_use,
gc_fire, gc_firenormal
};
const INT32 gcl_movement[num_gcl_movement] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight
};
const INT32 gcl_camera[num_gcl_camera] = {
gc_turnleft, gc_turnright
};
const INT32 gcl_movement_camera[num_gcl_movement_camera] = {
gc_forward, gc_backward, gc_strafeleft, gc_straferight,
gc_turnleft, gc_turnright
};
const INT32 gcl_jump[num_gcl_jump] = { gc_jump };
const INT32 gcl_use[num_gcl_use] = { gc_use };
const INT32 gcl_jump_use[num_gcl_jump_use] = {
gc_jump, gc_use
};
typedef struct typedef struct
{ {
@ -611,55 +652,117 @@ INT32 G_KeyStringtoNum(const char *keystr)
return 0; return 0;
} }
void G_Controldefault(void) void G_DefineDefaultControls(void)
{ {
gamecontrol[gc_forward ][0] = 'w'; INT32 i;
gamecontrol[gc_backward ][0] = 's';
gamecontrol[gc_strafeleft ][0] = 'a'; // FPS game controls (WASD)
gamecontrol[gc_straferight][0] = 'd'; gamecontroldefault[gcs_fps][gc_forward ][0] = 'w';
gamecontrol[gc_turnleft ][0] = KEY_LEFTARROW; gamecontroldefault[gcs_fps][gc_backward ][0] = 's';
gamecontrol[gc_turnright ][0] = KEY_RIGHTARROW; gamecontroldefault[gcs_fps][gc_strafeleft ][0] = 'a';
gamecontrol[gc_weaponnext ][0] = 'e'; gamecontroldefault[gcs_fps][gc_straferight][0] = 'd';
gamecontrol[gc_weaponprev ][0] = 'q'; gamecontroldefault[gcs_fps][gc_lookup ][0] = KEY_UPARROW;
gamecontrol[gc_wepslot1 ][0] = '1'; gamecontroldefault[gcs_fps][gc_lookdown ][0] = KEY_DOWNARROW;
gamecontrol[gc_wepslot2 ][0] = '2'; gamecontroldefault[gcs_fps][gc_turnleft ][0] = KEY_LEFTARROW;
gamecontrol[gc_wepslot3 ][0] = '3'; gamecontroldefault[gcs_fps][gc_turnright ][0] = KEY_RIGHTARROW;
gamecontrol[gc_wepslot4 ][0] = '4'; gamecontroldefault[gcs_fps][gc_centerview ][0] = KEY_END;
gamecontrol[gc_wepslot5 ][0] = '5'; gamecontroldefault[gcs_fps][gc_jump ][0] = KEY_SPACE;
gamecontrol[gc_wepslot6 ][0] = '6'; gamecontroldefault[gcs_fps][gc_use ][0] = KEY_LSHIFT;
gamecontrol[gc_wepslot7 ][0] = '7'; gamecontroldefault[gcs_fps][gc_fire ][0] = KEY_RCTRL;
gamecontrol[gc_wepslot8 ][0] = '8'; gamecontroldefault[gcs_fps][gc_fire ][1] = KEY_MOUSE1+0;
gamecontrol[gc_wepslot9 ][0] = '9'; gamecontroldefault[gcs_fps][gc_firenormal ][0] = 'c';
gamecontrol[gc_wepslot10 ][0] = '0';
gamecontrol[gc_fire ][0] = KEY_RCTRL; // Platform game controls (arrow keys)
gamecontrol[gc_fire ][1] = KEY_MOUSE1+0; gamecontroldefault[gcs_platform][gc_forward ][0] = KEY_UPARROW;
gamecontrol[gc_firenormal ][0] = 'c'; gamecontroldefault[gcs_platform][gc_backward ][0] = KEY_DOWNARROW;
gamecontrol[gc_tossflag ][0] = '\''; gamecontroldefault[gcs_platform][gc_strafeleft ][0] = 'a';
gamecontrol[gc_use ][0] = KEY_LSHIFT; gamecontroldefault[gcs_platform][gc_straferight][0] = 'd';
gamecontrol[gc_camtoggle ][0] = 'v'; gamecontroldefault[gcs_platform][gc_lookup ][0] = KEY_PGUP;
gamecontrol[gc_camreset ][0] = 'r'; gamecontroldefault[gcs_platform][gc_lookdown ][0] = KEY_PGDN;
gamecontrol[gc_lookup ][0] = KEY_UPARROW; gamecontroldefault[gcs_platform][gc_turnleft ][0] = KEY_LEFTARROW;
gamecontrol[gc_lookdown ][0] = KEY_DOWNARROW; gamecontroldefault[gcs_platform][gc_turnright ][0] = KEY_RIGHTARROW;
gamecontrol[gc_centerview ][0] = KEY_END; gamecontroldefault[gcs_platform][gc_centerview ][0] = KEY_END;
gamecontrol[gc_talkkey ][0] = 't'; gamecontroldefault[gcs_platform][gc_jump ][0] = KEY_SPACE;
gamecontrol[gc_teamkey ][0] = 'y'; gamecontroldefault[gcs_platform][gc_use ][0] = KEY_LSHIFT;
gamecontrol[gc_scores ][0] = KEY_TAB; gamecontroldefault[gcs_platform][gc_fire ][0] = 's';
gamecontrol[gc_jump ][0] = KEY_SPACE; gamecontroldefault[gcs_platform][gc_fire ][1] = KEY_MOUSE1+0;
gamecontrol[gc_console ][0] = KEY_CONSOLE; gamecontroldefault[gcs_platform][gc_firenormal ][0] = 'w';
gamecontrol[gc_pause ][0] = KEY_PAUSE;
for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0)
{
gamecontroldefault[i][gc_weaponnext ][0] = 'e';
gamecontroldefault[i][gc_weaponprev ][0] = 'q';
gamecontroldefault[i][gc_wepslot1 ][0] = '1';
gamecontroldefault[i][gc_wepslot2 ][0] = '2';
gamecontroldefault[i][gc_wepslot3 ][0] = '3';
gamecontroldefault[i][gc_wepslot4 ][0] = '4';
gamecontroldefault[i][gc_wepslot5 ][0] = '5';
gamecontroldefault[i][gc_wepslot6 ][0] = '6';
gamecontroldefault[i][gc_wepslot7 ][0] = '7';
gamecontroldefault[i][gc_wepslot8 ][0] = '8';
gamecontroldefault[i][gc_wepslot9 ][0] = '9';
gamecontroldefault[i][gc_wepslot10 ][0] = '0';
gamecontroldefault[i][gc_tossflag ][0] = '\'';
gamecontroldefault[i][gc_camtoggle ][0] = 'v';
gamecontroldefault[i][gc_camreset ][0] = 'r';
gamecontroldefault[i][gc_talkkey ][0] = 't';
gamecontroldefault[i][gc_teamkey ][0] = 'y';
gamecontroldefault[i][gc_scores ][0] = KEY_TAB;
gamecontroldefault[i][gc_console ][0] = KEY_CONSOLE;
gamecontroldefault[i][gc_pause ][0] = KEY_PAUSE;
}
} }
void G_SaveKeySetting(FILE *f) INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen)
{
INT32 i, j, gc;
boolean skipscheme;
for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0)
{
skipscheme = false;
for (j = 0; j < (gclist && gclen ? gclen : num_gamecontrols); j++)
{
gc = (gclist && gclen) ? gclist[j] : j;
if (((fromcontrols[gc][0] && gamecontroldefault[i][gc][0]) ? fromcontrols[gc][0] != gamecontroldefault[i][gc][0] : true) &&
((fromcontrols[gc][0] && gamecontroldefault[i][gc][1]) ? fromcontrols[gc][0] != gamecontroldefault[i][gc][1] : true) &&
((fromcontrols[gc][1] && gamecontroldefault[i][gc][0]) ? fromcontrols[gc][1] != gamecontroldefault[i][gc][0] : true) &&
((fromcontrols[gc][1] && gamecontroldefault[i][gc][1]) ? fromcontrols[gc][1] != gamecontroldefault[i][gc][1] : true))
{
skipscheme = true;
break;
}
}
if (!skipscheme)
return i;
}
return gcs_custom;
}
void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen)
{
INT32 i, gc;
for (i = 0; i < (gclist && gclen ? gclen : num_gamecontrols); i++)
{
gc = (gclist && gclen) ? gclist[i] : i;
setupcontrols[gc][0] = fromcontrols[gc][0];
setupcontrols[gc][1] = fromcontrols[gc][1];
}
}
void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis)[2])
{ {
INT32 i; INT32 i;
for (i = 1; i < num_gamecontrols; i++) for (i = 1; i < num_gamecontrols; i++)
{ {
fprintf(f, "setcontrol \"%s\" \"%s\"", gamecontrolname[i], fprintf(f, "setcontrol \"%s\" \"%s\"", gamecontrolname[i],
G_KeynumToString(gamecontrol[i][0])); G_KeynumToString(fromcontrols[i][0]));
if (gamecontrol[i][1]) if (fromcontrols[i][1])
fprintf(f, " \"%s\"\n", G_KeynumToString(gamecontrol[i][1])); fprintf(f, " \"%s\"\n", G_KeynumToString(fromcontrols[i][1]));
else else
fprintf(f, "\n"); fprintf(f, "\n");
} }
@ -667,10 +770,10 @@ void G_SaveKeySetting(FILE *f)
for (i = 1; i < num_gamecontrols; i++) for (i = 1; i < num_gamecontrols; i++)
{ {
fprintf(f, "setcontrol2 \"%s\" \"%s\"", gamecontrolname[i], fprintf(f, "setcontrol2 \"%s\" \"%s\"", gamecontrolname[i],
G_KeynumToString(gamecontrolbis[i][0])); G_KeynumToString(fromcontrolsbis[i][0]));
if (gamecontrolbis[i][1]) if (fromcontrolsbis[i][1])
fprintf(f, " \"%s\"\n", G_KeynumToString(gamecontrolbis[i][1])); fprintf(f, " \"%s\"\n", G_KeynumToString(fromcontrolsbis[i][1]));
else else
fprintf(f, "\n"); fprintf(f, "\n");
} }

View file

@ -99,6 +99,14 @@ typedef enum
num_gamecontrols num_gamecontrols
} gamecontrols_e; } gamecontrols_e;
typedef enum
{
gcs_custom,
gcs_fps,
gcs_platform,
num_gamecontrolschemes
} gamecontrolschemes_e;
// mouse values are used once // mouse values are used once
extern consvar_t cv_mousesens, cv_mouseysens; extern consvar_t cv_mousesens, cv_mouseysens;
extern consvar_t cv_mousesens2, cv_mouseysens2; extern consvar_t cv_mousesens2, cv_mouseysens2;
@ -116,9 +124,30 @@ extern UINT8 gamekeydown[NUMINPUTS];
// two key codes (or virtual key) per game control // two key codes (or virtual key) per game control
extern INT32 gamecontrol[num_gamecontrols][2]; extern INT32 gamecontrol[num_gamecontrols][2];
extern INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player extern INT32 gamecontrolbis[num_gamecontrols][2]; // secondary splitscreen player
extern INT32 gamecontroldefault[num_gamecontrolschemes][num_gamecontrols][2]; // default control storage, use 0 (gcs_custom) for memory retention
#define PLAYER1INPUTDOWN(gc) (gamekeydown[gamecontrol[gc][0]] || gamekeydown[gamecontrol[gc][1]]) #define PLAYER1INPUTDOWN(gc) (gamekeydown[gamecontrol[gc][0]] || gamekeydown[gamecontrol[gc][1]])
#define PLAYER2INPUTDOWN(gc) (gamekeydown[gamecontrolbis[gc][0]] || gamekeydown[gamecontrolbis[gc][1]]) #define PLAYER2INPUTDOWN(gc) (gamekeydown[gamecontrolbis[gc][0]] || gamekeydown[gamecontrolbis[gc][1]])
#define num_gcl_tutorial_check 6
#define num_gcl_tutorial_used 8
#define num_gcl_tutorial_full 13
#define num_gcl_movement 4
#define num_gcl_camera 2
#define num_gcl_movement_camera 6
#define num_gcl_jump 1
#define num_gcl_use 1
#define num_gcl_jump_use 2
extern const INT32 gcl_tutorial_check[num_gcl_tutorial_check];
extern const INT32 gcl_tutorial_used[num_gcl_tutorial_used];
extern const INT32 gcl_tutorial_full[num_gcl_tutorial_full];
extern const INT32 gcl_movement[num_gcl_movement];
extern const INT32 gcl_camera[num_gcl_camera];
extern const INT32 gcl_movement_camera[num_gcl_movement_camera];
extern const INT32 gcl_jump[num_gcl_jump];
extern const INT32 gcl_use[num_gcl_use];
extern const INT32 gcl_jump_use[num_gcl_jump_use];
// peace to my little coder fingers! // peace to my little coder fingers!
// check a gamecontrol being active or not // check a gamecontrol being active or not
@ -133,8 +162,10 @@ INT32 G_KeyStringtoNum(const char *keystr);
void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control); void G_ClearControlKeys(INT32 (*setupcontrols)[2], INT32 control);
void Command_Setcontrol_f(void); void Command_Setcontrol_f(void);
void Command_Setcontrol2_f(void); void Command_Setcontrol2_f(void);
void G_Controldefault(void); void G_DefineDefaultControls(void);
void G_SaveKeySetting(FILE *f); INT32 G_GetControlScheme(INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen);
void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const INT32 *gclist, INT32 gclen);
void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis)[2]);
void G_CheckDoubleUsage(INT32 keynum); void G_CheckDoubleUsage(INT32 keynum);
#endif #endif

View file

@ -338,7 +338,7 @@ angle_t gld_FrustumAngle(void)
} }
// If the pitch is larger than this you can look all around at a FOV of 90 // If the pitch is larger than this you can look all around at a FOV of 90
if (aimingangle > (ANGLE_45+ANG1) && (ANGLE_315-ANG1) > aimingangle) if (abs((signed)aimingangle) > 46 * ANG1)
return 0xffffffff; return 0xffffffff;
// ok, this is a gross hack that barely works... // ok, this is a gross hack that barely works...

View file

@ -26,10 +26,6 @@
#include <windows.h> #include <windows.h>
#endif #endif
#if defined (VID_X11) && !defined (HAVE_SDL)
#include <GL/glx.h>
#endif
#include "../doomdef.h" #include "../doomdef.h"
//THIS MUST DISAPPEAR!!! //THIS MUST DISAPPEAR!!!
#include "hw_glide.h" #include "hw_glide.h"

View file

@ -114,10 +114,10 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option)
if (option & V_NOSCALESTART) if (option & V_NOSCALESTART)
sdupx = sdupy = 2.0f; sdupx = sdupy = 2.0f;
v[0].x = v[3].x = (x*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; v[0].x = v[3].x = (x*sdupx-SHORT(gpatch->leftoffset)*pdupx)/vid.width - 1;
v[2].x = v[1].x = (x*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; v[2].x = v[1].x = (x*sdupx+(SHORT(gpatch->width)-SHORT(gpatch->leftoffset))*pdupx)/vid.width - 1;
v[0].y = v[1].y = 1-(y*sdupy-gpatch->topoffset*pdupy)/vid.height; v[0].y = v[1].y = 1-(y*sdupy-SHORT(gpatch->topoffset)*pdupy)/vid.height;
v[2].y = v[3].y = 1-(y*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; v[2].y = v[3].y = 1-(y*sdupy+(SHORT(gpatch->height)-SHORT(gpatch->topoffset))*pdupy)/vid.height;
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
@ -183,18 +183,29 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
dupx = dupy = (dupx < dupy ? dupx : dupy); dupx = dupy = (dupx < dupy ? dupx : dupy);
fscalew = fscaleh = FIXED_TO_FLOAT(pscale); fscalew = fscaleh = FIXED_TO_FLOAT(pscale);
if (option & V_OFFSET) // See my comments in v_video.c's V_DrawFixedPatch
// -- Monster Iestyn 29/10/18
{ {
cx -= (float)gpatch->leftoffset * dupx * fscalew; float offsetx = 0.0f, offsety = 0.0f;
cy -= (float)gpatch->topoffset * dupy * fscaleh;
} // left offset
else
{
cy -= (float)gpatch->topoffset * fscaleh;
if (option & V_FLIP) if (option & V_FLIP)
cx -= ((float)gpatch->width - (float)gpatch->leftoffset) * fscalew; offsetx = (float)(SHORT(gpatch->width) - SHORT(gpatch->leftoffset)) * fscalew;
else else
cx -= (float)gpatch->leftoffset * fscalew; offsetx = (float)SHORT(gpatch->leftoffset) * fscalew;
// top offset
// TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!?
offsety = (float)SHORT(gpatch->topoffset) * fscaleh;
if ((option & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs
{
offsetx *= dupx;
offsety *= dupy;
}
cx -= offsetx;
cy -= offsety;
} }
if (splitscreen && (option & V_PERPLAYER)) if (splitscreen && (option & V_PERPLAYER))
@ -312,13 +323,13 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale,
if (pscale != FRACUNIT || (splitscreen && option & V_PERPLAYER)) if (pscale != FRACUNIT || (splitscreen && option & V_PERPLAYER))
{ {
fwidth = (float)gpatch->width * fscalew * dupx; fwidth = (float)SHORT(gpatch->width) * fscalew * dupx;
fheight = (float)gpatch->height * fscaleh * dupy; fheight = (float)SHORT(gpatch->height) * fscaleh * dupy;
} }
else else
{ {
fwidth = (float)gpatch->width * dupx; fwidth = (float)SHORT(gpatch->width) * dupx;
fheight = (float)gpatch->height * dupy; fheight = (float)SHORT(gpatch->height) * dupy;
} }
// positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1 // positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1
@ -418,8 +429,8 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
// fuck it, no GL support for croppedpatch v_perplayer right now. it's not like it's accessible to Lua or anything, and we only use it for menus... // fuck it, no GL support for croppedpatch v_perplayer right now. it's not like it's accessible to Lua or anything, and we only use it for menus...
cy -= (float)gpatch->topoffset * fscale; cy -= (float)SHORT(gpatch->topoffset) * fscale;
cx -= (float)gpatch->leftoffset * fscale; cx -= (float)SHORT(gpatch->leftoffset) * fscale;
if (!(option & V_NOSCALESTART)) if (!(option & V_NOSCALESTART))
{ {
@ -461,11 +472,11 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
fwidth = w; fwidth = w;
fheight = h; fheight = h;
if (fwidth > gpatch->width) if (fwidth > SHORT(gpatch->width))
fwidth = gpatch->width; fwidth = SHORT(gpatch->width);
if (fheight > gpatch->height) if (fheight > SHORT(gpatch->height))
fheight = gpatch->height; fheight = SHORT(gpatch->height);
if (pscale != FRACUNIT) if (pscale != FRACUNIT)
{ {
@ -495,17 +506,17 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
v[0].sow = v[3].sow = ((sx )/(float)gpatch->width )*gpatch->max_s; v[0].sow = v[3].sow = ((sx )/(float)SHORT(gpatch->width) )*gpatch->max_s;
if (sx + w > gpatch->width) if (sx + w > SHORT(gpatch->width))
v[2].sow = v[1].sow = gpatch->max_s; v[2].sow = v[1].sow = gpatch->max_s;
else else
v[2].sow = v[1].sow = ((sx+w)/(float)gpatch->width )*gpatch->max_s; v[2].sow = v[1].sow = ((sx+w)/(float)SHORT(gpatch->width) )*gpatch->max_s;
v[0].tow = v[1].tow = ((sy )/(float)gpatch->height)*gpatch->max_t; v[0].tow = v[1].tow = ((sy )/(float)SHORT(gpatch->height))*gpatch->max_t;
if (sy + h > gpatch->height) if (sy + h > SHORT(gpatch->height))
v[2].tow = v[3].tow = gpatch->max_t; v[2].tow = v[3].tow = gpatch->max_t;
else else
v[2].tow = v[3].tow = ((sy+h)/(float)gpatch->height)*gpatch->max_t; v[2].tow = v[3].tow = ((sy+h)/(float)SHORT(gpatch->height))*gpatch->max_t;
flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest; flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest;
@ -705,6 +716,32 @@ void HWR_DrawConsoleBack(UINT32 color, INT32 height)
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
} }
// Very similar to HWR_DrawConsoleBack, except we draw from the middle(-ish) of the screen to the bottom.
void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight)
{
FOutVector v[4];
FSurfaceInfo Surf;
INT32 height = (boxheight * 4) + (boxheight/2)*5; // 4 lines of space plus gaps between and some leeway
// setup some neat-o translucency effect
v[0].x = v[3].x = -1.0f;
v[2].x = v[1].x = 1.0f;
v[0].y = v[1].y = -1.0f;
v[2].y = v[3].y = -1.0f+((height<<1)/(float)vid.height);
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
v[0].sow = v[3].sow = 0.0f;
v[2].sow = v[1].sow = 1.0f;
v[0].tow = v[1].tow = 1.0f;
v[2].tow = v[3].tow = 0.0f;
Surf.FlatColor.rgba = UINT2RGBA(color);
Surf.FlatColor.s.alpha = (color == 0 ? 0xC0 : 0x80); // make black darker, like software
HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest);
}
// ========================================================================== // ==========================================================================
// R_DRAW.C STUFF // R_DRAW.C STUFF

View file

@ -32,10 +32,6 @@
// STANDARD DLL EXPORTS // STANDARD DLL EXPORTS
// ========================================================================== // ==========================================================================
#ifdef HAVE_SDL
#undef VID_X11
#endif
EXPORT boolean HWRAPI(Init) (I_Error_t ErrorFunction); EXPORT boolean HWRAPI(Init) (I_Error_t ErrorFunction);
#ifndef HAVE_SDL #ifndef HAVE_SDL
EXPORT void HWRAPI(Shutdown) (void); EXPORT void HWRAPI(Shutdown) (void);
@ -43,9 +39,6 @@ EXPORT void HWRAPI(Shutdown) (void);
#ifdef _WINDOWS #ifdef _WINDOWS
EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes); EXPORT void HWRAPI(GetModeList) (vmode_t **pvidmodes, INT32 *numvidmodes);
#endif #endif
#ifdef VID_X11
EXPORT Window HWRAPI(HookXwin) (Display *, INT32, INT32, boolean);
#endif
#if defined (PURESDL) || defined (macintosh) #if defined (PURESDL) || defined (macintosh)
EXPORT void HWRAPI(SetPalette) (INT32 *, RGBA_t *gamma); EXPORT void HWRAPI(SetPalette) (INT32 *, RGBA_t *gamma);
#else #else
@ -71,10 +64,6 @@ EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void); EXPORT INT32 HWRAPI(GetTextureUsed) (void);
EXPORT INT32 HWRAPI(GetRenderVersion) (void); EXPORT INT32 HWRAPI(GetRenderVersion) (void);
#ifdef VID_X11 // ifdef to be removed as soon as windoze supports that as well
// metzgermeister: added for Voodoo detection
EXPORT char *HWRAPI(GetRenderer) (void);
#endif
#ifdef SHUFFLE #ifdef SHUFFLE
#define SCREENVERTS 10 #define SCREENVERTS 10
EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]);
@ -115,10 +104,6 @@ struct hwdriver_s
#ifdef _WINDOWS #ifdef _WINDOWS
GetModeList pfnGetModeList; GetModeList pfnGetModeList;
#endif #endif
#ifdef VID_X11
HookXwin pfnHookXwin;
GetRenderer pfnGetRenderer;
#endif
#ifndef HAVE_SDL #ifndef HAVE_SDL
Shutdown pfnShutdown; Shutdown pfnShutdown;
#endif #endif

View file

@ -2116,6 +2116,10 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
else else
{ {
fixed_t texturevpeg; fixed_t texturevpeg;
boolean attachtobottom = false;
#ifdef ESLOPE
boolean slopeskew = false; // skew FOF walls with slopes?
#endif
// Wow, how was this missing from OpenGL for so long? // Wow, how was this missing from OpenGL for so long?
// ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software // ...Oh well, anyway, Lower Unpegged now changes pegging of FOFs like in software
@ -2123,24 +2127,50 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
if (newline) if (newline)
{ {
texturevpeg = sides[newline->sidenum[0]].rowoffset; texturevpeg = sides[newline->sidenum[0]].rowoffset;
if (newline->flags & ML_DONTPEGBOTTOM) attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM);
texturevpeg -= *rover->topheight - *rover->bottomheight; #ifdef ESLOPE
slopeskew = !!(newline->flags & ML_DONTPEGTOP);
#endif
} }
else else
{ {
texturevpeg = sides[rover->master->sidenum[0]].rowoffset; texturevpeg = sides[rover->master->sidenum[0]].rowoffset;
if (gr_linedef->flags & ML_DONTPEGBOTTOM) attachtobottom = !!(gr_linedef->flags & ML_DONTPEGBOTTOM);
texturevpeg -= *rover->topheight - *rover->bottomheight; #ifdef ESLOPE
slopeskew = !!(rover->master->flags & ML_DONTPEGTOP);
#endif
} }
grTex = HWR_GetTexture(texnum); grTex = HWR_GetTexture(texnum);
#ifdef ESLOPE #ifdef ESLOPE
wallVerts[3].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; if (!slopeskew) // no skewing
wallVerts[2].t = (*rover->topheight - hS + texturevpeg) * grTex->scaleY; {
wallVerts[0].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; if (attachtobottom)
wallVerts[1].t = (*rover->topheight - lS + texturevpeg) * grTex->scaleY; texturevpeg -= *rover->topheight - *rover->bottomheight;
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
{
if (!attachtobottom) // skew by top
{
wallVerts[3].t = wallVerts[2].t = texturevpeg * grTex->scaleY;
wallVerts[0].t = (h - l + texturevpeg) * grTex->scaleY;
wallVerts[1].t = (hS - lS + texturevpeg) * grTex->scaleY;
}
else // skew by bottom
{
wallVerts[0].t = wallVerts[1].t = texturevpeg * grTex->scaleY;
wallVerts[3].t = wallVerts[0].t - (h - l) * grTex->scaleY;
wallVerts[2].t = wallVerts[1].t - (hS - lS) * grTex->scaleY;
}
}
#else #else
if (attachtobottom)
texturevpeg -= *rover->topheight - *rover->bottomheight;
wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY; wallVerts[3].t = wallVerts[2].t = (*rover->topheight - h + texturevpeg) * grTex->scaleY;
wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY; wallVerts[0].t = wallVerts[1].t = (*rover->topheight - l + texturevpeg) * grTex->scaleY;
#endif #endif
@ -5270,8 +5300,10 @@ static void HWR_AddSprites(sector_t *sec)
approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
if (approx_dist <= limit_dist) if (approx_dist > limit_dist)
HWR_ProjectSprite(thing); continue;
HWR_ProjectSprite(thing);
} }
} }
else else
@ -5293,8 +5325,10 @@ static void HWR_AddSprites(sector_t *sec)
approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
if (approx_dist <= limit_dist) if (approx_dist > limit_dist)
HWR_ProjectPrecipitationSprite(precipthing); continue;
HWR_ProjectPrecipitationSprite(precipthing);
} }
} }
else else
@ -5624,6 +5658,16 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
x1 = tr_x + x1 * rightcos; x1 = tr_x + x1 * rightcos;
x2 = tr_x - x2 * rightcos; x2 = tr_x - x2 * rightcos;
// okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok
if (!(thing->precipflags & PCF_THUNK))
{
if (thing->precipflags & PCF_RAIN)
P_RainThinker(thing);
else
P_SnowThinker(thing);
thing->precipflags |= PCF_THUNK;
}
// //
// store information in a vissprite // store information in a vissprite
// //

View file

@ -35,6 +35,7 @@ void HWR_clearAutomap(void);
void HWR_drawAMline(const fline_t *fl, INT32 color); void HWR_drawAMline(const fline_t *fl, INT32 color);
void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength); void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength);
void HWR_DrawConsoleBack(UINT32 color, INT32 height); void HWR_DrawConsoleBack(UINT32 color, INT32 height);
void HWR_DrawTutorialBack(UINT32 color, INT32 boxheight);
void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player); void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player);
void HWR_RenderPlayerView(INT32 viewnumber, player_t *player); void HWR_RenderPlayerView(INT32 viewnumber, player_t *player);
void HWR_DrawViewBorder(INT32 clearlines); void HWR_DrawViewBorder(INT32 clearlines);

View file

@ -29,6 +29,11 @@
// model version // model version
#define MD2_VERSION 8 #define MD2_VERSION 8
// magic number "IDP2" or 844121161
#define MD2_IDENT (INT32)(('2' << 24) + ('P' << 16) + ('D' << 8) + 'I')
// model version
#define MD2_VERSION 8
#define MD2_MAX_TRIANGLES 8192 #define MD2_MAX_TRIANGLES 8192
#define MD2_MAX_VERTICES 4096 #define MD2_MAX_VERTICES 4096
#define MD2_MAX_TEXCOORDS 4096 #define MD2_MAX_TEXCOORDS 4096

View file

@ -86,7 +86,7 @@ void HU_Init(void);
void HU_LoadGraphics(void); void HU_LoadGraphics(void);
// reset heads up when consoleplayer respawns. // reset heads up when consoleplayer respawns.
FUNCMATH void HU_Start(void); void HU_Start(void);
boolean HU_Responder(event_t *ev); boolean HU_Responder(event_t *ev);

View file

@ -80,7 +80,7 @@ void I_ShutdownSound(void);
\return sfx handle \return sfx handle
*/ */
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority); INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel);
/** \brief Stops a sound channel. /** \brief Stops a sound channel.
@ -289,4 +289,4 @@ void I_PlayCD(UINT8 track, UINT8 looping);
*/ */
boolean I_SetVolumeCD(INT32 volume); boolean I_SetVolumeCD(INT32 volume);
#endif #endif

View file

@ -225,6 +225,33 @@ static void wattcp_outch(char s)
} }
#endif #endif
#ifdef USE_WINSOCK
// stupid microsoft makes things complicated
static char *get_WSAErrorStr(int e)
{
static char buf[256]; // allow up to 255 bytes
buf[0] = '\0';
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD)e,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)buf,
sizeof (buf),
NULL);
if (!buf[0]) // provide a fallback error message if no message is available for some reason
sprintf(buf, "Unknown error");
return buf;
}
#undef strerror
#define strerror get_WSAErrorStr
#endif
#ifdef USE_WINSOCK2 #ifdef USE_WINSOCK2
#define inet_ntop inet_ntopA #define inet_ntop inet_ntopA
#define HAVE_NTOP #define HAVE_NTOP
@ -703,9 +730,13 @@ static void SOCK_Send(void)
c = SOCK_SendToAddr(nodesocket[doomcom->remotenode], &clientaddress[doomcom->remotenode]); c = SOCK_SendToAddr(nodesocket[doomcom->remotenode], &clientaddress[doomcom->remotenode]);
} }
if (c == ERRSOCKET && errno != ECONNREFUSED && errno != EWOULDBLOCK) if (c == ERRSOCKET)
I_Error("SOCK_Send, error sending to node %d (%s) #%u: %s", doomcom->remotenode, {
SOCK_GetNodeAddress(doomcom->remotenode), errno, strerror(errno)); int e = errno; // save error code so it can't be modified later
if (e != ECONNREFUSED && e != EWOULDBLOCK)
I_Error("SOCK_Send, error sending to node %d (%s) #%u: %s", doomcom->remotenode,
SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
}
} }
#endif #endif

View file

@ -3458,8 +3458,8 @@ state_t states[NUMSTATES] =
{SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1}, // S_SMASHSPIKE_FLOAT {SPR_FMCE, 0, 20, {NULL}, 0, 0, S_SMASHSPIKE_EASE1}, // S_SMASHSPIKE_FLOAT
{SPR_FMCE, 0, 4, {A_ZThrust}, 4, (1<<16)|1, S_SMASHSPIKE_EASE2}, // S_SMASHSPIKE_EASE1 {SPR_FMCE, 0, 4, {A_ZThrust}, 4, (1<<16)|1, S_SMASHSPIKE_EASE2}, // S_SMASHSPIKE_EASE1
{SPR_FMCE, 0, 4, {A_ZThrust}, 0, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_EASE1 {SPR_FMCE, 0, 4, {A_ZThrust}, 0, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_EASE2
{SPR_FMCE, 0, 2, {A_ZThrust}, -6, (1<<16)|1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_FALL {SPR_FMCE, 0, 2, {A_ZThrust}, -6, 1, S_SMASHSPIKE_FALL}, // S_SMASHSPIKE_FALL
{SPR_FMCE, 1, 2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1 {SPR_FMCE, 1, 2, {A_MultiShotDist}, (MT_DUST<<16)|10, -48, S_SMASHSPIKE_STOMP2}, // S_SMASHSPIKE_STOMP1
{SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1}, // S_SMASHSPIKE_STOMP2 {SPR_FMCE, 2, 14, {NULL}, 0, 0, S_SMASHSPIKE_RISE1}, // S_SMASHSPIKE_STOMP2
{SPR_FMCE, 1, 2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE1 {SPR_FMCE, 1, 2, {NULL}, 0, 0, S_SMASHSPIKE_RISE2}, // S_SMASHSPIKE_RISE1
@ -17814,6 +17814,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_ANGLEMAN
758, // doomednum
S_INVISIBLE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8, // radius
8, // height
0, // display offset
10, // mass
0, // damage
sfx_None, // activesound
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_POLYANCHOR { // MT_POLYANCHOR
760, // doomednum 760, // doomednum
S_INVISIBLE, // spawnstate S_INVISIBLE, // spawnstate

View file

@ -4305,6 +4305,7 @@ typedef enum mobj_type
MT_PULL, MT_PULL,
MT_GHOST, MT_GHOST,
MT_OVERLAY, MT_OVERLAY,
MT_ANGLEMAN,
MT_POLYANCHOR, MT_POLYANCHOR,
MT_POLYSPAWN, MT_POLYSPAWN,
MT_POLYSPAWNCRUSH, MT_POLYSPAWNCRUSH,

View file

@ -14,6 +14,9 @@
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
#include "p_local.h" #include "p_local.h"
#include "p_setup.h" // So we can have P_SetupLevelSky #include "p_setup.h" // So we can have P_SetupLevelSky
#ifdef ESLOPE
#include "p_slopes.h" // P_GetZAt
#endif
#include "z_zone.h" #include "z_zone.h"
#include "r_main.h" #include "r_main.h"
#include "r_things.h" #include "r_things.h"
@ -2009,6 +2012,24 @@ static int lib_evStartCrumble(lua_State *L)
return 0; return 0;
} }
#ifdef ESLOPE
// P_SLOPES
////////////
static int lib_pGetZAt(lua_State *L)
{
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
//HUDSAFE
if (!slope)
return LUA_ErrInvalid(L, "pslope_t");
lua_pushfixed(L, P_GetZAt(slope, x, y));
return 1;
}
#endif
// R_DEFS // R_DEFS
//////////// ////////////
@ -2633,6 +2654,11 @@ static luaL_Reg lib[] = {
{"EV_CrumbleChain",lib_evCrumbleChain}, {"EV_CrumbleChain",lib_evCrumbleChain},
{"EV_StartCrumble",lib_evStartCrumble}, {"EV_StartCrumble",lib_evStartCrumble},
#ifdef ESLOPE
// p_slopes
{"P_GetZAt",lib_pGetZAt},
#endif
// r_defs // r_defs
{"R_PointToAngle",lib_rPointToAngle}, {"R_PointToAngle",lib_rPointToAngle},
{"R_PointToAngle2",lib_rPointToAngle2}, {"R_PointToAngle2",lib_rPointToAngle2},

View file

@ -48,6 +48,7 @@ enum hook {
hook_MobjMoveBlocked, hook_MobjMoveBlocked,
hook_MapThingSpawn, hook_MapThingSpawn,
hook_FollowMobj, hook_FollowMobj,
hook_PlayerQuit,
hook_MAX // last hook hook_MAX // last hook
}; };
@ -87,5 +88,6 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
#define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked) #define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked)
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
boolean LUAh_FollowMobj(player_t *player, mobj_t *mo); // Hook for P_PlayerAfterThink Smiles mobj-following boolean LUAh_FollowMobj(player_t *player, mobj_t *mo); // Hook for P_PlayerAfterThink Smiles mobj-following
void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting
#endif #endif

View file

@ -59,6 +59,7 @@ const char *const hookNames[hook_MAX+1] = {
"MobjMoveBlocked", "MobjMoveBlocked",
"MapThingSpawn", "MapThingSpawn",
"FollowMobj", "FollowMobj",
"PlayerQuit",
NULL NULL
}; };
@ -1192,4 +1193,30 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj)
return hooked; return hooked;
} }
void LUAh_PlayerQuit(player_t *plr, int reason)
{
hook_p hookp;
if (!gL || !(hooksAvailable[hook_PlayerQuit/8] & (1<<(hook_PlayerQuit%8))))
return;
lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_PlayerQuit)
{
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit
lua_pushinteger(gL, reason); // Reason for quitting
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
LUA_Call(gL, 2);
}
lua_settop(gL, 0);
}
#endif #endif

View file

@ -814,6 +814,15 @@ static int libd_RandomChance(lua_State *L)
return 1; return 1;
} }
// 30/10/18 Lat': Get cv_translucenthud's value for HUD rendering as a normal V_xxTRANS int
// Could as well be thrown in global vars for ease of access but I guess it makes sense for it to be a HUD fn
static int libd_getlocaltransflag(lua_State *L)
{
HUDONLY
lua_pushinteger(L, (10-cv_translucenthud.value)*V_10TRANS); // A bit weird that it's called "translucenthud" yet 10 is fully opaque :V
return 1;
}
static luaL_Reg lib_draw[] = { static luaL_Reg lib_draw[] = {
// cache // cache
{"patchExists", libd_patchExists}, {"patchExists", libd_patchExists},
@ -844,6 +853,7 @@ static luaL_Reg lib_draw[] = {
{"dupx", libd_dupx}, {"dupx", libd_dupx},
{"dupy", libd_dupy}, {"dupy", libd_dupy},
{"renderer", libd_renderer}, {"renderer", libd_renderer},
{"localTransFlag", libd_getlocaltransflag},
{NULL, NULL} {NULL, NULL}
}; };
@ -867,6 +877,19 @@ static int lib_huddisable(lua_State *L)
return 0; return 0;
} }
// 30/10/18: Lat': How come this wasn't here before?
static int lib_hudenabled(lua_State *L)
{
enum hud option = luaL_checkoption(L, 1, NULL, hud_disable_options);
if (hud_enabled[option/8] & (1<<(option%8)))
lua_pushboolean(L, true);
else
lua_pushboolean(L, false);
return 1;
}
// add a HUD element for rendering // add a HUD element for rendering
static int lib_hudadd(lua_State *L) static int lib_hudadd(lua_State *L)
{ {
@ -894,6 +917,7 @@ static int lib_hudadd(lua_State *L)
static luaL_Reg lib_hud[] = { static luaL_Reg lib_hud[] = {
{"enable", lib_hudenable}, {"enable", lib_hudenable},
{"disable", lib_huddisable}, {"disable", lib_huddisable},
{"enabled", lib_hudenabled},
{"add", lib_hudadd}, {"add", lib_hudadd},
{NULL, NULL} {NULL, NULL}
}; };

View file

@ -42,6 +42,11 @@ extern lua_State *gL;
#define META_SEG "SEG_T*" #define META_SEG "SEG_T*"
#define META_NODE "NODE_T*" #define META_NODE "NODE_T*"
#endif #endif
#ifdef ESLOPE
#define META_SLOPE "PSLOPE_T*"
#define META_VECTOR2 "VECTOR2_T"
#define META_VECTOR3 "VECTOR3_T"
#endif
#define META_MAPHEADER "MAPHEADER_T*" #define META_MAPHEADER "MAPHEADER_T*"
#define META_CVAR "CONSVAR_T*" #define META_CVAR "CONSVAR_T*"

View file

@ -16,6 +16,10 @@
#include "p_local.h" #include "p_local.h"
#include "p_setup.h" #include "p_setup.h"
#include "z_zone.h" #include "z_zone.h"
#ifdef ESLOPE
#include "p_slopes.h"
#endif
#include "r_main.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"
@ -38,7 +42,13 @@ enum sector_e {
sector_heightsec, sector_heightsec,
sector_camsec, sector_camsec,
sector_lines, sector_lines,
#ifdef ESLOPE
sector_ffloors,
sector_fslope,
sector_cslope
#else
sector_ffloors sector_ffloors
#endif
}; };
static const char *const sector_opt[] = { static const char *const sector_opt[] = {
@ -55,6 +65,10 @@ static const char *const sector_opt[] = {
"camsec", "camsec",
"lines", "lines",
"ffloors", "ffloors",
#ifdef ESLOPE
"f_slope",
"c_slope",
#endif
NULL}; NULL};
enum subsector_e { enum subsector_e {
@ -160,6 +174,10 @@ enum ffloor_e {
ffloor_toplightlevel, ffloor_toplightlevel,
ffloor_bottomheight, ffloor_bottomheight,
ffloor_bottompic, ffloor_bottompic,
#ifdef ESLOPE
ffloor_tslope,
ffloor_bslope,
#endif
ffloor_sector, ffloor_sector,
ffloor_flags, ffloor_flags,
ffloor_master, ffloor_master,
@ -176,6 +194,10 @@ static const char *const ffloor_opt[] = {
"toplightlevel", "toplightlevel",
"bottomheight", "bottomheight",
"bottompic", "bottompic",
#ifdef ESLOPE
"t_slope",
"b_slope",
#endif
"sector", // secnum pushed as control sector userdata "sector", // secnum pushed as control sector userdata
"flags", "flags",
"master", // control linedef "master", // control linedef
@ -261,6 +283,47 @@ static const char *const bbox_opt[] = {
"right", "right",
NULL}; NULL};
#ifdef ESLOPE
enum slope_e {
slope_valid = 0,
slope_o,
slope_d,
slope_zdelta,
slope_normal,
slope_zangle,
slope_xydirection,
slope_sourceline,
slope_refpos,
slope_flags
};
static const char *const slope_opt[] = {
"valid",
"o",
"d",
"zdelta",
"normal",
"zangle",
"xydirection",
"sourceline",
"refpos",
"flags",
NULL};
// shared by both vector2_t and vector3_t
enum vector_e {
vector_x = 0,
vector_y,
vector_z
};
static const char *const vector_opt[] = {
"x",
"y",
"z",
NULL};
#endif
static const char *const array_opt[] ={"iterate",NULL}; static const char *const array_opt[] ={"iterate",NULL};
static const char *const valid_opt[] ={"valid",NULL}; static const char *const valid_opt[] ={"valid",NULL};
@ -493,6 +556,14 @@ static int sector_get(lua_State *L)
LUA_PushUserdata(L, sector->ffloors, META_FFLOOR); LUA_PushUserdata(L, sector->ffloors, META_FFLOOR);
lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateFFloors and sector->ffloors as upvalues for the function lua_pushcclosure(L, sector_iterate, 2); // push lib_iterateFFloors and sector->ffloors as upvalues for the function
return 1; return 1;
#ifdef ESLOPE
case sector_fslope: // f_slope
LUA_PushUserdata(L, sector->f_slope, META_SLOPE);
return 1;
case sector_cslope: // c_slope
LUA_PushUserdata(L, sector->c_slope, META_SLOPE);
return 1;
#endif
} }
return 0; return 0;
} }
@ -515,6 +586,10 @@ static int sector_set(lua_State *L)
case sector_heightsec: // heightsec case sector_heightsec: // heightsec
case sector_camsec: // camsec case sector_camsec: // camsec
case sector_ffloors: // ffloors case sector_ffloors: // ffloors
#ifdef ESLOPE
case sector_fslope: // f_slope
case sector_cslope: // c_slope
#endif
default: default:
return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]);
case sector_floorheight: { // floorheight case sector_floorheight: { // floorheight
@ -1602,6 +1677,14 @@ static int ffloor_get(lua_State *L)
lua_pushlstring(L, levelflat->name, 8); lua_pushlstring(L, levelflat->name, 8);
return 1; return 1;
} }
#ifdef ESLOPE
case ffloor_tslope:
LUA_PushUserdata(L, *ffloor->t_slope, META_SLOPE);
return 1;
case ffloor_bslope:
LUA_PushUserdata(L, *ffloor->b_slope, META_SLOPE);
return 1;
#endif
case ffloor_sector: case ffloor_sector:
LUA_PushUserdata(L, &sectors[ffloor->secnum], META_SECTOR); LUA_PushUserdata(L, &sectors[ffloor->secnum], META_SECTOR);
return 1; return 1;
@ -1641,6 +1724,10 @@ static int ffloor_set(lua_State *L)
switch(field) switch(field)
{ {
case ffloor_valid: // valid case ffloor_valid: // valid
#ifdef ESLOPE
case ffloor_tslope: // t_slope
case ffloor_bslope: // b_slope
#endif
case ffloor_sector: // sector case ffloor_sector: // sector
case ffloor_master: // master case ffloor_master: // master
case ffloor_target: // target case ffloor_target: // target
@ -1701,6 +1788,189 @@ static int ffloor_set(lua_State *L)
return 0; return 0;
} }
#ifdef ESLOPE
//////////////
// pslope_t //
//////////////
static int slope_get(lua_State *L)
{
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
if (!slope)
{
if (field == slope_valid) {
lua_pushboolean(L, 0);
return 1;
}
return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
}
switch(field)
{
case slope_valid: // valid
lua_pushboolean(L, 1);
return 1;
case slope_o: // o
LUA_PushUserdata(L, &slope->o, META_VECTOR3);
return 1;
case slope_d: // d
LUA_PushUserdata(L, &slope->d, META_VECTOR2);
return 1;
case slope_zdelta: // zdelta
lua_pushfixed(L, slope->zdelta);
return 1;
case slope_normal: // normal
LUA_PushUserdata(L, &slope->normal, META_VECTOR3);
return 1;
case slope_zangle: // zangle
lua_pushangle(L, slope->zangle);
return 1;
case slope_xydirection: // xydirection
lua_pushangle(L, slope->xydirection);
return 1;
case slope_sourceline: // source linedef
LUA_PushUserdata(L, slope->sourceline, META_LINE);
return 1;
case slope_refpos: // refpos
lua_pushinteger(L, slope->refpos);
return 1;
case slope_flags: // flags
lua_pushinteger(L, slope->flags);
return 1;
}
return 0;
}
static int slope_set(lua_State *L)
{
pslope_t *slope = *((pslope_t **)luaL_checkudata(L, 1, META_SLOPE));
enum slope_e field = luaL_checkoption(L, 2, slope_opt[0], slope_opt);
if (!slope)
return luaL_error(L, "accessed pslope_t doesn't exist anymore.");
if (hud_running)
return luaL_error(L, "Do not alter pslope_t in HUD rendering code!");
switch(field) // todo: reorganize this shit
{
case slope_valid: // valid
case slope_sourceline: // sourceline
case slope_d: // d
case slope_flags: // flags
case slope_normal: // normal
case slope_refpos: // refpos
default:
return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
case slope_o: { // o
luaL_checktype(L, 3, LUA_TTABLE);
lua_getfield(L, 3, "x");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 3, 1);
}
if (!lua_isnil(L, -1))
slope->o.x = luaL_checkfixed(L, -1);
else
slope->o.x = 0;
lua_pop(L, 1);
lua_getfield(L, 3, "y");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 3, 2);
}
if (!lua_isnil(L, -1))
slope->o.y = luaL_checkfixed(L, -1);
else
slope->o.y = 0;
lua_pop(L, 1);
lua_getfield(L, 3, "z");
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_rawgeti(L, 3, 3);
}
if (!lua_isnil(L, -1))
slope->o.z = luaL_checkfixed(L, -1);
else
slope->o.z = 0;
lua_pop(L, 1);
break;
}
case slope_zdelta: { // zdelta, this is temp until i figure out wtf to do
slope->zdelta = luaL_checkfixed(L, 3);
slope->zangle = R_PointToAngle2(0, 0, FRACUNIT, -slope->zdelta);
P_CalculateSlopeNormal(slope);
break;
}
case slope_zangle: { // zangle
angle_t zangle = luaL_checkangle(L, 3);
if (zangle == ANGLE_90 || zangle == ANGLE_270)
return luaL_error(L, "invalid zangle for slope!");
slope->zangle = zangle;
slope->zdelta = -FINETANGENT(((slope->zangle+ANGLE_90)>>ANGLETOFINESHIFT) & 4095);
P_CalculateSlopeNormal(slope);
break;
}
case slope_xydirection: // xydirection
slope->xydirection = luaL_checkangle(L, 3);
slope->d.x = -FINECOSINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK);
slope->d.y = -FINESINE((slope->xydirection>>ANGLETOFINESHIFT) & FINEMASK);
P_CalculateSlopeNormal(slope);
break;
}
return 0;
}
///////////////
// vector*_t //
///////////////
static int vector2_get(lua_State *L)
{
vector2_t *vec = *((vector2_t **)luaL_checkudata(L, 1, META_VECTOR2));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector2_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
default: break;
}
return 0;
}
static int vector3_get(lua_State *L)
{
vector3_t *vec = *((vector3_t **)luaL_checkudata(L, 1, META_VECTOR3));
enum vector_e field = luaL_checkoption(L, 2, vector_opt[0], vector_opt);
if (!vec)
return luaL_error(L, "accessed vector3_t doesn't exist anymore.");
switch(field)
{
case vector_x: lua_pushfixed(L, vec->x); return 1;
case vector_y: lua_pushfixed(L, vec->y); return 1;
case vector_z: lua_pushfixed(L, vec->z); return 1;
default: break;
}
return 0;
}
#endif
///////////////////// /////////////////////
// mapheaderinfo[] // // mapheaderinfo[] //
///////////////////// /////////////////////
@ -1924,6 +2194,26 @@ int LUA_MapLib(lua_State *L)
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
lua_pop(L, 1); lua_pop(L, 1);
#ifdef ESLOPE
luaL_newmetatable(L, META_SLOPE);
lua_pushcfunction(L, slope_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, slope_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1);
luaL_newmetatable(L, META_VECTOR2);
lua_pushcfunction(L, vector2_get);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
luaL_newmetatable(L, META_VECTOR3);
lua_pushcfunction(L, vector3_get);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
#endif
luaL_newmetatable(L, META_MAPHEADER); luaL_newmetatable(L, META_MAPHEADER);
lua_pushcfunction(L, mapheaderinfo_get); lua_pushcfunction(L, mapheaderinfo_get);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");

View file

@ -83,7 +83,12 @@ enum mobj_e {
mobj_extravalue1, mobj_extravalue1,
mobj_extravalue2, mobj_extravalue2,
mobj_cusval, mobj_cusval,
#ifdef ESLOPE
mobj_cvmem,
mobj_standingslope
#else
mobj_cvmem mobj_cvmem
#endif
}; };
static const char *const mobj_opt[] = { static const char *const mobj_opt[] = {
@ -146,6 +151,9 @@ static const char *const mobj_opt[] = {
"extravalue2", "extravalue2",
"cusval", "cusval",
"cvmem", "cvmem",
#ifdef ESLOPE
"standingslope",
#endif
NULL}; NULL};
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field]) #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
@ -358,6 +366,11 @@ static int mobj_get(lua_State *L)
case mobj_cvmem: case mobj_cvmem:
lua_pushinteger(L, mo->cvmem); lua_pushinteger(L, mo->cvmem);
break; break;
#ifdef ESLOPE
case mobj_standingslope:
LUA_PushUserdata(L, mo->standingslope, META_SLOPE);
break;
#endif
default: // extra custom variables in Lua memory default: // extra custom variables in Lua memory
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1)); I_Assert(lua_istable(L, -1));
@ -675,6 +688,10 @@ static int mobj_set(lua_State *L)
case mobj_cvmem: case mobj_cvmem:
mo->cvmem = luaL_checkinteger(L, 3); mo->cvmem = luaL_checkinteger(L, 3);
break; break;
#ifdef ESLOPE
case mobj_standingslope:
return NOSET;
#endif
default: default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1)); I_Assert(lua_istable(L, -1));

View file

@ -22,6 +22,9 @@
#include "byteptr.h" #include "byteptr.h"
#include "p_saveg.h" #include "p_saveg.h"
#include "p_local.h" #include "p_local.h"
#ifdef ESLOPE
#include "p_slopes.h" // for P_SlopeById
#endif
#ifdef LUA_ALLOW_BYTECODE #ifdef LUA_ALLOW_BYTECODE
#include "d_netfil.h" // for LUA_DumpFile #include "d_netfil.h" // for LUA_DumpFile
#endif #endif
@ -193,25 +196,27 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump)
{ {
MYFILE f; MYFILE f;
char *name; char *name;
size_t len;
f.wad = wad; f.wad = wad;
f.size = W_LumpLengthPwad(wad, lump); f.size = W_LumpLengthPwad(wad, lump);
f.data = Z_Malloc(f.size, PU_LUA, NULL); f.data = Z_Malloc(f.size, PU_LUA, NULL);
W_ReadLumpPwad(wad, lump, f.data); W_ReadLumpPwad(wad, lump, f.data);
f.curpos = f.data; f.curpos = f.data;
len = strlen(wadfiles[wad]->filename); // length of file name
if (wadfiles[wad]->type == RET_LUA) if (wadfiles[wad]->type == RET_LUA)
{ {
name = malloc(strlen(wadfiles[wad]->filename)+1); name = malloc(len+1);
strcpy(name, wadfiles[wad]->filename); strcpy(name, wadfiles[wad]->filename);
} }
else // If it's not a .lua file, copy the lump name in too. else // If it's not a .lua file, copy the lump name in too.
{ {
lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump]; lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump];
size_t length = strlen(wadfiles[wad]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name len += 1 + strlen(lump_p->name2); // length of file name, '|', and lump name
name = malloc(length + 1); name = malloc(len+1);
sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2); sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2);
name[length] = '\0'; name[len] = '\0';
} }
LUA_LoadFile(&f, name); // actually load file! LUA_LoadFile(&f, name); // actually load file!
@ -496,6 +501,9 @@ enum
ARCH_NODE, ARCH_NODE,
#endif #endif
ARCH_FFLOOR, ARCH_FFLOOR,
#ifdef ESLOPE
ARCH_SLOPE,
#endif
ARCH_MAPHEADER, ARCH_MAPHEADER,
ARCH_TEND=0xFF, ARCH_TEND=0xFF,
@ -520,6 +528,9 @@ static const struct {
{META_NODE, ARCH_NODE}, {META_NODE, ARCH_NODE},
#endif #endif
{META_FFLOOR, ARCH_FFLOOR}, {META_FFLOOR, ARCH_FFLOOR},
#ifdef ESLOPE
{META_SLOPE, ARCH_SLOPE},
#endif
{META_MAPHEADER, ARCH_MAPHEADER}, {META_MAPHEADER, ARCH_MAPHEADER},
{NULL, ARCH_NULL} {NULL, ARCH_NULL}
}; };
@ -774,6 +785,19 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
} }
break; break;
} }
#ifdef ESLOPE
case ARCH_SLOPE:
{
pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex));
if (!slope)
WRITEUINT8(save_p, ARCH_NULL);
else {
WRITEUINT8(save_p, ARCH_SLOPE);
WRITEUINT16(save_p, slope->id);
}
break;
}
#endif
case ARCH_MAPHEADER: case ARCH_MAPHEADER:
{ {
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex)); mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
@ -995,8 +1019,13 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
LUA_PushUserdata(gL, rover, META_FFLOOR); LUA_PushUserdata(gL, rover, META_FFLOOR);
break; break;
} }
#ifdef ESLOPE
case ARCH_SLOPE:
LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE);
break;
#endif
case ARCH_MAPHEADER: case ARCH_MAPHEADER:
LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_MAPHEADER); LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER);
break; break;
case ARCH_TEND: case ARCH_TEND:
return 1; return 1;

View file

@ -497,7 +497,9 @@ static void GIF_framewrite(void)
// screen regions are handled in GIF_lzw // screen regions are handled in GIF_lzw
{ {
UINT16 delay = 3; // todo int d1 = (int)((100.0/NEWTICRATE)*(gif_frames+1));
int d2 = (int)((100.0/NEWTICRATE)*(gif_frames));
UINT16 delay = d1-d2;
INT32 startline; INT32 startline;
WRITEMEM(p, gifframe_gchead, 4); WRITEMEM(p, gifframe_gchead, 4);

View file

@ -273,6 +273,7 @@ menu_t SP_MainDef, OP_MainDef;
menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef;
// Single Player // Single Player
static void M_StartTutorial(INT32 choice);
static void M_LoadGame(INT32 choice); static void M_LoadGame(INT32 choice);
static void M_TimeAttackLevelSelect(INT32 choice); static void M_TimeAttackLevelSelect(INT32 choice);
static void M_TimeAttack(INT32 choice); static void M_TimeAttack(INT32 choice);
@ -443,6 +444,9 @@ static CV_PossibleValue_t serversort_cons_t[] = {
}; };
consvar_t cv_serversort = {"serversort", "Ping", CV_HIDEN | CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_serversort = {"serversort", "Ping", CV_HIDEN | CV_CALL, serversort_cons_t, M_SortServerList, 0, NULL, NULL, 0, 0, NULL};
// first time memory
consvar_t cv_tutorialprompt = {"tutorialprompt", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
// autorecord demos for time attack // autorecord demos for time attack
static consvar_t cv_autorecord = {"autorecord", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_autorecord = {"autorecord", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -734,6 +738,7 @@ static menuitem_t SR_EmblemHintMenu[] =
// Single Player Main // Single Player Main
static menuitem_t SP_MainMenu[] = static menuitem_t SP_MainMenu[] =
{ {
{IT_CALL | IT_STRING, NULL, "Tutorial", M_StartTutorial, 84},
{IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 92}, {IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 92},
{IT_SECRET, NULL, "Record Attack", M_TimeAttack, 100}, {IT_SECRET, NULL, "Record Attack", M_TimeAttack, 100},
{IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 108}, {IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 108},
@ -742,6 +747,7 @@ static menuitem_t SP_MainMenu[] =
enum enum
{ {
sptutorial,
sploadgame, sploadgame,
sprecordattack, sprecordattack,
spnightsmode, spnightsmode,
@ -1572,7 +1578,18 @@ menu_t SR_EmblemHintDef =
}; };
// Single Player // Single Player
menu_t SP_MainDef = CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72); menu_t SP_MainDef = //CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72);
{
NULL,
sizeof(SP_MainMenu)/sizeof(menuitem_t),
&MainDef,
SP_MainMenu,
M_DrawCenteredMenu,
BASEVIDWIDTH/2, 72,
1, // start at "Start Game" on first entry
NULL
};
menu_t SP_LoadDef = menu_t SP_LoadDef =
{ {
"M_PICKG", "M_PICKG",
@ -6114,6 +6131,8 @@ static void M_CustomLevelSelect(INT32 choice)
static void M_SinglePlayerMenu(INT32 choice) static void M_SinglePlayerMenu(INT32 choice)
{ {
(void)choice; (void)choice;
SP_MainMenu[sptutorial].status =
tutorialmap ? IT_CALL|IT_STRING : IT_NOTHING|IT_DISABLED;
SP_MainMenu[sprecordattack].status = SP_MainMenu[sprecordattack].status =
(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
SP_MainMenu[spnightsmode].status = SP_MainMenu[spnightsmode].status =
@ -6139,6 +6158,80 @@ static void M_LoadGameLevelSelect(INT32 choice)
M_SetupNextMenu(&SP_LevelSelectDef); M_SetupNextMenu(&SP_LevelSelectDef);
} }
void M_TutorialSaveControlResponse(INT32 ch)
{
if (ch == 'y' || ch == KEY_ENTER)
{
G_CopyControls(gamecontrol, gamecontroldefault[tutorialgcs], gcl_tutorial_full, num_gcl_tutorial_full);
CV_Set(&cv_usemouse, cv_usemouse.defaultvalue);
CV_Set(&cv_alwaysfreelook, cv_alwaysfreelook.defaultvalue);
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog, cv_analog.defaultvalue);
S_StartSound(NULL, sfx_itemup);
}
else
S_StartSound(NULL, sfx_menu1);
}
static void M_TutorialControlResponse(INT32 ch)
{
if (ch != KEY_ESCAPE)
{
G_CopyControls(gamecontroldefault[gcs_custom], gamecontrol, NULL, 0); // using gcs_custom as temp storage for old controls
if (ch == 'y' || ch == KEY_ENTER)
{
tutorialgcs = gcs_fps;
tutorialusemouse = cv_usemouse.value;
tutorialfreelook = cv_alwaysfreelook.value;
tutorialmousemove = cv_mousemove.value;
tutorialanalog = cv_analog.value;
G_CopyControls(gamecontrol, gamecontroldefault[tutorialgcs], gcl_tutorial_full, num_gcl_tutorial_full);
CV_Set(&cv_usemouse, cv_usemouse.defaultvalue);
CV_Set(&cv_alwaysfreelook, cv_alwaysfreelook.defaultvalue);
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog, cv_analog.defaultvalue);
//S_StartSound(NULL, sfx_itemup);
}
else
{
tutorialgcs = gcs_custom;
S_StartSound(NULL, sfx_menu1);
}
M_StartTutorial(INT32_MAX);
}
else
S_StartSound(NULL, sfx_menu1);
MessageDef.prevMenu = &SP_MainDef; // if FirstPrompt -> ControlsPrompt -> ESC, we would go to the main menu unless we force this
}
// Starts up the tutorial immediately (tbh I wasn't sure where else to put this)
static void M_StartTutorial(INT32 choice)
{
if (!tutorialmap)
return; // no map to go to, don't bother
if (choice != INT32_MAX && G_GetControlScheme(gamecontrol, gcl_tutorial_check, num_gcl_tutorial_check) != gcs_fps)
{
M_StartMessage("Do you want to try the \202recommended \202movement controls\x80?\n\nWe will set them just for this tutorial.\n\nPress 'Y' or 'Enter' to confirm\nPress 'N' or any key to keep \nyour current controls.\n",M_TutorialControlResponse,MM_YESNO);
return;
}
else if (choice != INT32_MAX)
tutorialgcs = gcs_custom;
CV_SetValue(&cv_tutorialprompt, 0); // first-time prompt
tutorialmode = true; // turn on tutorial mode
emeralds = 0;
M_ClearMenus(true);
gamecomplete = false;
cursaveslot = 0;
G_DeferedInitNew(false, G_BuildMapName(tutorialmap), 0, false, false);
}
// ============== // ==============
// LOAD GAME MENU // LOAD GAME MENU
// ============== // ==============
@ -6746,6 +6839,26 @@ static void M_HandleLoadSave(INT32 choice)
} }
} }
static void M_FirstTimeResponse(INT32 ch)
{
S_StartSound(NULL, sfx_menu1);
if (ch == KEY_ESCAPE)
return;
if (ch != 'y' && ch != KEY_ENTER)
{
CV_SetValue(&cv_tutorialprompt, 0);
M_ReadSaveStrings();
MessageDef.prevMenu = &SP_LoadDef; // calls M_SetupNextMenu
}
else
{
M_StartTutorial(0);
MessageDef.prevMenu = &MessageDef; // otherwise, the controls prompt won't fire
}
}
// //
// Selected from SRB2 menu // Selected from SRB2 menu
// //
@ -6753,6 +6866,13 @@ static void M_LoadGame(INT32 choice)
{ {
(void)choice; (void)choice;
if (tutorialmap && cv_tutorialprompt.value)
{
M_StartMessage("Do you want to \x82play a brief Tutorial\x80?\n\nWe highly recommend this because \nthe controls are slightly different \nfrom other games.\n\nPress 'Y' or 'Enter' to go\nPress 'N' or any key to skip\n",
M_FirstTimeResponse, MM_YESNO);
return;
}
M_ReadSaveStrings(); M_ReadSaveStrings();
M_SetupNextMenu(&SP_LoadDef); M_SetupNextMenu(&SP_LoadDef);
} }
@ -9219,9 +9339,17 @@ static void M_DrawControl(void)
// draw title (or big pic) // draw title (or big pic)
M_DrawMenuTitle(); M_DrawMenuTitle();
M_CentreText(30, if (tutorialmode && tutorialgcs)
(setupcontrols_secondaryplayer ? "SET CONTROLS FOR SECONDARY PLAYER" : {
"PRESS ENTER TO CHANGE, BACKSPACE TO CLEAR")); if ((gametic / TICRATE) % 2)
M_CentreText(30, "\202EXIT THE TUTORIAL TO CHANGE THE CONTROLS");
else
M_CentreText(30, "EXIT THE TUTORIAL TO CHANGE THE CONTROLS");
}
else
M_CentreText(30,
(setupcontrols_secondaryplayer ? "SET CONTROLS FOR SECONDARY PLAYER" :
"PRESS ENTER TO CHANGE, BACKSPACE TO CLEAR"));
if (i) if (i)
V_DrawString(currentMenu->x - 16, y-(skullAnimCounter/5), V_YELLOWMAP, "\x1A"); // up arrow V_DrawString(currentMenu->x - 16, y-(skullAnimCounter/5), V_YELLOWMAP, "\x1A"); // up arrow
@ -9356,6 +9484,9 @@ static void M_ChangeControl(INT32 choice)
{ {
static char tmp[55]; static char tmp[55];
if (tutorialmode && tutorialgcs) // don't allow control changes if temp control override is active
return;
controltochange = currentMenu->menuitems[choice].alphaKey; controltochange = currentMenu->menuitems[choice].alphaKey;
sprintf(tmp, M_GetText("Hit the new key for\n%s\nESC for Cancel"), sprintf(tmp, M_GetText("Hit the new key for\n%s\nESC for Cancel"),
currentMenu->menuitems[choice].text); currentMenu->menuitems[choice].text);
@ -9544,7 +9675,6 @@ static void M_ToggleMIDI(INT32 choice)
default: default:
break; break;
} }
if (midi_disabled) if (midi_disabled)
{ {
midi_disabled = false; midi_disabled = false;

View file

@ -240,6 +240,8 @@ extern INT16 char_on, startchar;
#define BwehHehHe() S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)) // Bweh heh he #define BwehHehHe() S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)) // Bweh heh he
void M_TutorialSaveControlResponse(INT32 ch);
void M_ForceSaveSlotSelected(INT32 sslot); void M_ForceSaveSlotSelected(INT32 sslot);
void M_CheatActivationResponder(INT32 ch); void M_CheatActivationResponder(INT32 ch);

View file

@ -58,7 +58,7 @@ typedef off_t off64_t;
#if defined(__MINGW32__) && ((__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3)) #if defined(__MINGW32__) && ((__GNUC__ > 7) || (__GNUC__ == 6 && __GNUC_MINOR__ >= 3))
#define PRIdS "u" #define PRIdS "u"
#elif defined (_WIN32) #elif defined (_WIN32)
#define PRIdS "Iu" #define PRIdS "Iu"
#elif defined (DJGPP) #elif defined (DJGPP)
#define PRIdS "u" #define PRIdS "u"
@ -475,7 +475,8 @@ void M_FirstLoadConfig(void)
} }
// load default control // load default control
G_Controldefault(); G_DefineDefaultControls();
G_CopyControls(gamecontrol, gamecontroldefault[gcs_fps], NULL, 0);
// load config, make sure those commands doesnt require the screen... // load config, make sure those commands doesnt require the screen...
COM_BufInsertText(va("exec \"%s\"\n", configfile)); COM_BufInsertText(va("exec \"%s\"\n", configfile));
@ -538,8 +539,28 @@ void M_SaveConfig(const char *filename)
// FIXME: save key aliases if ever implemented.. // FIXME: save key aliases if ever implemented..
CV_SaveVariables(f); if (tutorialmode && tutorialgcs)
if (!dedicated) G_SaveKeySetting(f); {
CV_SetValue(&cv_usemouse, tutorialusemouse);
CV_SetValue(&cv_alwaysfreelook, tutorialfreelook);
CV_SetValue(&cv_mousemove, tutorialmousemove);
CV_SetValue(&cv_analog, tutorialanalog);
CV_SaveVariables(f);
CV_Set(&cv_usemouse, cv_usemouse.defaultvalue);
CV_Set(&cv_alwaysfreelook, cv_alwaysfreelook.defaultvalue);
CV_Set(&cv_mousemove, cv_mousemove.defaultvalue);
CV_Set(&cv_analog, cv_analog.defaultvalue);
}
else
CV_SaveVariables(f);
if (!dedicated)
{
if (tutorialmode && tutorialgcs)
G_SaveKeySetting(f, gamecontroldefault[gcs_custom], gamecontrolbis); // using gcs_custom as temp storage
else
G_SaveKeySetting(f, gamecontrol, gamecontrolbis);
}
fclose(f); fclose(f);
} }

View file

@ -3324,6 +3324,11 @@ void A_MonitorPop(mobj_t *actor)
newmobj->sprite = SPR_TV1P; newmobj->sprite = SPR_TV1P;
} }
} }
// Run a linedef executor immediately upon popping
// You may want to delay your effects by 18 tics to sync with the reward giving
if (actor->spawnpoint && actor->lastlook)
P_LinedefExecute(actor->lastlook, actor->target, NULL);
} }
// Function: A_GoldMonitorPop // Function: A_GoldMonitorPop
@ -3407,6 +3412,11 @@ void A_GoldMonitorPop(mobj_t *actor)
newmobj->sprite = SPR_TV1P; newmobj->sprite = SPR_TV1P;
} }
} }
// Run a linedef executor immediately upon popping
// You may want to delay your effects by 18 tics to sync with the reward giving
if (actor->spawnpoint && actor->lastlook)
P_LinedefExecute(actor->lastlook, actor->target, NULL);
} }
// Function: A_GoldMonitorRestore // Function: A_GoldMonitorRestore

View file

@ -3729,14 +3729,15 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
if (player->pflags & PF_FLIPCAM && !(player->powers[pw_carry] == CR_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) if (player->pflags & PF_FLIPCAM && !(player->powers[pw_carry] == CR_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP)
postimg = postimg_flip; postimg = postimg_flip;
else if (player->awayviewtics) else if (player->awayviewtics && player->awayviewmobj != NULL) // Camera must obviously exist
{ {
camera_t dummycam; camera_t dummycam;
dummycam.subsector = player->awayviewmobj->subsector; dummycam.subsector = player->awayviewmobj->subsector;
dummycam.x = player->awayviewmobj->x; dummycam.x = player->awayviewmobj->x;
dummycam.y = player->awayviewmobj->y; dummycam.y = player->awayviewmobj->y;
dummycam.z = player->awayviewmobj->z; dummycam.z = player->awayviewmobj->z;
dummycam.height = 40*FRACUNIT; // alt view height is 20*FRACUNIT //dummycam.height = 40*FRACUNIT; // alt view height is 20*FRACUNIT
dummycam.height = 0; // Why? Remote viewpoint cameras have no height.
// Are we in water? // Are we in water?
if (P_CameraCheckWater(&dummycam)) if (P_CameraCheckWater(&dummycam))
postimg = postimg_water; postimg = postimg_water;
@ -4059,7 +4060,8 @@ void P_RecalcPrecipInSector(sector_t *sector)
// //
void P_NullPrecipThinker(precipmobj_t *mobj) void P_NullPrecipThinker(precipmobj_t *mobj)
{ {
(void)mobj; //(void)mobj;
mobj->precipflags &= ~PCF_THUNK;
} }
void P_SnowThinker(precipmobj_t *mobj) void P_SnowThinker(precipmobj_t *mobj)
@ -4079,25 +4081,26 @@ void P_RainThinker(precipmobj_t *mobj)
{ {
// cycle through states, // cycle through states,
// calling action functions at transitions // calling action functions at transitions
if (mobj->tics > 0 && --mobj->tics == 0) if (mobj->tics <= 0)
{ return;
// you can cycle through multiple states in a tic
if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate)) if (--mobj->tics)
return; // freed itself return;
}
if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate))
return;
if (mobj->state != &states[S_RAINRETURN])
return;
mobj->z = mobj->ceilingz;
P_SetPrecipMobjState(mobj, S_RAIN1);
if (mobj->state == &states[S_RAINRETURN])
{
mobj->z = mobj->ceilingz;
P_SetPrecipMobjState(mobj, S_RAIN1);
}
return; return;
} }
// adjust height // adjust height
mobj->z += mobj->momz; if ((mobj->z += mobj->momz) <= mobj->floorz)
if (mobj->z <= mobj->floorz)
{ {
// no splashes on sky or bottomless pits // no splashes on sky or bottomless pits
if (mobj->precipflags & PCF_PIT) if (mobj->precipflags & PCF_PIT)
@ -7433,6 +7436,48 @@ void P_MobjThinker(mobj_t *mobj)
if ((mobj->flags & MF_ENEMY) && (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)) if ((mobj->flags & MF_ENEMY) && (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1))
mobj->flags2 &= ~MF2_FRET; mobj->flags2 &= ~MF2_FRET;
// Angle-to-tracer to trigger a linedef exec
// See Linedef Exec 457 (Track mobj angle to point)
if ((mobj->eflags & MFE_TRACERANGLE) && mobj->tracer && mobj->extravalue2)
{
// mobj->lastlook - Don't disable behavior after first failure
// mobj->extravalue1 - Angle tolerance
// mobj->extravalue2 - Exec tag upon failure
// mobj->cvval - Allowable failure delay
// mobj->cvmem - Failure timer
angle_t ang = mobj->angle - R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y);
// \todo account for distance between mobj and tracer
// Because closer mobjs can be facing beyond the angle tolerance
// yet tracer is still in the camera view
// failure state: mobj is not facing tracer
// Reasaonable defaults: ANGLE_67h, ANGLE_292h
if (ang >= (UINT32)mobj->extravalue1 && ang <= ANGLE_MAX - (UINT32)mobj->extravalue1)
{
if (mobj->cvmem)
mobj->cvmem--;
else
{
INT32 exectag = mobj->extravalue2; // remember this before we erase the values
if (mobj->lastlook)
mobj->cvmem = mobj->cusval; // reset timer for next failure
else
{
// disable after first failure
mobj->eflags &= ~MFE_TRACERANGLE;
mobj->lastlook = mobj->extravalue1 = mobj->extravalue2 = mobj->cvmem = mobj->cusval = 0;
}
P_LinedefExecute(exectag, mobj, NULL);
}
}
else
mobj->cvmem = mobj->cusval; // reset failure timer
}
switch (mobj->type) switch (mobj->type)
{ {
case MT_WALLSPIKEBASE: case MT_WALLSPIKEBASE:
@ -8921,14 +8966,15 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{ {
precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type);
mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; mo->precipflags |= PCF_RAIN;
//mo->thinker.function.acp1 = (actionf_p1)P_RainThinker;
return mo; return mo;
} }
static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{ {
precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type);
mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; //mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker;
return mo; return mo;
} }
@ -10891,6 +10937,16 @@ ML_EFFECT4 : Don't clip inside the ground
mobj->flags2 |= MF2_OBJECTFLIP; mobj->flags2 |= MF2_OBJECTFLIP;
} }
// Extra functionality
if (mthing->options & MTF_EXTRA)
{
if (mobj->flags & MF_MONITOR && (mthing->angle & 16384))
{
// Store line exec tag to run upon popping
mobj->lastlook = (mthing->angle & 16383);
}
}
// Final set of not being able to draw nightsitems. // Final set of not being able to draw nightsitems.
if (mobj->flags & MF_NIGHTSITEM) if (mobj->flags & MF_NIGHTSITEM)
mobj->flags2 |= MF2_DONTDRAW; mobj->flags2 |= MF2_DONTDRAW;

View file

@ -239,6 +239,9 @@ typedef enum
MFE_SPRUNG = 1<<8, MFE_SPRUNG = 1<<8,
// Platform movement // Platform movement
MFE_APPLYPMOMZ = 1<<9, MFE_APPLYPMOMZ = 1<<9,
// Compute and trigger on mobj angle relative to tracer
// See Linedef Exec 457 (Track mobj angle to point)
MFE_TRACERANGLE = 1<<10,
// free: to and including 1<<15 // free: to and including 1<<15
} mobjeflag_t; } mobjeflag_t;
@ -254,6 +257,10 @@ typedef enum {
PCF_FOF = 4, PCF_FOF = 4,
// Above MOVING FOF (this means we need to keep floorz up to date...) // Above MOVING FOF (this means we need to keep floorz up to date...)
PCF_MOVINGFOF = 8, PCF_MOVINGFOF = 8,
// Is rain.
PCF_RAIN = 16,
// Ran the thinker this tic.
PCF_THUNK = 32,
} precipflag_t; } precipflag_t;
// Map Object definition. // Map Object definition.
typedef struct mobj_s typedef struct mobj_s
@ -449,7 +456,7 @@ boolean P_SupermanLook4Players(mobj_t *actor);
void P_DestroyRobots(void); void P_DestroyRobots(void);
void P_SnowThinker(precipmobj_t *mobj); void P_SnowThinker(precipmobj_t *mobj);
void P_RainThinker(precipmobj_t *mobj); void P_RainThinker(precipmobj_t *mobj);
FUNCMATH void P_NullPrecipThinker(precipmobj_t *mobj); void P_NullPrecipThinker(precipmobj_t *mobj);
void P_RemovePrecipMobj(precipmobj_t *mobj); void P_RemovePrecipMobj(precipmobj_t *mobj);
void P_SetScale(mobj_t *mobj, fixed_t newscale); void P_SetScale(mobj_t *mobj, fixed_t newscale);
void P_XYMovement(mobj_t *mo); void P_XYMovement(mobj_t *mo);

View file

@ -2121,8 +2121,7 @@ static void P_NetArchiveThinkers(void)
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_RemoveThinkerDelayed if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed
|| th->function.acp1 == (actionf_p1)P_RainThinker || th->function.acp1 == (actionf_p1)P_NullPrecipThinker))
|| th->function.acp1 == (actionf_p1)P_SnowThinker))
numsaved++; numsaved++;
if (th->function.acp1 == (actionf_p1)P_MobjThinker) if (th->function.acp1 == (actionf_p1)P_MobjThinker)
@ -2131,8 +2130,7 @@ static void P_NetArchiveThinkers(void)
continue; continue;
} }
#ifdef PARANOIA #ifdef PARANOIA
else if (th->function.acp1 == (actionf_p1)P_RainThinker else if (th->function.acp1 == (actionf_p1)P_NullPrecipThinker);
|| th->function.acp1 == (actionf_p1)P_SnowThinker);
#endif #endif
else if (th->function.acp1 == (actionf_p1)T_MoveCeiling) else if (th->function.acp1 == (actionf_p1)T_MoveCeiling)
{ {

View file

@ -1542,6 +1542,7 @@ static void P_LoadRawSideDefs2(void *data)
} }
case 443: // Calls a named Lua function case 443: // Calls a named Lua function
case 459: // Control text prompt (named tag)
{ {
char process[8*3+1]; char process[8*3+1];
memset(process,0,8*3+1); memset(process,0,8*3+1);
@ -2754,6 +2755,9 @@ boolean P_SetupLevel(boolean skipprecip)
I_UpdateNoVsync(); I_UpdateNoVsync();
} }
// Close text prompt before freeing the old level
F_EndTextPrompt(false, true);
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
LUA_InvalidateLevel(); LUA_InvalidateLevel();
#endif #endif

View file

@ -29,7 +29,7 @@ static pslope_t *slopelist = NULL;
static UINT16 slopecount = 0; static UINT16 slopecount = 0;
// Calculate line normal // Calculate line normal
static void P_CalculateSlopeNormal(pslope_t *slope) { void P_CalculateSlopeNormal(pslope_t *slope) {
slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT); slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x); slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x);
slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y); slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);

View file

@ -14,6 +14,7 @@
#define P_SLOPES_H__ #define P_SLOPES_H__
#ifdef ESLOPE #ifdef ESLOPE
void P_CalculateSlopeNormal(pslope_t *slope);
void P_ResetDynamicSlopes(void); void P_ResetDynamicSlopes(void);
void P_RunDynamicSlopes(void); void P_RunDynamicSlopes(void);
// P_SpawnSlope_Line // P_SpawnSlope_Line

View file

@ -35,6 +35,7 @@
#include "m_misc.h" #include "m_misc.h"
#include "m_cond.h" //unlock triggers #include "m_cond.h" //unlock triggers
#include "lua_hook.h" // LUAh_LinedefExecute #include "lua_hook.h" // LUAh_LinedefExecute
#include "f_finale.h" // control text prompt
#ifdef HW3SOUND #ifdef HW3SOUND
#include "hardware/hw3sound.h" #include "hardware/hw3sound.h"
@ -2226,8 +2227,7 @@ void P_SwitchWeather(INT32 weathernum)
for (think = thinkercap.next; think != &thinkercap; think = think->next) for (think = thinkercap.next; think != &thinkercap; think = think->next)
{ {
if ((think->function.acp1 != (actionf_p1)P_SnowThinker) if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
&& (think->function.acp1 != (actionf_p1)P_RainThinker))
continue; // not a precipmobj thinker continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think; precipmobj = (precipmobj_t *)think;
@ -2243,14 +2243,12 @@ void P_SwitchWeather(INT32 weathernum)
for (think = thinkercap.next; think != &thinkercap; think = think->next) for (think = thinkercap.next; think != &thinkercap; think = think->next)
{ {
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think;
if (swap == PRECIP_RAIN) // Snow To Rain if (swap == PRECIP_RAIN) // Snow To Rain
{ {
if (!(think->function.acp1 == (actionf_p1)P_SnowThinker
|| think->function.acp1 == (actionf_p1)P_NullPrecipThinker))
continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think;
precipmobj->flags = mobjinfo[MT_RAIN].flags; precipmobj->flags = mobjinfo[MT_RAIN].flags;
st = &states[mobjinfo[MT_RAIN].spawnstate]; st = &states[mobjinfo[MT_RAIN].spawnstate];
precipmobj->state = st; precipmobj->state = st;
@ -2261,18 +2259,13 @@ void P_SwitchWeather(INT32 weathernum)
precipmobj->precipflags &= ~PCF_INVISIBLE; precipmobj->precipflags &= ~PCF_INVISIBLE;
think->function.acp1 = (actionf_p1)P_RainThinker; precipmobj->precipflags |= PCF_RAIN;
//think->function.acp1 = (actionf_p1)P_RainThinker;
} }
else if (swap == PRECIP_SNOW) // Rain To Snow else if (swap == PRECIP_SNOW) // Rain To Snow
{ {
INT32 z; INT32 z;
if (!(think->function.acp1 == (actionf_p1)P_RainThinker
|| think->function.acp1 == (actionf_p1)P_NullPrecipThinker))
continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think;
precipmobj->flags = mobjinfo[MT_SNOWFLAKE].flags; precipmobj->flags = mobjinfo[MT_SNOWFLAKE].flags;
z = M_RandomByte(); z = M_RandomByte();
@ -2290,19 +2283,13 @@ void P_SwitchWeather(INT32 weathernum)
precipmobj->frame = st->frame; precipmobj->frame = st->frame;
precipmobj->momz = mobjinfo[MT_SNOWFLAKE].speed; precipmobj->momz = mobjinfo[MT_SNOWFLAKE].speed;
precipmobj->precipflags &= ~PCF_INVISIBLE; precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_RAIN);
think->function.acp1 = (actionf_p1)P_SnowThinker; //think->function.acp1 = (actionf_p1)P_SnowThinker;
} }
else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse. else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse.
{ {
if (!(think->function.acp1 == (actionf_p1)P_RainThinker //think->function.acp1 = (actionf_p1)P_NullPrecipThinker;
|| think->function.acp1 == (actionf_p1)P_SnowThinker))
continue;
precipmobj = (precipmobj_t *)think;
think->function.acp1 = (actionf_p1)P_NullPrecipThinker;
precipmobj->precipflags |= PCF_INVISIBLE; precipmobj->precipflags |= PCF_INVISIBLE;
} }
@ -3093,6 +3080,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS);
sector_t *sec; // Sector that the FOF is visible in sector_t *sec; // Sector that the FOF is visible in
ffloor_t *rover; // FOF that we are going to crumble ffloor_t *rover; // FOF that we are going to crumble
boolean foundrover = false; // for debug, "Can't find a FOF" message
for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;)
{ {
@ -3107,16 +3095,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
for (rover = sec->ffloors; rover; rover = rover->next) for (rover = sec->ffloors; rover; rover = rover->next)
{ {
if (rover->master->frontsector->tag == foftag) if (rover->master->frontsector->tag == foftag)
break; {
foundrover = true;
EV_CrumbleChain(sec, rover);
}
} }
if (!rover) if (!foundrover)
{ {
CONS_Debug(DBG_GAMELOGIC, "Line type 436 Executor: Can't find a FOF control sector with tag %d\n", foftag); CONS_Debug(DBG_GAMELOGIC, "Line type 436 Executor: Can't find a FOF control sector with tag %d\n", foftag);
return; return;
} }
EV_CrumbleChain(sec, rover);
} }
} }
break; break;
@ -3277,6 +3267,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS);
sector_t *sec; // Sector that the FOF is visible (or not visible) in sector_t *sec; // Sector that the FOF is visible (or not visible) in
ffloor_t *rover; // FOF to vanish/un-vanish ffloor_t *rover; // FOF to vanish/un-vanish
boolean foundrover = false; // for debug, "Can't find a FOF" message
ffloortype_e oldflags; // store FOF's old flags ffloortype_e oldflags; // store FOF's old flags
for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;)
@ -3292,26 +3283,28 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
for (rover = sec->ffloors; rover; rover = rover->next) for (rover = sec->ffloors; rover; rover = rover->next)
{ {
if (rover->master->frontsector->tag == foftag) if (rover->master->frontsector->tag == foftag)
break; {
foundrover = true;
oldflags = rover->flags;
// Abracadabra!
if (line->flags & ML_NOCLIMB)
rover->flags |= FF_EXISTS;
else
rover->flags &= ~FF_EXISTS;
// if flags changed, reset sector's light list
if (rover->flags != oldflags)
sec->moved = true;
}
} }
if (!rover) if (!foundrover)
{ {
CONS_Debug(DBG_GAMELOGIC, "Line type 445 Executor: Can't find a FOF control sector with tag %d\n", foftag); CONS_Debug(DBG_GAMELOGIC, "Line type 445 Executor: Can't find a FOF control sector with tag %d\n", foftag);
return; return;
} }
oldflags = rover->flags;
// Abracadabra!
if (line->flags & ML_NOCLIMB)
rover->flags |= FF_EXISTS;
else
rover->flags &= ~FF_EXISTS;
// if flags changed, reset sector's light list
if (rover->flags != oldflags)
sec->moved = true;
} }
} }
break; break;
@ -3322,6 +3315,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS);
sector_t *sec; // Sector that the FOF is visible in sector_t *sec; // Sector that the FOF is visible in
ffloor_t *rover; // FOF that we are going to make fall down ffloor_t *rover; // FOF that we are going to make fall down
boolean foundrover = false; // for debug, "Can't find a FOF" message
player_t *player = NULL; // player that caused FOF to fall player_t *player = NULL; // player that caused FOF to fall
boolean respawn = true; // should the fallen FOF respawn? boolean respawn = true; // should the fallen FOF respawn?
@ -3344,19 +3338,21 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
for (rover = sec->ffloors; rover; rover = rover->next) for (rover = sec->ffloors; rover; rover = rover->next)
{ {
if (rover->master->frontsector->tag == foftag) if (rover->master->frontsector->tag == foftag)
break; {
foundrover = true;
if (line->flags & ML_BLOCKMONSTERS) // FOF flags determine respawn ability instead?
respawn = !(rover->flags & FF_NORETURN) ^ !!(line->flags & ML_NOCLIMB); // no climb inverts
EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, respawn);
}
} }
if (!rover) if (!foundrover)
{ {
CONS_Debug(DBG_GAMELOGIC, "Line type 446 Executor: Can't find a FOF control sector with tag %d\n", foftag); CONS_Debug(DBG_GAMELOGIC, "Line type 446 Executor: Can't find a FOF control sector with tag %d\n", foftag);
return; return;
} }
if (line->flags & ML_BLOCKMONSTERS) // FOF flags determine respawn ability instead?
respawn = !(rover->flags & FF_NORETURN) ^ !!(line->flags & ML_NOCLIMB); // no climb inverts
EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, respawn);
} }
} }
break; break;
@ -3489,6 +3485,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS);
sector_t *sec; // Sector that the FOF is visible in sector_t *sec; // Sector that the FOF is visible in
ffloor_t *rover; // FOF that we are going to operate ffloor_t *rover; // FOF that we are going to operate
boolean foundrover = false; // for debug, "Can't find a FOF" message
for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;)
{ {
@ -3503,38 +3500,40 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
for (rover = sec->ffloors; rover; rover = rover->next) for (rover = sec->ffloors; rover; rover = rover->next)
{ {
if (rover->master->frontsector->tag == foftag) if (rover->master->frontsector->tag == foftag)
break; {
foundrover = true;
// If fading an invisible FOF whose render flags we did not yet set,
// initialize its alpha to 1
// for relative alpha calc
if (!(line->flags & ML_NOCLIMB) && // do translucent
(rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE
!(rover->spawnflags & FF_RENDERSIDES) &&
!(rover->spawnflags & FF_RENDERPLANES) &&
!(rover->flags & FF_RENDERALL))
rover->alpha = 1;
P_RemoveFakeFloorFader(rover);
P_FadeFakeFloor(rover,
rover->alpha,
max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)),
0, // set alpha immediately
false, NULL, // tic-based logic
false, // do not handle FF_EXISTS
!(line->flags & ML_NOCLIMB), // handle FF_TRANSLUCENT
false, // do not handle lighting
false, // do not handle colormap
false, // do not handle collision
false, // do not do ghost fade (no collision during fade)
true); // use exact alpha values (for opengl)
}
} }
if (!rover) if (!foundrover)
{ {
CONS_Debug(DBG_GAMELOGIC, "Line type 452 Executor: Can't find a FOF control sector with tag %d\n", foftag); CONS_Debug(DBG_GAMELOGIC, "Line type 452 Executor: Can't find a FOF control sector with tag %d\n", foftag);
return; return;
} }
// If fading an invisible FOF whose render flags we did not yet set,
// initialize its alpha to 1
// for relative alpha calc
if (!(line->flags & ML_NOCLIMB) && // do translucent
(rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE
!(rover->spawnflags & FF_RENDERSIDES) &&
!(rover->spawnflags & FF_RENDERPLANES) &&
!(rover->flags & FF_RENDERALL))
rover->alpha = 1;
P_RemoveFakeFloorFader(rover);
P_FadeFakeFloor(rover,
rover->alpha,
max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)),
0, // set alpha immediately
false, NULL, // tic-based logic
false, // do not handle FF_EXISTS
!(line->flags & ML_NOCLIMB), // handle FF_TRANSLUCENT
false, // do not handle lighting
false, // do not handle colormap
false, // do not handle collision
false, // do not do ghost fade (no collision during fade)
true); // use exact alpha values (for opengl)
} }
break; break;
} }
@ -3549,6 +3548,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS);
sector_t *sec; // Sector that the FOF is visible in sector_t *sec; // Sector that the FOF is visible in
ffloor_t *rover; // FOF that we are going to operate ffloor_t *rover; // FOF that we are going to operate
boolean foundrover = false; // for debug, "Can't find a FOF" message
size_t j = 0; // sec->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc size_t j = 0; // sec->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc
for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;)
@ -3564,64 +3564,66 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
for (rover = sec->ffloors; rover; rover = rover->next) for (rover = sec->ffloors; rover; rover = rover->next)
{ {
if (rover->master->frontsector->tag == foftag) if (rover->master->frontsector->tag == foftag)
break; {
foundrover = true;
// Prevent continuous execs from interfering on an existing fade
if (!(line->flags & ML_EFFECT5)
&& rover->fadingdata)
//&& ((fade_t*)rover->fadingdata)->timer > (ticbased ? 2 : speed*2))
{
CONS_Debug(DBG_GAMELOGIC, "Line type 453 Executor: Fade FOF thinker already exists, timer: %d\n", ((fade_t*)rover->fadingdata)->timer);
continue;
}
if (speed > 0)
P_AddFakeFloorFader(rover, secnum, j,
destvalue,
speed,
(line->flags & ML_EFFECT4), // tic-based logic
(line->flags & ML_EFFECT3), // Relative destvalue
!(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS
!(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT
!(line->flags & ML_EFFECT2), // do not handle lighting
!(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags)
!(line->flags & ML_BOUNCY), // do not handle collision
(line->flags & ML_EFFECT1), // do ghost fade (no collision during fade)
(line->flags & ML_TFERLINE)); // use exact alpha values (for opengl)
else
{
// If fading an invisible FOF whose render flags we did not yet set,
// initialize its alpha to 1
// for relative alpha calc
if (!(line->flags & ML_NOCLIMB) && // do translucent
(rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE
!(rover->spawnflags & FF_RENDERSIDES) &&
!(rover->spawnflags & FF_RENDERPLANES) &&
!(rover->flags & FF_RENDERALL))
rover->alpha = 1;
P_RemoveFakeFloorFader(rover);
P_FadeFakeFloor(rover,
rover->alpha,
max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)),
0, // set alpha immediately
false, NULL, // tic-based logic
!(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS
!(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT
!(line->flags & ML_EFFECT2), // do not handle lighting
!(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags)
!(line->flags & ML_BOUNCY), // do not handle collision
(line->flags & ML_EFFECT1), // do ghost fade (no collision during fade)
(line->flags & ML_TFERLINE)); // use exact alpha values (for opengl)
}
}
j++; j++;
} }
if (!rover) if (!foundrover)
{ {
CONS_Debug(DBG_GAMELOGIC, "Line type 453 Executor: Can't find a FOF control sector with tag %d\n", foftag); CONS_Debug(DBG_GAMELOGIC, "Line type 453 Executor: Can't find a FOF control sector with tag %d\n", foftag);
return; return;
} }
// Prevent continuous execs from interfering on an existing fade
if (!(line->flags & ML_EFFECT5)
&& rover->fadingdata)
//&& ((fade_t*)rover->fadingdata)->timer > (ticbased ? 2 : speed*2))
{
CONS_Debug(DBG_GAMELOGIC, "Line type 453 Executor: Fade FOF thinker already exists, timer: %d\n", ((fade_t*)rover->fadingdata)->timer);
continue;
}
if (speed > 0)
P_AddFakeFloorFader(rover, secnum, j,
destvalue,
speed,
(line->flags & ML_EFFECT4), // tic-based logic
(line->flags & ML_EFFECT3), // Relative destvalue
!(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS
!(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT
!(line->flags & ML_EFFECT2), // do not handle lighting
!(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags)
!(line->flags & ML_BOUNCY), // do not handle collision
(line->flags & ML_EFFECT1), // do ghost fade (no collision during fade)
(line->flags & ML_TFERLINE)); // use exact alpha values (for opengl)
else
{
// If fading an invisible FOF whose render flags we did not yet set,
// initialize its alpha to 1
// for relative alpha calc
if (!(line->flags & ML_NOCLIMB) && // do translucent
(rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE
!(rover->spawnflags & FF_RENDERSIDES) &&
!(rover->spawnflags & FF_RENDERPLANES) &&
!(rover->flags & FF_RENDERALL))
rover->alpha = 1;
P_RemoveFakeFloorFader(rover);
P_FadeFakeFloor(rover,
rover->alpha,
max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)),
0, // set alpha immediately
false, NULL, // tic-based logic
!(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS
!(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT
!(line->flags & ML_EFFECT2), // do not handle lighting
!(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags)
!(line->flags & ML_BOUNCY), // do not handle collision
(line->flags & ML_EFFECT1), // do ghost fade (no collision during fade)
(line->flags & ML_TFERLINE)); // use exact alpha values (for opengl)
}
} }
break; break;
} }
@ -3632,6 +3634,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS);
sector_t *sec; // Sector that the FOF is visible in sector_t *sec; // Sector that the FOF is visible in
ffloor_t *rover; // FOF that we are going to operate ffloor_t *rover; // FOF that we are going to operate
boolean foundrover = false; // for debug, "Can't find a FOF" message
for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;)
{ {
@ -3646,17 +3649,19 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
for (rover = sec->ffloors; rover; rover = rover->next) for (rover = sec->ffloors; rover; rover = rover->next)
{ {
if (rover->master->frontsector->tag == foftag) if (rover->master->frontsector->tag == foftag)
break; {
foundrover = true;
P_ResetFakeFloorFader(rover, NULL,
!(line->flags & ML_BLOCKMONSTERS)); // do not finalize collision flags
}
} }
if (!rover) if (!foundrover)
{ {
CONS_Debug(DBG_GAMELOGIC, "Line type 454 Executor: Can't find a FOF control sector with tag %d\n", foftag); CONS_Debug(DBG_GAMELOGIC, "Line type 454 Executor: Can't find a FOF control sector with tag %d\n", foftag);
return; return;
} }
P_ResetFakeFloorFader(rover, NULL,
!(line->flags & ML_BLOCKMONSTERS)); // do not finalize collision flags
} }
break; break;
} }
@ -3755,6 +3760,68 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
P_ResetColormapFader(&sectors[secnum]); P_ResetColormapFader(&sectors[secnum]);
break; break;
case 457: // Track mobj angle to point
if (mo)
{
INT32 failureangle = min(max(abs(sides[line->sidenum[0]].textureoffset>>FRACBITS), 0), 360) * ANG1;
INT32 failuredelay = abs(sides[line->sidenum[0]].rowoffset>>FRACBITS);
INT32 failureexectag = line->sidenum[1] != 0xffff ?
(INT32)(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0;
boolean persist = (line->flags & ML_EFFECT2);
mobj_t *anchormo;
if ((secnum = P_FindSectorFromLineTag(line, -1)) < 0)
return;
anchormo = P_GetObjectTypeInSectorNum(MT_ANGLEMAN, secnum);
if (!anchormo)
return;
mo->eflags |= MFE_TRACERANGLE;
P_SetTarget(&mo->tracer, anchormo);
mo->lastlook = persist; // don't disable behavior after first failure
mo->extravalue1 = failureangle; // angle to exceed for failure state
mo->extravalue2 = failureexectag; // exec tag for failure state (angle is not within range)
mo->cusval = mo->cvmem = failuredelay; // cusval = tics to allow failure before line trigger; cvmem = decrement timer
}
break;
case 458: // Stop tracking mobj angle to point
if (mo && (mo->eflags & MFE_TRACERANGLE))
{
mo->eflags &= ~MFE_TRACERANGLE;
P_SetTarget(&mo->tracer, NULL);
mo->lastlook = mo->cvmem = mo->cusval = mo->extravalue1 = mo->extravalue2 = 0;
}
break;
case 459: // Control Text Prompt
// console player only unless NOCLIMB is set
if (mo && mo->player && P_IsLocalPlayer(mo->player) && (!bot || bot != mo))
{
INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1);
INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1);
INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : line->tag);
boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS);
//boolean allplayers = (line->flags & ML_NOCLIMB);
boolean runpostexec = (line->flags & ML_EFFECT1);
boolean blockcontrols = !(line->flags & ML_EFFECT2);
boolean freezerealtime = !(line->flags & ML_EFFECT3);
//boolean freezethinkers = (line->flags & ML_EFFECT4);
boolean callbynamedtag = (line->flags & ML_TFERLINE);
if (closetextprompt)
F_EndTextPrompt(false, false);
else
{
if (callbynamedtag && sides[line->sidenum[0]].text && sides[line->sidenum[0]].text[0])
F_GetPromptPageByNamedTag(sides[line->sidenum[0]].text, &promptnum, &pagenum);
F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime);
}
}
break;
#ifdef POLYOBJECTS #ifdef POLYOBJECTS
case 480: // Polyobj_DoorSlide case 480: // Polyobj_DoorSlide
case 481: // Polyobj_DoorSwing case 481: // Polyobj_DoorSwing

View file

@ -56,12 +56,12 @@ void Command_Numthinkers_f(void)
CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n")); CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n"));
CONS_Printf( CONS_Printf(
"\t1: P_MobjThinker\n" "\t1: P_MobjThinker\n"
"\t2: P_RainThinker\n" /*"\t2: P_RainThinker\n"
"\t3: P_SnowThinker\n" "\t3: P_SnowThinker\n"*/
"\t4: P_NullPrecipThinker\n" "\t2: P_NullPrecipThinker\n"
"\t5: T_Friction\n" "\t3: T_Friction\n"
"\t6: T_Pusher\n" "\t4: T_Pusher\n"
"\t7: P_RemoveThinkerDelayed\n"); "\t5: P_RemoveThinkerDelayed\n");
return; return;
} }
@ -73,27 +73,27 @@ void Command_Numthinkers_f(void)
action = (actionf_p1)P_MobjThinker; action = (actionf_p1)P_MobjThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker"); CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker");
break; break;
case 2: /*case 2:
action = (actionf_p1)P_RainThinker; action = (actionf_p1)P_RainThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_RainThinker"); CONS_Printf(M_GetText("Number of %s: "), "P_RainThinker");
break; break;
case 3: case 3:
action = (actionf_p1)P_SnowThinker; action = (actionf_p1)P_SnowThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker"); CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker");
break; break;*/
case 4: case 2:
action = (actionf_p1)P_NullPrecipThinker; action = (actionf_p1)P_NullPrecipThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker"); CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker");
break; break;
case 5: case 3:
action = (actionf_p1)T_Friction; action = (actionf_p1)T_Friction;
CONS_Printf(M_GetText("Number of %s: "), "T_Friction"); CONS_Printf(M_GetText("Number of %s: "), "T_Friction");
break; break;
case 6: case 4:
action = (actionf_p1)T_Pusher; action = (actionf_p1)T_Pusher;
CONS_Printf(M_GetText("Number of %s: "), "T_Pusher"); CONS_Printf(M_GetText("Number of %s: "), "T_Pusher");
break; break;
case 7: case 5:
action = (actionf_p1)P_RemoveThinkerDelayed; action = (actionf_p1)P_RemoveThinkerDelayed;
CONS_Printf(M_GetText("Number of %s: "), "P_RemoveThinkerDelayed"); CONS_Printf(M_GetText("Number of %s: "), "P_RemoveThinkerDelayed");
break; break;

View file

@ -8777,9 +8777,15 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
subsector_t *newsubsec; subsector_t *newsubsec;
fixed_t f1, f2; fixed_t f1, f2;
cameranoclip = (player->powers[pw_carry] == CR_NIGHTSMODE || player->pflags & PF_NOCLIP) || (player->mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!! // We probably shouldn't move the camera if there is no player or player mobj somehow
if (!player || !player->mo)
return true;
if (!(player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD)) mo = player->mo;
cameranoclip = (player->powers[pw_carry] == CR_NIGHTSMODE || player->pflags & PF_NOCLIP) || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!!
if (!(player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || tutorialmode))
{ {
if (player->spectator) // force cam off for spectators if (player->spectator) // force cam off for spectators
return true; return true;
@ -8798,7 +8804,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
else if (player == &players[secondarydisplayplayer]) else if (player == &players[secondarydisplayplayer])
focusangle = localangle2; focusangle = localangle2;
else else
focusangle = player->mo->angle; focusangle = mo->angle;
if (thiscam == &camera) if (thiscam == &camera)
camrotate = cv_cam_rotate.value; camrotate = cv_cam_rotate.value;
else if (thiscam == &camera2) else if (thiscam == &camera2)
@ -8810,17 +8816,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
return true; return true;
} }
if (!player || !player->mo)
return true;
mo = player->mo;
thiscam->radius = FixedMul(20*FRACUNIT, mo->scale); thiscam->radius = FixedMul(20*FRACUNIT, mo->scale);
thiscam->height = FixedMul(16*FRACUNIT, mo->scale); thiscam->height = FixedMul(16*FRACUNIT, mo->scale);
if (!mo)
return true;
// Don't run while respawning from a starpost // Don't run while respawning from a starpost
// Inu 4/8/13 Why not?! // Inu 4/8/13 Why not?!
// if (leveltime > 0 && timeinmap <= 0) // if (leveltime > 0 && timeinmap <= 0)
@ -8828,7 +8826,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (player->powers[pw_carry] == CR_NIGHTSMODE) if (player->powers[pw_carry] == CR_NIGHTSMODE)
{ {
focusangle = player->mo->angle; focusangle = mo->angle;
focusaiming = 0; focusaiming = 0;
} }
else if (player == &players[consoleplayer]) else if (player == &players[consoleplayer])
@ -8843,14 +8841,23 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
} }
else else
{ {
focusangle = player->mo->angle; focusangle = mo->angle;
focusaiming = player->aiming; focusaiming = player->aiming;
} }
if (P_CameraThinker(player, thiscam, resetcalled)) if (P_CameraThinker(player, thiscam, resetcalled))
return true; return true;
if (thiscam == &camera) if (tutorialmode)
{
// force defaults because we have a camera look section
camspeed = (INT32)(atof(cv_cam_speed.defaultvalue) * FRACUNIT);
camstill = (!stricmp(cv_cam_still.defaultvalue, "off")) ? false : true;
camrotate = atoi(cv_cam_rotate.defaultvalue);
camdist = FixedMul((INT32)(atof(cv_cam_dist.defaultvalue) * FRACUNIT), mo->scale);
camheight = FixedMul((INT32)(atof(cv_cam_height.defaultvalue) * FRACUNIT), FixedMul(player->camerascale, mo->scale));
}
else if (thiscam == &camera)
{ {
camspeed = cv_cam_speed.value; camspeed = cv_cam_speed.value;
camstill = cv_cam_still.value; camstill = cv_cam_still.value;
@ -8890,12 +8897,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
angle = R_PointToAngle2(player->axis1->x, player->axis1->y, player->axis2->x, player->axis2->y); angle = R_PointToAngle2(player->axis1->x, player->axis1->y, player->axis2->x, player->axis2->y);
angle += ANGLE_90; angle += ANGLE_90;
} }
else if (player->mo->target) else if (mo->target)
{ {
if (player->mo->target->flags2 & MF2_AMBUSH) if (mo->target->flags2 & MF2_AMBUSH)
angle = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y); angle = R_PointToAngle2(mo->target->x, mo->target->y, mo->x, mo->y);
else else
angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y); angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y);
} }
} }
else if (P_AnalogMove(player)) // Analog else if (P_AnalogMove(player)) // Analog
@ -8984,7 +8991,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (twodlevel || (mo->flags2 & MF2_TWOD)) if (twodlevel || (mo->flags2 & MF2_TWOD))
{ {
// Camera doesn't ALWAYS need to move, only when running... // Camera doesn't ALWAYS need to move, only when running...
if (abs(player->mo->momx) > 10) if (abs(mo->momx) > 10)
{ {
// Move the camera all smooth-like, not jerk it around... // Move the camera all smooth-like, not jerk it around...
if (mo->momx > 0) if (mo->momx > 0)
@ -9291,24 +9298,20 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
// Make player translucent if camera is too close (only in single player). // Make player translucent if camera is too close (only in single player).
if (!(multiplayer || netgame) && !splitscreen) if (!(multiplayer || netgame) && !splitscreen)
{ {
fixed_t vx = 0, vy = 0; fixed_t vx = thiscam->x, vy = thiscam->y;
if (player->awayviewtics) { if (player->awayviewtics && player->awayviewmobj != NULL) // Camera must obviously exist
{
vx = player->awayviewmobj->x; vx = player->awayviewmobj->x;
vy = player->awayviewmobj->y; vy = player->awayviewmobj->y;
} }
else
{
vx = thiscam->x;
vy = thiscam->y;
}
if (P_AproxDistance(vx - player->mo->x, vy - player->mo->y) < FixedMul(48*FRACUNIT, mo->scale)) if (P_AproxDistance(vx - mo->x, vy - mo->y) < FixedMul(48*FRACUNIT, mo->scale))
player->mo->flags2 |= MF2_SHADOW; mo->flags2 |= MF2_SHADOW;
else else
player->mo->flags2 &= ~MF2_SHADOW; mo->flags2 &= ~MF2_SHADOW;
} }
else else
player->mo->flags2 &= ~MF2_SHADOW; mo->flags2 &= ~MF2_SHADOW;
/* if (!resetcalled && (player->powers[pw_carry] == CR_NIGHTSMODE && player->exiting)) /* if (!resetcalled && (player->powers[pw_carry] == CR_NIGHTSMODE && player->exiting))
{ {
@ -9623,8 +9626,9 @@ void P_PlayerThink(player_t *player)
if (player->flashcount) if (player->flashcount)
player->flashcount--; player->flashcount--;
if (player->awayviewtics) // By the time P_MoveChaseCamera is called, this might be zero. Do not do it here.
player->awayviewtics--; //if (player->awayviewtics)
// player->awayviewtics--;
/// \note do this in the cheat code /// \note do this in the cheat code
if (player->pflags & PF_NOCLIP) if (player->pflags & PF_NOCLIP)
@ -10597,6 +10601,9 @@ void P_PlayerAfterThink(player_t *player)
} }
} }
if (player->awayviewtics)
player->awayviewtics--;
// spectator invisibility and nogravity. // spectator invisibility and nogravity.
if ((netgame || multiplayer) && player->spectator) if ((netgame || multiplayer) && player->spectator)
{ {

View file

@ -261,7 +261,7 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void)
val = source[frac>>FRACBITS]; val = source[frac>>FRACBITS];
if (val != TRANSPARENTPIXEL) if (val != TRANSPARENTPIXEL)
*dest = colormap[*(transmap + (val<<8) + (*dest))]; *dest = *(transmap + (colormap[val]<<8) + (*dest));
dest += vid.width; dest += vid.width;
@ -281,12 +281,12 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void)
{ {
val = source[(frac>>FRACBITS) & heightmask]; val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL) if (val != TRANSPARENTPIXEL)
*dest = colormap[*(transmap + (val<<8) + (*dest))]; *dest = *(transmap + (colormap[val]<<8) + (*dest));
dest += vid.width; dest += vid.width;
frac += fracstep; frac += fracstep;
val = source[(frac>>FRACBITS) & heightmask]; val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL) if (val != TRANSPARENTPIXEL)
*dest = colormap[*(transmap + (val<<8) + (*dest))]; *dest = *(transmap + (colormap[val]<<8) + (*dest));
dest += vid.width; dest += vid.width;
frac += fracstep; frac += fracstep;
} }
@ -294,7 +294,7 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void)
{ {
val = source[(frac>>FRACBITS) & heightmask]; val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL) if (val != TRANSPARENTPIXEL)
*dest = colormap[*(transmap + (val<<8) + (*dest))]; *dest = *(transmap + (colormap[val]<<8) + (*dest));
} }
} }
} }

View file

@ -913,7 +913,7 @@ void R_SetupFrame(player_t *player, boolean skybox)
chasecam = (cv_chasecam.value != 0); chasecam = (cv_chasecam.value != 0);
} }
if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN) if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
chasecam = true; // force chasecam on chasecam = true; // force chasecam on
else if (player->spectator) // no spectator chasecam else if (player->spectator) // no spectator chasecam
chasecam = false; // force chasecam off chasecam = false; // force chasecam off

View file

@ -87,7 +87,7 @@ extern lighttable_t **planezlight;
extern fixed_t *yslope; extern fixed_t *yslope;
extern fixed_t distscale[MAXVIDWIDTH]; extern fixed_t distscale[MAXVIDWIDTH];
FUNCMATH void R_InitPlanes(void); void R_InitPlanes(void);
void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale); void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale);
void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale); void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale);
void R_ClearPlanes(void); void R_ClearPlanes(void);

View file

@ -63,11 +63,7 @@ typedef struct floorsplat_s
fixed_t P_SegLength(seg_t *seg); fixed_t P_SegLength(seg_t *seg);
// call at P_SetupLevel() // call at P_SetupLevel()
#if !(defined (WALLSPLATS) || defined (FLOORSPLATS))
FUNCMATH void R_ClearLevelSplats(void);
#else
void R_ClearLevelSplats(void); void R_ClearLevelSplats(void);
#endif
#ifdef WALLSPLATS #ifdef WALLSPLATS
void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top, void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top,

View file

@ -1525,6 +1525,17 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
return; return;
} }
// okay, we can't return now except for vertical clipping... this is a hack, but weather isn't networked, so it should be ok
if (!(thing->precipflags & PCF_THUNK))
{
if (thing->precipflags & PCF_RAIN)
P_RainThinker(thing);
else
P_SnowThinker(thing);
thing->precipflags |= PCF_THUNK;
}
//SoM: 3/17/2000: Disregard sprites that are out of view.. //SoM: 3/17/2000: Disregard sprites that are out of view..
gzt = thing->z + spritecachedinfo[lump].topoffset; gzt = thing->z + spritecachedinfo[lump].topoffset;
gz = gzt - spritecachedinfo[lump].height; gz = gzt - spritecachedinfo[lump].height;
@ -1642,8 +1653,10 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
if (approx_dist <= limit_dist) if (approx_dist > limit_dist)
R_ProjectSprite(thing); continue;
R_ProjectSprite(thing);
} }
} }
else else
@ -1664,8 +1677,10 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
if (approx_dist <= limit_dist) if (approx_dist > limit_dist)
R_ProjectPrecipitationSprite(precipthing); continue;
R_ProjectPrecipitationSprite(precipthing);
} }
} }
else else

View file

@ -37,6 +37,7 @@ extern INT32 msg_id;
#include "r_sky.h" // skyflatnum #include "r_sky.h" // skyflatnum
#include "p_local.h" // camera info #include "p_local.h" // camera info
#include "fastcmp.h" #include "fastcmp.h"
#include "m_misc.h" // for tunes command
#if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS) #if defined(HAVE_BLUA) && defined(HAVE_LUA_MUSICPLUS)
#include "lua_hook.h" // MusicChange hook #include "lua_hook.h" // MusicChange hook
@ -51,6 +52,8 @@ static INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, I
CV_PossibleValue_t soundvolume_cons_t[] = {{0, "MIN"}, {31, "MAX"}, {0, NULL}}; CV_PossibleValue_t soundvolume_cons_t[] = {{0, "MIN"}, {31, "MAX"}, {0, NULL}};
static void SetChannelsNum(void); static void SetChannelsNum(void);
static void Command_Tunes_f(void);
static void Command_RestartAudio_f(void);
// commands for music and sound servers // commands for music and sound servers
#ifdef MUSSERV #ifdef MUSSERV
@ -96,6 +99,7 @@ consvar_t cv_closedcaptioning = {"closedcaptioning", "Off", CV_SAVE|CV_CALL, CV_
consvar_t cv_numChannels = {"snd_channels", "32", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_numChannels = {"snd_channels", "32", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum, 0, NULL, NULL, 0, 0, NULL};
static consvar_t surround = {"surround", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t surround = {"surround", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_resetmusic = {"resetmusic", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
#if defined(HAVE_MIXERX) && !defined(HAVE_MIXER) // mixer_sound.c defines these with static handler methods #if defined(HAVE_MIXERX) && !defined(HAVE_MIXER) // mixer_sound.c defines these with static handler methods
static CV_PossibleValue_t midiplayer_cons_t[] = {{MIDI_OPNMIDI, "OPNMIDI"}, {MIDI_Fluidsynth, "Fluidsynth"}, {MIDI_Timidity, "Timidity"}, {MIDI_Native, "Native"}, {0, NULL}}; static CV_PossibleValue_t midiplayer_cons_t[] = {{MIDI_OPNMIDI, "OPNMIDI"}, {MIDI_Fluidsynth, "Fluidsynth"}, {MIDI_Timidity, "Timidity"}, {MIDI_Native, "Native"}, {0, NULL}};
@ -258,6 +262,17 @@ void S_RegisterSoundStuff(void)
#endif #endif
CV_RegisterVar(&surround); CV_RegisterVar(&surround);
CV_RegisterVar(&cv_samplerate); CV_RegisterVar(&cv_samplerate);
CV_RegisterVar(&cv_resetmusic);
COM_AddCommand("tunes", Command_Tunes_f);
COM_AddCommand("restartaudio", Command_RestartAudio_f);
#ifdef HAVE_MIXERX
CV_RegisterVar(&cv_midiplayer);
CV_RegisterVar(&cv_midisoundfontpath);
CV_RegisterVar(&cv_miditimiditypath);
#endif
#if defined (macintosh) && !defined (HAVE_SDL) // mp3 playlist stuff #if defined (macintosh) && !defined (HAVE_SDL) // mp3 playlist stuff
{ {
@ -637,7 +652,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
// Assigns the handle to one of the channels in the // Assigns the handle to one of the channels in the
// mix/output buffer. // mix/output buffer.
channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
} }
dontplay: dontplay:
@ -690,7 +705,7 @@ dontplay:
// Assigns the handle to one of the channels in the // Assigns the handle to one of the channels in the
// mix/output buffer. // mix/output buffer.
channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
} }
void S_StartSound(const void *origin, sfxenum_t sfx_id) void S_StartSound(const void *origin, sfxenum_t sfx_id)
@ -1755,3 +1770,88 @@ void S_StartEx(boolean reset)
S_StopMusic(); S_StopMusic();
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
} }
static void Command_Tunes_f(void)
{
const char *tunearg;
UINT16 tunenum, track = 0;
const size_t argc = COM_Argc();
if (argc < 2) //tunes slot ...
{
CONS_Printf("tunes <name/num> [track] [speed] / <-show> / <-default> / <-none>:\n");
CONS_Printf(M_GetText("Play an arbitrary music lump. If a map number is used, 'MAP##M' is played.\n"));
CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n\n"));
CONS_Printf(M_GetText("* With \"-show\", shows the currently playing tune and track.\n"));
CONS_Printf(M_GetText("* With \"-default\", returns to the default music for the map.\n"));
CONS_Printf(M_GetText("* With \"-none\", any music playing will be stopped.\n"));
return;
}
tunearg = COM_Argv(1);
tunenum = (UINT16)atoi(tunearg);
track = 0;
if (!strcasecmp(tunearg, "-show"))
{
CONS_Printf(M_GetText("The current tune is: %s [track %d]\n"),
mapmusname, (mapmusflags & MUSIC_TRACKMASK));
return;
}
if (!strcasecmp(tunearg, "-none"))
{
S_StopMusic();
return;
}
else if (!strcasecmp(tunearg, "-default"))
{
tunearg = mapheaderinfo[gamemap-1]->musname;
track = mapheaderinfo[gamemap-1]->mustrack;
}
else if (!tunearg[2] && toupper(tunearg[0]) >= 'A' && toupper(tunearg[0]) <= 'Z')
tunenum = (UINT16)M_MapNumber(tunearg[0], tunearg[1]);
if (tunenum && tunenum >= 1036)
{
CONS_Alert(CONS_NOTICE, M_GetText("Valid music slots are 1 to 1035.\n"));
return;
}
if (!tunenum && strlen(tunearg) > 6) // This is automatic -- just show the error just in case
CONS_Alert(CONS_NOTICE, M_GetText("Music name too long - truncated to six characters.\n"));
if (argc > 2)
track = (UINT16)atoi(COM_Argv(2))-1;
if (tunenum)
snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum));
else
strncpy(mapmusname, tunearg, 7);
mapmusname[6] = 0;
mapmusflags = (track & MUSIC_TRACKMASK);
S_ChangeMusic(mapmusname, mapmusflags, true);
if (argc > 3)
{
float speed = (float)atof(COM_Argv(3));
if (speed > 0.0f)
S_SpeedMusic(speed);
}
}
static void Command_RestartAudio_f(void)
{
S_StopMusic();
S_StopSounds();
I_ShutdownMusic();
I_ShutdownSound();
I_StartupSound();
I_InitMusic();
// These must be called or no sound and music until manually set.
I_SetSfxVolume(cv_soundvolume.value);
S_SetMusicVolume(cv_digmusicvolume.value, cv_midimusicvolume.value);
if (Playing()) // Gotta make sure the player is in a level
P_RestoreMusic(&players[consoleplayer]);
}

View file

@ -26,6 +26,7 @@
extern consvar_t stereoreverse; extern consvar_t stereoreverse;
extern consvar_t cv_soundvolume, cv_closedcaptioning, cv_digmusicvolume, cv_midimusicvolume; extern consvar_t cv_soundvolume, cv_closedcaptioning, cv_digmusicvolume, cv_midimusicvolume;
extern consvar_t cv_numChannels; extern consvar_t cv_numChannels;
extern consvar_t cv_resetmusic;
#ifdef HAVE_MIXERX #ifdef HAVE_MIXERX
extern consvar_t cv_midiplayer; extern consvar_t cv_midiplayer;

View file

@ -69,11 +69,7 @@ consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE, CV_Unsigned, NULL, 0, N
consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#ifdef DIRECTFULLSCREEN
static FUNCMATH void SCR_ChangeFullscreen (void);
#else
static void SCR_ChangeFullscreen (void); static void SCR_ChangeFullscreen (void);
#endif
consvar_t cv_fullscreen = {"fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fullscreen = {"fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen, 0, NULL, NULL, 0, 0, NULL};

View file

@ -12,19 +12,19 @@ consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NUL
consvar_t cdUpdate = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cdUpdate = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
FUNCMATH void I_InitCD(void){} void I_InitCD(void){}
FUNCMATH void I_StopCD(void){} void I_StopCD(void){}
FUNCMATH void I_PauseCD(void){} void I_PauseCD(void){}
FUNCMATH void I_ResumeCD(void){} void I_ResumeCD(void){}
FUNCMATH void I_ShutdownCD(void){} void I_ShutdownCD(void){}
FUNCMATH void I_UpdateCD(void){} void I_UpdateCD(void){}
FUNCMATH void I_PlayCD(UINT8 track, UINT8 looping) void I_PlayCD(UINT8 track, UINT8 looping)
{ {
(void)track; (void)track;
(void)looping; (void)looping;

View file

@ -1,8 +1,11 @@
// Emacs style mode select -*- C++ -*- // Emacs style mode select -*- C++ -*-
//
// SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Portions Copyright (C) 1998-2000 by DooM Legacy Team. // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2014-2018 by Sonic Team Junior.
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -124,6 +127,10 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
#include "macosx/mac_resources.h" #include "macosx/mac_resources.h"
#endif #endif
#ifndef errno
#include <errno.h>
#endif
// Locations for searching the srb2.pk3 // Locations for searching the srb2.pk3
#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
#define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2" #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2"
@ -1149,6 +1156,7 @@ static void I_ShutdownJoystick2(void)
D_PostEvent(&event); D_PostEvent(&event);
} }
joystick2_started = 0;
JoyReset(&JoyInfo2); JoyReset(&JoyInfo2);
if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
{ {
@ -1678,7 +1686,7 @@ static void I_ShutdownMouse2(void)
EscapeCommFunction(mouse2filehandle, CLRRTS); EscapeCommFunction(mouse2filehandle, CLRRTS);
PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT | PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR); PURGE_TXCLEAR | PURGE_RXCLEAR);
CloseHandle(mouse2filehandle); CloseHandle(mouse2filehandle);
@ -1871,11 +1879,11 @@ void I_StartupMouse2(void)
{ {
// COM file handle // COM file handle
mouse2filehandle = CreateFileA(cv_mouse2port.string, GENERIC_READ | GENERIC_WRITE, mouse2filehandle = CreateFileA(cv_mouse2port.string, GENERIC_READ | GENERIC_WRITE,
0, // exclusive access 0, // exclusive access
NULL, // no security attrs NULL, // no security attrs
OPEN_EXISTING, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
NULL); NULL);
if (mouse2filehandle == INVALID_HANDLE_VALUE) if (mouse2filehandle == INVALID_HANDLE_VALUE)
{ {
INT32 e = GetLastError(); INT32 e = GetLastError();
@ -1895,7 +1903,7 @@ void I_StartupMouse2(void)
// purge buffers // purge buffers
PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT
| PURGE_TXCLEAR | PURGE_RXCLEAR); | PURGE_TXCLEAR | PURGE_RXCLEAR);
// setup port to 1200 7N1 // setup port to 1200 7N1
dcb.DCBlength = sizeof (DCB); dcb.DCBlength = sizeof (DCB);
@ -1921,14 +1929,14 @@ void I_StartupMouse2(void)
// //
// I_Tactile // I_Tactile
// //
FUNCMATH void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect) void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect)
{ {
// UNUSED. // UNUSED.
(void)pFFType; (void)pFFType;
(void)FFEffect; (void)FFEffect;
} }
FUNCMATH void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect) void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
{ {
// UNUSED. // UNUSED.
(void)pFFType; (void)pFFType;
@ -1939,7 +1947,7 @@ FUNCMATH void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
*/ */
static ticcmd_t emptycmd; static ticcmd_t emptycmd;
FUNCMATH ticcmd_t *I_BaseTiccmd(void) ticcmd_t *I_BaseTiccmd(void)
{ {
return &emptycmd; return &emptycmd;
} }
@ -1948,7 +1956,7 @@ FUNCMATH ticcmd_t *I_BaseTiccmd(void)
*/ */
static ticcmd_t emptycmd2; static ticcmd_t emptycmd2;
FUNCMATH ticcmd_t *I_BaseTiccmd2(void) ticcmd_t *I_BaseTiccmd2(void)
{ {
return &emptycmd2; return &emptycmd2;
} }
@ -2024,7 +2032,7 @@ static void I_ShutdownTimer(void)
tic_t I_GetTime (void) tic_t I_GetTime (void)
{ {
static Uint32 basetime = 0; static Uint32 basetime = 0;
Uint32 ticks = SDL_GetTicks(); Uint32 ticks = SDL_GetTicks();
if (!basetime) if (!basetime)
basetime = ticks; basetime = ticks;
@ -2042,7 +2050,7 @@ tic_t I_GetTime (void)
// //
//I_StartupTimer //I_StartupTimer
// //
FUNCMATH void I_StartupTimer(void) void I_StartupTimer(void)
{ {
#ifdef _WIN32 #ifdef _WIN32
// for win2k time bug // for win2k time bug
@ -2090,7 +2098,6 @@ INT32 I_StartupSystem(void)
return 0; return 0;
} }
// //
// I_Quit // I_Quit
// //
@ -2142,11 +2149,11 @@ void I_WaitVBL(INT32 count)
SDL_Delay(count); SDL_Delay(count);
} }
FUNCMATH void I_BeginRead(void) void I_BeginRead(void)
{ {
} }
FUNCMATH void I_EndRead(void) void I_EndRead(void)
{ {
} }
@ -2369,7 +2376,7 @@ void I_GetDiskFreeSpace(INT64 *freespace)
{ {
DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters; DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;
GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector, GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector,
&NumberOfFreeClusters, &TotalNumberOfClusters); &NumberOfFreeClusters, &TotalNumberOfClusters);
*freespace = BytesPerSector*SectorsPerCluster*NumberOfFreeClusters; *freespace = BytesPerSector*SectorsPerCluster*NumberOfFreeClusters;
} }
#else // Dummy for platform independent; 1GB should be enough #else // Dummy for platform independent; 1GB should be enough
@ -2576,22 +2583,22 @@ static const char *locateWad(void)
#ifdef CMAKECONFIG #ifdef CMAKECONFIG
#ifndef NDEBUG #ifndef NDEBUG
I_OutputMsg(","CMAKE_ASSETS_DIR); I_OutputMsg(","CMAKE_ASSETS_DIR);
strcpy(returnWadPath, CMAKE_ASSETS_DIR); strcpy(returnWadPath, CMAKE_ASSETS_DIR);
if (isWadPathOk(returnWadPath)) if (isWadPathOk(returnWadPath))
{ {
return returnWadPath; return returnWadPath;
} }
#endif #endif
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
OSX_GetResourcesPath(returnWadPath); OSX_GetResourcesPath(returnWadPath);
I_OutputMsg(",%s", returnWadPath); I_OutputMsg(",%s", returnWadPath);
if (isWadPathOk(returnWadPath)) if (isWadPathOk(returnWadPath))
{ {
return returnWadPath; return returnWadPath;
} }
#endif #endif
// examine default dirs // examine default dirs
@ -2696,7 +2703,30 @@ const char *I_LocateWad(void)
#ifdef __linux__ #ifdef __linux__
#define MEMINFO_FILE "/proc/meminfo" #define MEMINFO_FILE "/proc/meminfo"
#define MEMTOTAL "MemTotal:" #define MEMTOTAL "MemTotal:"
#define MEMAVAILABLE "MemAvailable:"
#define MEMFREE "MemFree:" #define MEMFREE "MemFree:"
#define CACHED "Cached:"
#define BUFFERS "Buffers:"
#define SHMEM "Shmem:"
/* Parse the contents of /proc/meminfo (in buf), return value of "name"
* (example: MemTotal) */
static long get_entry(const char* name, const char* buf)
{
long val;
char* hit = strstr(buf, name);
if (hit == NULL) {
return -1;
}
errno = 0;
val = strtol(hit + strlen(name), NULL, 10);
if (errno != 0) {
CONS_Alert(CONS_ERROR, M_GetText("get_entry: strtol() failed: %s\n"), strerror(errno));
return -1;
}
return val;
}
#endif #endif
// quick fix for compil // quick fix for compil
@ -2758,6 +2788,11 @@ UINT32 I_GetFreeMem(UINT32 *total)
UINT32 totalKBytes; UINT32 totalKBytes;
INT32 n; INT32 n;
INT32 meminfo_fd = -1; INT32 meminfo_fd = -1;
long Cached;
long MemFree;
long Buffers;
long Shmem;
long MemAvailable = -1;
meminfo_fd = open(MEMINFO_FILE, O_RDONLY); meminfo_fd = open(MEMINFO_FILE, O_RDONLY);
n = read(meminfo_fd, buf, 1023); n = read(meminfo_fd, buf, 1023);
@ -2783,16 +2818,28 @@ UINT32 I_GetFreeMem(UINT32 *total)
memTag += sizeof (MEMTOTAL); memTag += sizeof (MEMTOTAL);
totalKBytes = atoi(memTag); totalKBytes = atoi(memTag);
if ((memTag = strstr(buf, MEMFREE)) == NULL) if ((memTag = strstr(buf, MEMAVAILABLE)) == NULL)
{ {
// Error Cached = get_entry(CACHED, buf);
if (total) MemFree = get_entry(MEMFREE, buf);
*total = 0L; Buffers = get_entry(BUFFERS, buf);
return 0; Shmem = get_entry(SHMEM, buf);
} MemAvailable = Cached + MemFree + Buffers - Shmem;
memTag += sizeof (MEMFREE); if (MemAvailable == -1)
freeKBytes = atoi(memTag); {
// Error
if (total)
*total = 0L;
return 0;
}
freeKBytes = MemAvailable;
}
else
{
memTag += sizeof (MEMAVAILABLE);
freeKBytes = atoi(memTag);
}
if (total) if (total)
*total = totalKBytes << 10; *total = totalKBytes << 10;
@ -2869,5 +2916,5 @@ const CPUInfoFlags *I_CPUInfo(void)
} }
// note CPUAFFINITY code used to reside here // note CPUAFFINITY code used to reside here
FUNCMATH void I_RegisterSysCommands(void) {} void I_RegisterSysCommands(void) {}
#endif #endif

View file

@ -1,8 +1,10 @@
// Emacs style mode select -*- C++ -*- // Emacs style mode select -*- C++ -*-
// SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Portions Copyright (C) 1998-2000 by DooM Legacy Team. // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 2014-2018 by Sonic Team Junior.
// //
// This program is free software; you can redistribute it and/or // This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License // modify it under the terms of the GNU General Public License
@ -1057,7 +1059,7 @@ void I_SetPalette(RGBA_t *palette)
} }
// return number of fullscreen + X11 modes // return number of fullscreen + X11 modes
FUNCMATH INT32 VID_NumModes(void) INT32 VID_NumModes(void)
{ {
if (USE_FULLSCREEN && numVidModes != -1) if (USE_FULLSCREEN && numVidModes != -1)
return numVidModes - firstEntry; return numVidModes - firstEntry;
@ -1065,7 +1067,7 @@ FUNCMATH INT32 VID_NumModes(void)
return MAXWINMODES; return MAXWINMODES;
} }
FUNCMATH const char *VID_GetModeName(INT32 modeNum) const char *VID_GetModeName(INT32 modeNum)
{ {
#if 0 #if 0
if (USE_FULLSCREEN && numVidModes != -1) // fullscreen modes if (USE_FULLSCREEN && numVidModes != -1) // fullscreen modes
@ -1095,7 +1097,7 @@ FUNCMATH const char *VID_GetModeName(INT32 modeNum)
return &vidModeName[modeNum][0]; return &vidModeName[modeNum][0];
} }
FUNCMATH INT32 VID_GetModeForSize(INT32 w, INT32 h) INT32 VID_GetModeForSize(INT32 w, INT32 h)
{ {
int i; int i;
for (i = 0; i < MAXWINMODES; i++) for (i = 0; i < MAXWINMODES; i++)

View file

@ -1,3 +1,11 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2014-2018 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file /// \file
/// \brief SDL Mixer interface for sound /// \brief SDL Mixer interface for sound
@ -49,10 +57,8 @@
#include "gme/gme.h" #include "gme/gme.h"
#define GME_TREBLE 5.0 #define GME_TREBLE 5.0
#define GME_BASS 1.0 #define GME_BASS 1.0
#ifdef HAVE_PNG /// TODO: compile with zlib support without libpng
#define HAVE_ZLIB
#ifdef HAVE_ZLIB
#ifndef _MSC_VER #ifndef _MSC_VER
#ifndef _LARGEFILE64_SOURCE #ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE
@ -68,8 +74,8 @@
#endif #endif
#include "zlib.h" #include "zlib.h"
#endif #endif // HAVE_ZLIB
#endif #endif // HAVE_LIBGME
UINT8 sound_started = false; UINT8 sound_started = false;
@ -250,7 +256,7 @@ void I_ShutdownSound(void)
#endif #endif
} }
FUNCMATH void I_UpdateSound(void) void I_UpdateSound(void)
{ {
} }
@ -306,7 +312,7 @@ static Mix_Chunk *ds2chunk(void *stream)
return NULL; // would and/or did wrap, can't store. return NULL; // would and/or did wrap, can't store.
break; break;
} }
sound = malloc(newsamples<<2); // samples * frequency shift * bytes per sample * channels sound = Z_Malloc(newsamples<<2, PU_SOUND, NULL); // samples * frequency shift * bytes per sample * channels
s = (SINT8 *)stream; s = (SINT8 *)stream;
d = (INT16 *)sound; d = (INT16 *)sound;
@ -374,6 +380,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
{ {
void *lump; void *lump;
Mix_Chunk *chunk; Mix_Chunk *chunk;
SDL_RWops *rw;
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
Music_Emu *emu; Music_Emu *emu;
gme_info_t *info; gme_info_t *info;
@ -490,7 +497,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
} }
Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up
#else #else
//CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); return NULL; // No zlib support
#endif #endif
} }
// Try to read it as a GME sound // Try to read it as a GME sound
@ -517,21 +524,43 @@ void *I_GetSfx(sfxinfo_t *sfx)
#endif #endif
// Try to load it as a WAVE or OGG using Mixer. // Try to load it as a WAVE or OGG using Mixer.
return Mix_LoadWAV_RW(SDL_RWFromMem(lump, sfx->length), 1); rw = SDL_RWFromMem(lump, sfx->length);
if (rw != NULL)
{
chunk = Mix_LoadWAV_RW(rw, 1);
return chunk;
}
return NULL; // haven't been able to get anything
} }
void I_FreeSfx(sfxinfo_t *sfx) void I_FreeSfx(sfxinfo_t *sfx)
{ {
if (sfx->data) if (sfx->data)
{
Mix_Chunk *chunk = (Mix_Chunk*)sfx->data;
UINT8 *abufdata = NULL;
if (chunk->allocated == 0)
{
// We allocated the data in this chunk, so get the abuf from mixer, then let it free the chunk, THEN we free the data
// I believe this should ensure the sound is not playing when we free it
abufdata = chunk->abuf;
}
Mix_FreeChunk(sfx->data); Mix_FreeChunk(sfx->data);
if (abufdata)
{
// I'm going to assume we used Z_Malloc to allocate this data.
Z_Free(abufdata);
}
}
sfx->data = NULL; sfx->data = NULL;
sfx->lumpnum = LUMPERROR; sfx->lumpnum = LUMPERROR;
} }
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
{ {
UINT8 volume = (((UINT16)vol + 1) * (UINT16)sfx_volume) / 62; // (256 * 31) / 62 == 127 UINT8 volume = (((UINT16)vol + 1) * (UINT16)sfx_volume) / 62; // (256 * 31) / 62 == 127
INT32 handle = Mix_PlayChannel(-1, S_sfx[id].data, 0); INT32 handle = Mix_PlayChannel(channel, S_sfx[id].data, 0);
Mix_Volume(handle, volume); Mix_Volume(handle, volume);
Mix_SetPanning(handle, min((UINT16)(0xff-sep)<<1, 0xff), min((UINT16)(sep)<<1, 0xff)); Mix_SetPanning(handle, min((UINT16)(0xff-sep)<<1, 0xff), min((UINT16)(sep)<<1, 0xff));
(void)pitch; // Mixer can't handle pitch (void)pitch; // Mixer can't handle pitch
@ -686,7 +715,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
/// Music System /// Music System
/// ------------------------ /// ------------------------
FUNCMATH void I_InitMusic(void) void I_InitMusic(void)
{ {
} }
@ -987,6 +1016,7 @@ boolean I_LoadSong(char *data, size_t len)
size_t wstart, wp; size_t wstart, wp;
char *p = data; char *p = data;
SDL_RWops *rw;
if (music if (music
#ifdef HAVE_LIBGME #ifdef HAVE_LIBGME
@ -1082,7 +1112,8 @@ boolean I_LoadSong(char *data, size_t len)
} }
Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up
#else #else
//CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n");
return true;
#endif #endif
} }
else if (!gme_open_data(data, len, &gme, 44100)) else if (!gme_open_data(data, len, &gme, 44100))
@ -1101,7 +1132,10 @@ boolean I_LoadSong(char *data, size_t len)
Mix_Timidity_addToPathList(cv_miditimiditypath.string); // this overwrites previous custom path Mix_Timidity_addToPathList(cv_miditimiditypath.string); // this overwrites previous custom path
#endif #endif
music = Mix_LoadMUS_RW(SDL_RWFromMem(data, len), SDL_FALSE); rw = SDL_RWFromMem(data, len);
{
music = Mix_LoadMUS_RW(rw, 1);
}
if (!music) if (!music)
{ {
CONS_Alert(CONS_ERROR, "Mix_LoadMUS_RW: %s\n", Mix_GetError()); CONS_Alert(CONS_ERROR, "Mix_LoadMUS_RW: %s\n", Mix_GetError());
@ -1149,6 +1183,7 @@ boolean I_LoadSong(char *data, size_t len)
song_length = (float)(atoi(p) / 1000.0L); song_length = (float)(atoi(p) / 1000.0L);
} }
// below: search MP3 or other tags that use wide char encoding // below: search MP3 or other tags that use wide char encoding
// \todo this isn't actually how MP3 stores its tags. We're just using endian markers as context clues.
else if (!loop_point && !memcmp(p, key1w, key1len*2)) // LOOP wide char else if (!loop_point && !memcmp(p, key1w, key1len*2)) // LOOP wide char
{ {
p += key1len*2; p += key1len*2;

View file

@ -219,7 +219,7 @@ static void Snd_UnlockAudio(void) //Alam: Unlock audio data and reinstall audio
#endif #endif
} }
FUNCMATH static inline Uint16 Snd_LowerRate(Uint16 sr) static inline Uint16 Snd_LowerRate(Uint16 sr)
{ {
if (sr <= audio.freq) // already lowered rate? if (sr <= audio.freq) // already lowered rate?
return sr; // good then return sr; // good then
@ -604,10 +604,11 @@ void I_FreeSfx(sfxinfo_t * sfx)
// Pitching (that is, increased speed of playback) // Pitching (that is, increased speed of playback)
// is set, but currently not used by mixing. // is set, but currently not used by mixing.
// //
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
{ {
(void)priority; (void)priority;
(void)pitch; (void)pitch;
(void)channel;
if (sound_disabled) if (sound_disabled)
return 0; return 0;
@ -1350,12 +1351,12 @@ musictype_t I_SongType(void)
boolean I_SongPlaying(void) boolean I_SongPlaying(void)
{ {
return musicStarted; return false;
} }
boolean I_SongPaused(void) boolean I_SongPaused(void)
{ {
return Mix_PausedMusic(); return false;
} }
/// ------------------------ /// ------------------------
@ -1379,8 +1380,8 @@ UINT32 I_GetSongLength(void)
boolean I_SetSongLoopPoint(UINT32 looppoint) boolean I_SetSongLoopPoint(UINT32 looppoint)
{ {
(void)looppoint; (void)looppoint;
return false; return false;
} }
UINT32 I_GetSongLoopPoint(void) UINT32 I_GetSongLoopPoint(void)

View file

@ -603,6 +603,9 @@ static void ST_drawDebugInfo(void)
static void ST_drawScore(void) static void ST_drawScore(void)
{ {
if (F_GetPromptHideHud(hudinfo[HUD_SCORE].y))
return;
// SCORE: // SCORE:
ST_DrawPatchFromHud(HUD_SCORE, sboscore, V_HUDTRANS); ST_DrawPatchFromHud(HUD_SCORE, sboscore, V_HUDTRANS);
if (objectplacing) if (objectplacing)
@ -712,6 +715,9 @@ static void ST_drawTime(void)
tictrn = G_TicsToCentiseconds(tics); tictrn = G_TicsToCentiseconds(tics);
} }
if (F_GetPromptHideHud(hudinfo[HUD_TIME].y))
return;
// TIME: // TIME:
ST_DrawPatchFromHud(HUD_TIME, ((downwards && (tics < 30*TICRATE) && (leveltime/5 & 1)) ? sboredtime : sbotime), V_HUDTRANS); ST_DrawPatchFromHud(HUD_TIME, ((downwards && (tics < 30*TICRATE) && (leveltime/5 & 1)) ? sboredtime : sbotime), V_HUDTRANS);
@ -738,6 +744,9 @@ static inline void ST_drawRings(void)
{ {
INT32 ringnum; INT32 ringnum;
if (F_GetPromptHideHud(hudinfo[HUD_RINGS].y))
return;
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));
ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0)); ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0));
@ -756,6 +765,9 @@ static void ST_drawLivesArea(void)
if (!stplyr->skincolor) if (!stplyr->skincolor)
return; // Just joined a server, skin isn't loaded yet! return; // Just joined a server, skin isn't loaded yet!
if (F_GetPromptHideHud(hudinfo[HUD_LIVES].y))
return;
// face background // face background
V_DrawSmallScaledPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y, V_DrawSmallScaledPatch(hudinfo[HUD_LIVES].x, hudinfo[HUD_LIVES].y,
hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, livesback); hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, livesback);
@ -927,6 +939,9 @@ static void ST_drawInput(void)
if (stplyr->powers[pw_carry] == CR_NIGHTSMODE) if (stplyr->powers[pw_carry] == CR_NIGHTSMODE)
y -= 16; y -= 16;
if (F_GetPromptHideHud(y))
return;
// O backing // O backing
V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_LIVES].f|20); V_DrawFill(x, y-1, 16, 16, hudinfo[HUD_LIVES].f|20);
V_DrawFill(x, y+15, 16, 1, hudinfo[HUD_LIVES].f|29); V_DrawFill(x, y+15, 16, 1, hudinfo[HUD_LIVES].f|29);
@ -1202,6 +1217,9 @@ static void ST_drawPowerupHUD(void)
static INT32 flagoffs[2] = {0, 0}, shieldoffs[2] = {0, 0}; static INT32 flagoffs[2] = {0, 0}, shieldoffs[2] = {0, 0};
#define ICONSEP (16+4) // matches weapon rings HUD #define ICONSEP (16+4) // matches weapon rings HUD
if (F_GetPromptHideHud(hudinfo[HUD_POWERUPS].y))
return;
if (stplyr->spectator || stplyr->playerstate != PST_LIVE) if (stplyr->spectator || stplyr->playerstate != PST_LIVE)
return; return;
@ -1364,7 +1382,7 @@ static void ST_drawFirstPersonHUD(void)
p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); p = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
// Display the countdown drown numbers! // Display the countdown drown numbers!
if (p) if (p && !F_GetPromptHideHud(60 - SHORT(p->topoffset)))
V_DrawScaledPatch((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset), V_DrawScaledPatch((BASEVIDWIDTH/2) - (SHORT(p->width)/2) + SHORT(p->leftoffset), 60 - SHORT(p->topoffset),
V_PERPLAYER|V_PERPLAYER|V_TRANSLUCENT, p); V_PERPLAYER|V_PERPLAYER|V_TRANSLUCENT, p);
} }
@ -1908,6 +1926,9 @@ static void ST_drawMatchHUD(void)
const INT32 y = 176; // HUD_LIVES const INT32 y = 176; // HUD_LIVES
INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6;
if (F_GetPromptHideHud(y))
return;
if (!G_RingSlingerGametype()) if (!G_RingSlingerGametype())
return; return;
@ -1954,6 +1975,9 @@ static void ST_drawTextHUD(void)
y -= 8;\ y -= 8;\
} }
if (F_GetPromptHideHud(y))
return;
if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator))
{ {
if (leveltime < hidetime * TICRATE) if (leveltime < hidetime * TICRATE)
@ -2087,6 +2111,9 @@ static void ST_drawTeamHUD(void)
patch_t *p; patch_t *p;
#define SEP 20 #define SEP 20
if (F_GetPromptHideHud(0)) // y base is 0
return;
if (gametype == GT_CTF) if (gametype == GT_CTF)
p = bflagico; p = bflagico;
else else
@ -2200,7 +2227,8 @@ static INT32 ST_drawEmeraldHuntIcon(mobj_t *hunt, patch_t **patches, INT32 offse
interval = 0; interval = 0;
} }
V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, hudinfo[HUD_HUNTPICS].f|V_PERPLAYER|V_HUDTRANS, patches[i]); if (!F_GetPromptHideHud(hudinfo[HUD_HUNTPICS].y))
V_DrawScaledPatch(hudinfo[HUD_HUNTPICS].x+offset, hudinfo[HUD_HUNTPICS].y, hudinfo[HUD_HUNTPICS].f|V_PERPLAYER|V_HUDTRANS, patches[i]);
return interval; return interval;
} }
@ -2298,7 +2326,8 @@ 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 || G_IsSpecialStage(gamemap)) if ((maptol & TOL_NIGHTS || G_IsSpecialStage(gamemap)) &&
!F_GetPromptHideHudAll())
ST_drawNiGHTSHUD(); ST_drawNiGHTSHUD();
else else
{ {

View file

@ -24,7 +24,7 @@
// //
// Called by main loop. // Called by main loop.
FUNCMATH void ST_Ticker(void); void ST_Ticker(void);
// Called by main loop. // Called by main loop.
void ST_Drawer(void); void ST_Drawer(void);

View file

@ -532,7 +532,6 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
{ {
UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
UINT32 alphalevel = 0; UINT32 alphalevel = 0;
boolean flip = false;
fixed_t col, ofs, colfrac, rowfrac, fdup; fixed_t col, ofs, colfrac, rowfrac, fdup;
INT32 dupx, dupy; INT32 dupx, dupy;
@ -610,22 +609,32 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
colfrac = FixedDiv(FRACUNIT, fdup); colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, fdup); rowfrac = FixedDiv(FRACUNIT, fdup);
if (scrn & V_OFFSET) // Crosshair shit // So it turns out offsets aren't scaled in V_NOSCALESTART unless V_OFFSET is applied ...poo, that's terrible
// For now let's just at least give V_OFFSET the ability to support V_FLIP
// I'll probably make a better fix for 2.2 where I don't have to worry about breaking existing support for stuff
// -- Monster Iestyn 29/10/18
{ {
y -= FixedMul((SHORT(patch->topoffset)*dupy)<<FRACBITS, pscale); fixed_t offsetx = 0, offsety = 0;
x -= FixedMul((SHORT(patch->leftoffset)*dupx)<<FRACBITS, pscale);
}
else
{
y -= FixedMul(SHORT(patch->topoffset)<<FRACBITS, pscale);
// left offset
if (scrn & V_FLIP) if (scrn & V_FLIP)
{ offsetx = FixedMul((SHORT(patch->width) - SHORT(patch->leftoffset))<<FRACBITS, pscale) + 1;
flip = true;
x -= FixedMul((SHORT(patch->width) - SHORT(patch->leftoffset))<<FRACBITS, pscale) + 1;
}
else else
x -= FixedMul(SHORT(patch->leftoffset)<<FRACBITS, pscale); offsetx = FixedMul(SHORT(patch->leftoffset)<<FRACBITS, pscale);
// top offset
// TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!?
offsety = FixedMul(SHORT(patch->topoffset)<<FRACBITS, pscale);
if ((scrn & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs
{
offsetx = FixedMul(offsetx, dupx<<FRACBITS);
offsety = FixedMul(offsety, dupy<<FRACBITS);
}
// Subtract the offsets from x/y positions
x -= offsetx;
y -= offsety;
} }
if (splitscreen && (scrn & V_PERPLAYER)) if (splitscreen && (scrn & V_PERPLAYER))
@ -774,7 +783,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, ++offx, desttop++) for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, ++offx, desttop++)
{ {
INT32 topdelta, prevdelta = -1; INT32 topdelta, prevdelta = -1;
if (flip) // offx is measured from right edge instead of left if (scrn & V_FLIP) // offx is measured from right edge instead of left
{ {
if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION) if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
break; break;
@ -798,7 +807,7 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
prevdelta = topdelta; prevdelta = topdelta;
source = (const UINT8 *)(column) + 3; source = (const UINT8 *)(column) + 3;
dest = desttop; dest = desttop;
if (flip) if (scrn & V_FLIP)
dest = deststart + (destend - desttop); dest = deststart + (destend - desttop);
dest += FixedInt(FixedMul(topdelta<<FRACBITS,fdup))*vid.width; dest += FixedInt(FixedMul(topdelta<<FRACBITS,fdup))*vid.width;
@ -1045,7 +1054,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
// //
void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor) void V_DrawContinueIcon(INT32 x, INT32 y, INT32 flags, INT32 skinnum, UINT8 skincolor)
{ {
if (skins[skinnum].flags & SF_HIRES) if (skinnum < 0 || skinnum >= numskins || (skins[skinnum].flags & SF_HIRES))
V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE));
else else
{ {
@ -1480,6 +1489,49 @@ void V_DrawFadeConsBack(INT32 plines)
*buf = consolebgmap[*buf]; *buf = consolebgmap[*buf];
} }
// Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom.
void V_DrawPromptBack(INT32 boxheight, INT32 color)
{
UINT8 *deststop, *buf;
boxheight *= vid.dupy;
if (color == INT32_MAX)
color = cons_backcolor.value;
#ifdef HWRENDER
if (rendermode != render_soft && rendermode != render_none)
{
UINT32 hwcolor;
switch (color)
{
case 0: hwcolor = 0xffffff00; break; // White
case 1: hwcolor = 0x00000000; break; // Gray // Note this is different from V_DrawFadeConsBack
case 2: hwcolor = 0x40201000; break; // Brown
case 3: hwcolor = 0xff000000; break; // Red
case 4: hwcolor = 0xff800000; break; // Orange
case 5: hwcolor = 0x80800000; break; // Yellow
case 6: hwcolor = 0x00800000; break; // Green
case 7: hwcolor = 0x0000ff00; break; // Blue
case 8: hwcolor = 0x4080ff00; break; // Cyan
// Default green
default: hwcolor = 0x00800000; break;
}
HWR_DrawTutorialBack(hwcolor, boxheight);
return;
}
#endif
CON_SetupBackColormapEx(color, true);
// heavily simplified -- we don't need to know x or y position,
// just the start and stop positions
deststop = screens[0] + vid.rowbytes * vid.height;
buf = deststop - vid.rowbytes * ((boxheight * 4) + (boxheight/2)*5); // 4 lines of space plus gaps between and some leeway
for (; buf < deststop; ++buf)
*buf = promptbgmap[*buf];
}
// Gets string colormap, used for 0x80 color codes // Gets string colormap, used for 0x80 color codes
// //
static const UINT8 *V_GetStringColormap(INT32 colorflags) static const UINT8 *V_GetStringColormap(INT32 colorflags)

View file

@ -158,6 +158,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum);
void V_DrawFadeScreen(UINT16 color, UINT8 strength); void V_DrawFadeScreen(UINT16 color, UINT8 strength);
void V_DrawFadeConsBack(INT32 plines); void V_DrawFadeConsBack(INT32 plines);
void V_DrawPromptBack(INT32 boxheight, INT32 color);
// draw a single character // draw a single character
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed); void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);

View file

@ -234,10 +234,10 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum)
for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
{ // shameless copy+paste of code from LUA_LoadLump { // shameless copy+paste of code from LUA_LoadLump
size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name size_t len = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name
char *name = malloc(length + 1); char *name = malloc(len+1);
sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2); sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2);
name[length] = '\0'; name[len] = '\0';
CONS_Printf(M_GetText("Loading SOC from %s\n"), name); CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
DEH_LoadDehackedLumpPwad(wadnum, lump); DEH_LoadDehackedLumpPwad(wadnum, lump);
@ -389,6 +389,8 @@ UINT16 W_InitFile(const char *filename)
if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) if (!memcmp(wadfiles[i]->md5sum, md5sum, 16))
{ {
CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename);
if (handle)
fclose(handle);
return INT16_MAX; return INT16_MAX;
} }
} }
@ -634,6 +636,8 @@ UINT16 W_InitFile(const char *filename)
if (fread(&header, 1, sizeof header, handle) < sizeof header) if (fread(&header, 1, sizeof header, handle) < sizeof header)
{ {
CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header from %s because %s\n"), filename, strerror(ferror(handle))); CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header from %s because %s\n"), filename, strerror(ferror(handle)));
if (handle)
fclose(handle);
return INT16_MAX; return INT16_MAX;
} }
@ -644,6 +648,8 @@ UINT16 W_InitFile(const char *filename)
&& memcmp(header.identification, "SDLL", 4) != 0) && memcmp(header.identification, "SDLL", 4) != 0)
{ {
CONS_Alert(CONS_ERROR, M_GetText("%s does not have a valid WAD header\n"), filename); CONS_Alert(CONS_ERROR, M_GetText("%s does not have a valid WAD header\n"), filename);
if (handle)
fclose(handle);
return INT16_MAX; return INT16_MAX;
} }
@ -658,6 +664,8 @@ UINT16 W_InitFile(const char *filename)
{ {
CONS_Alert(CONS_ERROR, M_GetText("Wadfile directory in %s is corrupted (%s)\n"), filename, strerror(ferror(handle))); CONS_Alert(CONS_ERROR, M_GetText("Wadfile directory in %s is corrupted (%s)\n"), filename, strerror(ferror(handle)));
free(fileinfov); free(fileinfov);
if (handle)
fclose(handle);
return INT16_MAX; return INT16_MAX;
} }

View file

@ -17,10 +17,8 @@
#include "gme/gme.h" #include "gme/gme.h"
#define GME_TREBLE 5.0 #define GME_TREBLE 5.0
#define GME_BASS 1.0 #define GME_BASS 1.0
#ifdef HAVE_PNG /// TODO: compile with zlib support without libpng
#define HAVE_ZLIB
#ifdef HAVE_ZLIB
#ifndef _MSC_VER #ifndef _MSC_VER
#ifndef _LARGEFILE64_SOURCE #ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE
@ -36,8 +34,8 @@
#endif #endif
#include "zlib.h" #include "zlib.h"
#endif #endif // HAVE_ZLIB
#endif #endif // HAVE_LIBGME
static FMOD_SYSTEM *fsys; static FMOD_SYSTEM *fsys;
static FMOD_SOUND *music_stream; static FMOD_SOUND *music_stream;
@ -354,12 +352,13 @@ void I_FreeSfx(sfxinfo_t *sfx)
sfx->data = NULL; sfx->data = NULL;
} }
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority) INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
{ {
FMOD_SOUND *sound; FMOD_SOUND *sound;
FMOD_CHANNEL *chan; FMOD_CHANNEL *chan;
INT32 i; INT32 i;
float frequency; float frequency;
(void)channel;
sound = (FMOD_SOUND *)S_sfx[id].data; sound = (FMOD_SOUND *)S_sfx[id].data;
I_Assert(sound != NULL); I_Assert(sound != NULL);
@ -927,6 +926,7 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms
(void)target_volume; (void)target_volume;
(void)source_volume; (void)source_volume;
(void)ms; (void)ms;
(void)callback;
return false; return false;
} }
@ -934,6 +934,7 @@ boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void))
{ {
(void)target_volume; (void)target_volume;
(void)ms; (void)ms;
(void)callback;
return false; return false;
} }