diff --git a/.gitattributes b/.gitattributes index d45620912..7751149ac 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,12 @@ +#Source code +/src/*.c text=auto +/src/*.h text=auto +/src/*.s text=auto +/src/*.m text=auto +/src/*.xpm text=auto +/src/Makefile text=auto +/src/Make*.cfg text=auto +/src/CMakeLists.txt text=auto # Windows EOL *.cs -crlf -whitespace *.mk -crlf -whitespace diff --git a/libs/libpng-src/pngconf.h b/libs/libpng-src/pngconf.h index 23f8313c3..5cb126197 100644 --- a/libs/libpng-src/pngconf.h +++ b/libs/libpng-src/pngconf.h @@ -62,7 +62,6 @@ #define PNG_NO_READ_iTXt #define PNG_NO_READ_APNG -#define PNG_NO_READ_UNKNOWN_CHUNKS #define PNG_NO_READ_USER_TRANSFORM #define PNG_READ_BGR_SUPPORTED #define PNG_NO_READ_SWAP_ALPHA diff --git a/libs/libpng-src/projects/libpng32.a b/libs/libpng-src/projects/libpng32.a index 74cb54e8c..5d2917502 100644 Binary files a/libs/libpng-src/projects/libpng32.a and b/libs/libpng-src/projects/libpng32.a differ diff --git a/libs/libpng-src/projects/libpng64.a b/libs/libpng-src/projects/libpng64.a index bba4c9121..cddf938dd 100644 Binary files a/libs/libpng-src/projects/libpng64.a and b/libs/libpng-src/projects/libpng64.a differ diff --git a/srb2.png b/srb2.png index 72a08f664..3bbe2c3e6 100644 Binary files a/srb2.png and b/srb2.png differ diff --git a/src/Makefile.cfg b/src/Makefile.cfg index cbbbf426f..409cc4f22 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -226,8 +226,7 @@ ifdef GCC61 WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare endif ifdef GCC71 - WFLAGS+=-Wno-error=implicit-fallthrough - WFLAGS+=-Wno-implicit-fallthrough + WFLAGS+=-Wimplicit-fallthrough=4 endif ifdef GCC81 WFLAGS+=-Wno-error=format-overflow diff --git a/src/am_map.c b/src/am_map.c index 6d7042f1c..a184ea768 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -62,7 +62,7 @@ static const UINT8 NOCLIMBYELLOWS = (11*16); #define NOCLIMBCDWALLCOLORS NOCLIMBYELLOWS #define THINGCOLORS GREENS #define GRIDCOLORS (GRAYS + GRAYSRANGE/2) -#define XHAIRCOLORS GRAYS +#define XHAIRCOLORS DWHITE // controls #define AM_PANUPKEY KEY_UPARROW @@ -111,11 +111,6 @@ typedef struct mpoint_t a, b; } mline_t; -typedef struct -{ - fixed_t slp, islp; -} islope_t; - // // The vector graphics for the automap. // A line drawing of the player pointing right, @@ -137,16 +132,14 @@ static const mline_t player_arrow[] = { #undef R #define NUMPLYRLINES (sizeof (player_arrow)/sizeof (mline_t)) -#if 0 #define R (FRACUNIT) -static mline_t triangle_guy[] = { - { { (fixed_t)-.867f*R, (fixed_t)-.5f*R }, { (fixed_t) .867f*R, (fixed_t)-.5f*R } }, - { { (fixed_t) .867f*R, (fixed_t)-.5f*R }, { (fixed_t) 0, (fixed_t) R } }, - { { (fixed_t) 0, (fixed_t) R }, { (fixed_t)-.867f*R, (fixed_t)-.5f*R } } +static const mline_t cross_mark[] = +{ + { { -R, 0 }, { R, 0} }, + { { 0, -R }, { 0, R } }, }; #undef R -#define NUMTRIANGLEGUYLINES (sizeof (triangle_guy)/sizeof (mline_t)) -#endif +#define NUMCROSSMARKLINES (sizeof(cross_mark)/sizeof(mline_t)) #define R (FRACUNIT) static const mline_t thintriangle_guy[] = { @@ -206,7 +199,7 @@ static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow -static INT32 followplayer = true; // specifies whether to follow the player around +static boolean followplayer = true; // specifies whether to follow the player around // function for drawing lines, depends on rendermode typedef void (*AMDRAWFLINEFUNC) (const fline_t *fl, INT32 color); @@ -816,17 +809,18 @@ static void AM_drawGrid(INT32 color) fixed_t x, y; fixed_t start, end; mline_t ml; + fixed_t gridsize = (MAPBLOCKUNITS<>FRACTOMAPBITS)) % gridsize) + start += gridsize - ((start - (bmaporgx>>FRACTOMAPBITS)) % gridsize); end = m_x + m_w; // draw vertical gridlines ml.a.y = m_y; ml.b.y = m_y + m_h; - for (x = start; x < end; x += (MAPBLOCKUNITS<>FRACTOMAPBITS)) % gridsize) + start += gridsize - ((start - (bmaporgy>>FRACTOMAPBITS)) % gridsize); end = m_y + m_h; // draw horizontal gridlines ml.a.x = m_x; ml.b.x = m_x + m_w; - for (y = start; y < end; y += (MAPBLOCKUNITS<mo->angle, DWHITE, plr->mo->x, plr->mo->y); + AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 16<mo->angle, DWHITE, plr->mo->x, plr->mo->y); return; } @@ -1053,7 +1047,7 @@ static inline void AM_drawPlayers(void) if (p->skincolor > 0) color = R_GetTranslationColormap(TC_DEFAULT, p->skincolor, GTC_CACHE)[GREENS + 8]; - AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle, color, p->mo->x, p->mo->y); + AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 16<mo->angle, color, p->mo->x, p->mo->y); } } @@ -1073,13 +1067,30 @@ static inline void AM_drawThings(UINT8 colors) } } -/** Draws the crosshair, actually just a dot in software mode. +/** Draws the crosshair. * * \param color Color for the crosshair. */ static inline void AM_drawCrosshair(UINT8 color) { - V_DrawFill(f_w/2 + f_x, f_h/2 + f_y, 1, 1, color|V_NOSCALESTART); + const fixed_t scale = 4<> FRACBITS; + fl.a.y = FixedMul(cross_mark[i].a.y, scale) >> FRACBITS; + fl.b.x = FixedMul(cross_mark[i].b.x, scale) >> FRACBITS; + fl.b.y = FixedMul(cross_mark[i].b.y, scale) >> FRACBITS; + + fl.a.x += f_x + (f_w / 2); + fl.a.y += f_y + (f_h / 2); + fl.b.x += f_x + (f_w / 2); + fl.b.y += f_y + (f_h / 2); + + AM_drawFline(&fl, color); + } } /** Draws the automap. @@ -1095,5 +1106,5 @@ void AM_Drawer(void) AM_drawPlayers(); AM_drawThings(THINGCOLORS); - AM_drawCrosshair(XHAIRCOLORS); + if (!followplayer) AM_drawCrosshair(XHAIRCOLORS); } diff --git a/src/am_map.h b/src/am_map.h index 4e8c782a9..d59532819 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -26,11 +26,6 @@ typedef struct fpoint_t a, b; } fline_t; -// Used by ST StatusBar stuff. -#define AM_MSGHEADER (('a'<<24)+('m'<<16)) -#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) -#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) - extern boolean am_recalc; // true if screen size changes extern boolean automapactive; // In AutoMap mode? diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 556d86384..476bb1a1e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -152,7 +152,7 @@ ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; static textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL}; -static consvar_t cv_showjoinaddress = {"showjoinaddress", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_showjoinaddress = {"showjoinaddress", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}}; consvar_t cv_playbackspeed = {"playbackspeed", "1", 0, playbackspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -513,6 +513,10 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->currentweapon = LONG(players[i].currentweapon); rsp->ringweapons = LONG(players[i].ringweapons); + rsp->ammoremoval = (UINT16)SHORT(players[i].ammoremoval); + rsp->ammoremovaltimer = (tic_t)LONG(players[i].ammoremovaltimer); + rsp->ammoremovalweapon = LONG(players[i].ammoremovalweapon); + for (j = 0; j < NUMPOWERS; ++j) rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); @@ -575,6 +579,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->starpostnum = LONG(players[i].starpostnum); rsp->starposttime = (tic_t)LONG(players[i].starposttime); rsp->starpostangle = (angle_t)LONG(players[i].starpostangle); + rsp->starpostscale = (fixed_t)LONG(players[i].starpostscale); rsp->maxlink = LONG(players[i].maxlink); rsp->dashspeed = (fixed_t)LONG(players[i].dashspeed); @@ -644,6 +649,10 @@ static void resynch_read_player(resynch_pak *rsp) players[i].currentweapon = LONG(rsp->currentweapon); players[i].ringweapons = LONG(rsp->ringweapons); + players[i].ammoremoval = (UINT16)SHORT(rsp->ammoremoval); + players[i].ammoremovaltimer = (tic_t)LONG(rsp->ammoremovaltimer); + players[i].ammoremovalweapon = LONG(rsp->ammoremovalweapon); + for (j = 0; j < NUMPOWERS; ++j) players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); @@ -706,6 +715,7 @@ static void resynch_read_player(resynch_pak *rsp) players[i].starpostnum = LONG(rsp->starpostnum); players[i].starposttime = (tic_t)LONG(rsp->starposttime); players[i].starpostangle = (angle_t)LONG(rsp->starpostangle); + players[i].starpostscale = (fixed_t)LONG(rsp->starpostscale); players[i].maxlink = LONG(rsp->maxlink); players[i].dashspeed = (fixed_t)LONG(rsp->dashspeed); @@ -2407,7 +2417,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) // the remaining players. if (G_IsSpecialStage(gamemap)) { - INT32 i, count, increment, spheres; + INT32 i, count, sincrement, spheres, rincrement, rings; for (i = 0, count = 0; i < MAXPLAYERS; i++) { @@ -2417,18 +2427,35 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) count--; spheres = players[playernum].spheres; - increment = spheres/count; + rings = players[playernum].rings; + sincrement = spheres/count; + rincrement = rings/count; for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && i != playernum) { - if (spheres < increment) + if (spheres < 2*sincrement) + { P_GivePlayerSpheres(&players[i], spheres); + spheres = 0; + } else - P_GivePlayerSpheres(&players[i], increment); + { + P_GivePlayerSpheres(&players[i], sincrement); + spheres -= sincrement; + } - spheres -= increment; + if (rings < 2*rincrement) + { + P_GivePlayerRings(&players[i], rings); + rings = 0; + } + else + { + P_GivePlayerRings(&players[i], rincrement); + rings -= rincrement; + } } } } @@ -2938,13 +2965,13 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } -consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; -consvar_t cv_joinnextround = {"joinnextround", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done +consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; +consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}}; -consvar_t cv_resynchattempts = {"resynchattempts", "10", 0, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; -consvar_t cv_blamecfail = {"blamecfail", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; +consvar_t cv_resynchattempts = {"resynchattempts", "10", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; +consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; // max file size to send to a player (in kilobytes) static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}}; @@ -2985,11 +3012,6 @@ void D_ClientServerInit(void) RegisterNetXCmd(XD_KICK, Got_KickCmd); RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); #ifndef NONET - CV_RegisterVar(&cv_allownewplayer); - CV_RegisterVar(&cv_joinnextround); - CV_RegisterVar(&cv_showjoinaddress); - CV_RegisterVar(&cv_resynchattempts); - CV_RegisterVar(&cv_blamecfail); #ifdef DUMPCONSISTENCY CV_RegisterVar(&cv_dumpconsistency); #endif diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a6783fb3d..d09d2aa48 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -164,6 +164,9 @@ typedef struct angle_t aiming; INT32 currentweapon; INT32 ringweapons; + UINT16 ammoremoval; + tic_t ammoremovaltimer; + INT32 ammoremovalweapon; UINT16 powers[NUMPOWERS]; // Score is resynched in the confirm resync packet @@ -225,6 +228,7 @@ typedef struct INT32 starpostnum; tic_t starposttime; angle_t starpostangle; + fixed_t starpostscale; INT32 maxlink; fixed_t dashspeed; @@ -441,6 +445,7 @@ extern INT32 mapchangepending; // Points inside doomcom extern doomdata_t *netbuffer; +extern consvar_t cv_showjoinaddress; extern consvar_t cv_playbackspeed; #define BASEPACKETSIZE offsetof(doomdata_t, u) diff --git a/src/d_main.c b/src/d_main.c index eaeae4b10..37637edd6 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -129,6 +129,7 @@ char srb2home[256] = "."; char srb2path[256] = "."; boolean usehome = true; const char *pandf = "%s" PATHSEP "%s"; +static char addonsdir[MAX_WADPATH]; // // EVENT HANDLING @@ -287,7 +288,7 @@ static void D_Display(void) F_TitleScreenDrawer(); break; } - // Intentional fall-through + /* FALLTHRU */ case GS_LEVEL: if (!gametic) break; @@ -716,6 +717,7 @@ void D_StartTitle(void) botskin = 0; cv_debug = 0; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); lastmaploaded = 0; // In case someone exits out at the same time they start a time attack run, @@ -1038,7 +1040,6 @@ void D_SRB2Main(void) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); - I_mkdir(srb2home, 0700); #else snprintf(srb2home, sizeof srb2home, "%s", userhome); snprintf(downloaddir, sizeof downloaddir, "%s", userhome); @@ -1055,6 +1056,10 @@ void D_SRB2Main(void) configfile[sizeof configfile - 1] = '\0'; } + // Create addons dir + snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons"); + I_mkdir(addonsdir, 0755); + // rand() needs seeded regardless of password srand((unsigned int)time(NULL)); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3e82fc60c..bd57c2481 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -246,20 +246,20 @@ INT32 cv_debug; consvar_t cv_usemouse = {"use_mouse", "On", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_usemouse2 = {"use_mouse2", "Off", CV_SAVE|CV_CALL,usemouse_cons_t, I_StartupMouse2, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_usejoystick = {"use_joystick", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, +consvar_t cv_usejoystick = {"use_gamepad", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_usejoystick2 = {"use_joystick2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, +consvar_t cv_usejoystick2 = {"use_gamepad2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2, 0, NULL, NULL, 0, 0, NULL}; #if (defined (LJOYSTICK) || defined (HAVE_SDL)) #ifdef LJOYSTICK -consvar_t cv_joyport = {"joyport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_joyport2 = {"joyport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: for later +consvar_t cv_joyport = {"padport", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_joyport2 = {"padport2", "/dev/js0", CV_SAVE, joyport_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: for later #endif -consvar_t cv_joyscale = {"joyscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_joyscale2 = {"joyscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_joyscale = {"padscale", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_joyscale2 = {"padscale2", "1", CV_SAVE|CV_CALL, NULL, I_JoyScale2, 0, NULL, NULL, 0, 0, NULL}; #else -consvar_t cv_joyscale = {"joyscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save -consvar_t cv_joyscale2 = {"joyscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save +consvar_t cv_joyscale = {"padscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save +consvar_t cv_joyscale2 = {"padscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; //Alam: Dummy for save #endif #if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) consvar_t cv_mouse2port = {"mouse2port", "/dev/gpmdata", CV_SAVE, mouse2port_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -556,9 +556,16 @@ void D_RegisterServerCommands(void) // d_clisrv CV_RegisterVar(&cv_maxplayers); + CV_RegisterVar(&cv_resynchattempts); CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_noticedownload); CV_RegisterVar(&cv_downloadspeed); +#ifndef NONET + CV_RegisterVar(&cv_allownewplayer); + CV_RegisterVar(&cv_joinnextround); + CV_RegisterVar(&cv_showjoinaddress); + CV_RegisterVar(&cv_blamecfail); +#endif COM_AddCommand("ping", Command_Ping_f); CV_RegisterVar(&cv_nettimeout); @@ -630,6 +637,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_screenshot_folder); CV_RegisterVar(&cv_screenshot_colorprofile); CV_RegisterVar(&cv_moviemode); + CV_RegisterVar(&cv_movie_option); + CV_RegisterVar(&cv_movie_folder); // PNG variables CV_RegisterVar(&cv_zlib_level); CV_RegisterVar(&cv_zlib_memory); @@ -849,6 +858,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("rteleport", Command_RTeleport_f); COM_AddCommand("skynum", Command_Skynum_f); COM_AddCommand("weather", Command_Weather_f); + COM_AddCommand("toggletwod", Command_Toggletwod_f); #ifdef _DEBUG COM_AddCommand("causecfail", Command_CauseCfail_f); #endif @@ -1908,7 +1918,10 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) precache = false; if (resetplayer && !FLS) + { emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); + } if (modeattacking) { @@ -2706,14 +2719,6 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } } - // Clear player score and rings if a spectator. - if (players[playernum].spectator) - { - players[playernum].score = players[playernum].rings = 0; - if (players[playernum].mo) - players[playernum].mo->health = 1; - } - // In tag, check to see if you still have a game. if (G_TagGametype()) P_CheckSurvivors(); @@ -3600,7 +3605,7 @@ static void CoopLives_OnChange(void) { case 0: CONS_Printf(M_GetText("Players can now respawn indefinitely.\n")); - return; + break; case 1: CONS_Printf(M_GetText("Lives are now per-player.\n")); return; @@ -4103,6 +4108,7 @@ void Command_ExitGame_f(void) botskin = 0; cv_debug = 0; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); if (dirmenu) closefilemenu(true); diff --git a/src/d_netfil.c b/src/d_netfil.c index db9fa12e4..ed2d11138 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -745,9 +745,12 @@ void Got_Filetxpak(void) { INT32 filenum = netbuffer->u.filetxpak.fileid; fileneeded_t *file = &fileneeded[filenum]; - char *filename = file->filename; + char *filename; static INT32 filetime = 0; + filename = va("%s", file->filename); + nameonly(filename); + if (!(strcmp(filename, "srb2.pk3") && strcmp(filename, "srb2.srb") && strcmp(filename, "srb2.wad") @@ -758,6 +761,8 @@ void Got_Filetxpak(void) )) I_Error("Tried to download \"%s\"", filename); + filename = file->filename; + if (filenum >= fileneedednum) { DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum)); diff --git a/src/d_player.h b/src/d_player.h index 8648b3608..ff8c31203 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -335,6 +335,10 @@ typedef struct player_s INT32 currentweapon; // current weapon selected. INT32 ringweapons; // weapons currently obtained. + UINT16 ammoremoval; // amount of ammo removed for the current weapon. + tic_t ammoremovaltimer; // flashing counter for ammo used. + INT32 ammoremovalweapon; // weapon from which the ammo was removed. + // Power ups. invinc and invis are tic counters. UINT16 powers[NUMPOWERS]; @@ -439,6 +443,7 @@ typedef struct player_s INT32 starpostnum; // The number of the last starpost you hit tic_t starposttime; // Your time when you hit the starpost angle_t starpostangle; // Angle that the starpost is facing - you respawn facing this way + fixed_t starpostscale; // Scale of the player; if negative, player is gravflipped ///////////////// // NiGHTS Stuff// diff --git a/src/dehacked.c b/src/dehacked.c index 9cc5b9b7f..ef3e13f4f 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1181,6 +1181,20 @@ static void readlevelheader(MYFILE *f, INT32 num) mapheaderinfo[num-1]->muspostbosspos = (UINT32)get_number(word2); else if (fastcmp(word, "MUSICPOSTBOSSFADEIN")) mapheaderinfo[num-1]->muspostbossfadein = (UINT32)get_number(word2); + else if (fastcmp(word, "FORCERESETMUSIC")) + { + // This is a weird one because "FALSE"/"NO" could either apply to "leave to default preference" (cv_resetmusic) + // or "force off". Let's assume it means "force off", and let an unspecified value mean "default preference" + if (fastcmp(word2, "OFF") || word2[0] == 'F' || word2[0] == 'N') i = 0; + else if (fastcmp(word2, "ON") || word2[0] == 'T' || word2[0] == 'Y') i = 1; + else i = -1; // (fastcmp(word2, "DEFAULT")) + + if (i >= -1 && i <= 1) // -1 to force off, 1 to force on, 0 to honor default. + // This behavior can be disabled with cv_resetmusicbyheader + mapheaderinfo[num-1]->musforcereset = (SINT8)i; + else + deh_warning("Level header %d: invalid forceresetmusic option %d", num, i); + } else if (fastcmp(word, "FORCECHARACTER")) { strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1); @@ -2311,6 +2325,7 @@ static actionpointer_t actionpointers[] = {{A_Boss1Spikeballs}, "A_BOSS1SPIKEBALLS"}, {{A_Boss3TakeDamage}, "A_BOSS3TAKEDAMAGE"}, {{A_Boss3Path}, "A_BOSS3PATH"}, + {{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"}, {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, {{A_PlayAttackSound}, "A_PLAYATTACKSOUND"}, @@ -2417,6 +2432,7 @@ static actionpointer_t actionpointers[] = {{A_Boss5CheckFalling}, "A_BOSS5CHECKFALLING"}, {{A_Boss5PinchShot}, "A_BOSS5PINCHSHOT"}, {{A_Boss5MakeItRain}, "A_BOSS5MAKEITRAIN"}, + {{A_Boss5MakeJunk}, "A_BOSS5MAKEJUNK"}, {{A_LookForBetter}, "A_LOOKFORBETTER"}, {{A_Boss5BombExplode}, "A_BOSS5BOMBEXPLODE"}, {{A_DustDevilThink}, "A_DUSTDEVILTHINK"}, @@ -2965,6 +2981,17 @@ static void readunlockable(MYFILE *f, INT32 num) Z_Free(s); } +static const char NIGHTSGRADE_LIST[] = { + 'F', // GRADE_F + 'E', // GRADE_E + 'D', // GRADE_D + 'C', // GRADE_C + 'B', // GRADE_B + 'A', // GRADE_A + 'S', // GRADE_S + '\0' +}; + #define PARAMCHECK(n) do { if (!params[n]) { deh_warning("Too few parameters, need %d", n); return; }} while (0) static void readcondition(UINT8 set, UINT32 id, char *word2) { @@ -3066,7 +3093,21 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) PARAMCHECK(2); // one optional one ty = UC_NIGHTSSCORE + offset; - re = atoi(params[2 + !!(params[3])]); + i = (params[3] ? 3 : 2); + if (fastncmp("GRADE_",params[i],6)) + { + char *p = params[i]+6; + for (re = 0; NIGHTSGRADE_LIST[re]; re++) + if (*p == NIGHTSGRADE_LIST[re]) + break; + if (!NIGHTSGRADE_LIST[re]) + { + deh_warning("Invalid NiGHTS grade %s\n", params[i]); + return; + } + } + else + re = atoi(params[i]); // Convert to map number if it appears to be one if (params[1][0] >= 'A' && params[1][0] <= 'Z') @@ -3355,6 +3396,10 @@ static void readmaincfg(MYFILE *f) { gameovertics = get_number(word2); } + else if (fastcmp(word, "AMMOREMOVALTICS")) + { + ammoremovaltics = get_number(word2); + } else if (fastcmp(word, "INTROTOPLAY")) { introtoplay = (UINT8)get_number(word2); @@ -4609,10 +4654,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_SONIC3KBOSSEXPLOSION6", "S_JETFUME1", - "S_JETFUME2", // Boss 1 "S_EGGMOBILE_STND", + "S_EGGMOBILE_ROFL", "S_EGGMOBILE_LATK1", "S_EGGMOBILE_LATK2", "S_EGGMOBILE_LATK3", @@ -4622,7 +4667,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGMOBILE_LATK7", "S_EGGMOBILE_LATK8", "S_EGGMOBILE_LATK9", - "S_EGGMOBILE_LATK10", "S_EGGMOBILE_RATK1", "S_EGGMOBILE_RATK2", "S_EGGMOBILE_RATK3", @@ -4632,7 +4676,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGMOBILE_RATK7", "S_EGGMOBILE_RATK8", "S_EGGMOBILE_RATK9", - "S_EGGMOBILE_RATK10", "S_EGGMOBILE_PANIC1", "S_EGGMOBILE_PANIC2", "S_EGGMOBILE_PANIC3", @@ -4640,6 +4683,14 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGMOBILE_PANIC5", "S_EGGMOBILE_PANIC6", "S_EGGMOBILE_PANIC7", + "S_EGGMOBILE_PANIC8", + "S_EGGMOBILE_PANIC9", + "S_EGGMOBILE_PANIC10", + "S_EGGMOBILE_PANIC11", + "S_EGGMOBILE_PANIC12", + "S_EGGMOBILE_PANIC13", + "S_EGGMOBILE_PANIC14", + "S_EGGMOBILE_PANIC15", "S_EGGMOBILE_PAIN", "S_EGGMOBILE_PAIN2", "S_EGGMOBILE_DIE1", @@ -4650,6 +4701,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGMOBILE_FLEE2", "S_EGGMOBILE_BALL", "S_EGGMOBILE_TARGET", + "S_BOSSEGLZ1", + "S_BOSSEGLZ2", // Boss 2 "S_EGGMOBILE2_STND", @@ -4681,11 +4734,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Boss 3 "S_EGGMOBILE3_STND", - "S_EGGMOBILE3_LAUGH1", - "S_EGGMOBILE3_LAUGH2", - "S_EGGMOBILE3_LAUGH3", - "S_EGGMOBILE3_LAUGH4", - "S_EGGMOBILE3_LAUGH5", + "S_EGGMOBILE3_SHOCK", "S_EGGMOBILE3_ATK1", "S_EGGMOBILE3_ATK2", "S_EGGMOBILE3_ATK3A", @@ -4694,21 +4743,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGMOBILE3_ATK3D", "S_EGGMOBILE3_ATK4", "S_EGGMOBILE3_ATK5", - "S_EGGMOBILE3_LAUGH6", - "S_EGGMOBILE3_LAUGH7", - "S_EGGMOBILE3_LAUGH8", - "S_EGGMOBILE3_LAUGH9", - "S_EGGMOBILE3_LAUGH10", - "S_EGGMOBILE3_LAUGH11", - "S_EGGMOBILE3_LAUGH12", - "S_EGGMOBILE3_LAUGH13", - "S_EGGMOBILE3_LAUGH14", - "S_EGGMOBILE3_LAUGH15", - "S_EGGMOBILE3_LAUGH16", - "S_EGGMOBILE3_LAUGH17", - "S_EGGMOBILE3_LAUGH18", - "S_EGGMOBILE3_LAUGH19", - "S_EGGMOBILE3_LAUGH20", + "S_EGGMOBILE3_ROFL", "S_EGGMOBILE3_PAIN", "S_EGGMOBILE3_PAIN2", "S_EGGMOBILE3_DIE1", @@ -4718,15 +4753,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGMOBILE3_FLEE1", "S_EGGMOBILE3_FLEE2", - // Boss 3 Propeller - "S_PROPELLER1", - "S_PROPELLER2", - "S_PROPELLER3", - "S_PROPELLER4", - "S_PROPELLER5", - "S_PROPELLER6", - "S_PROPELLER7", - // Boss 3 pinch "S_FAKEMOBILE_INIT", "S_FAKEMOBILE", @@ -4739,6 +4765,14 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FAKEMOBILE_DIE1", "S_FAKEMOBILE_DIE2", + "S_BOSSSEBH1", + "S_BOSSSEBH2", + + // Boss 3 Shockwave + + "S_SHOCKWAVE1", + "S_SHOCKWAVE2", + // Boss 4 "S_EGGMOBILE4_STND", "S_EGGMOBILE4_LATK1", @@ -4781,6 +4815,25 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGROBOJET", // Boss 5 + "S_FANG_SETUP", + "S_FANG_INTRO0", + "S_FANG_INTRO1", + "S_FANG_INTRO2", + "S_FANG_INTRO3", + "S_FANG_INTRO4", + "S_FANG_INTRO5", + "S_FANG_INTRO6", + "S_FANG_INTRO7", + "S_FANG_INTRO8", + "S_FANG_INTRO9", + "S_FANG_INTRO10", + "S_FANG_INTRO11", + "S_FANG_INTRO12", + "S_FANG_CLONE1", + "S_FANG_CLONE2", + "S_FANG_CLONE3", + "S_FANG_CLONE4", + "S_FANG_IDLE0", "S_FANG_IDLE1", "S_FANG_IDLE2", "S_FANG_IDLE3", @@ -4852,6 +4905,26 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FANG_FLEEBOUNCE2", "S_FANG_KO", + "S_BROKENROBOTRANDOM", + "S_BROKENROBOTA", + "S_BROKENROBOTB", + "S_BROKENROBOTC", + "S_BROKENROBOTD", + "S_BROKENROBOTE", + "S_BROKENROBOTF", + + "S_ALART1", + "S_ALART2", + + "S_VWREF", + "S_VWREB", + + "S_PROJECTORLIGHT1", + "S_PROJECTORLIGHT2", + "S_PROJECTORLIGHT3", + "S_PROJECTORLIGHT4", + "S_PROJECTORLIGHT5", + "S_FBOMB1", "S_FBOMB2", "S_FBOMB_EXPL1", @@ -5142,16 +5215,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_MSSHIELD_F1", "S_MSSHIELD_F2", - "S_MSSHIELD_F3", - "S_MSSHIELD_F4", - "S_MSSHIELD_F5", - "S_MSSHIELD_F6", - "S_MSSHIELD_F7", - "S_MSSHIELD_F8", - "S_MSSHIELD_F9", - "S_MSSHIELD_F10", - "S_MSSHIELD_F11", - "S_MSSHIELD_F12", // Ring "S_RING", @@ -5585,14 +5648,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_DRIPC1", "S_DRIPC2", - // Coral 1 + // Coral "S_CORAL1", - - // Coral 2 "S_CORAL2", - - // Coral 3 "S_CORAL3", + "S_CORAL4", + "S_CORAL5", // Blue Crystal "S_BLUECRYSTAL1", @@ -5600,6 +5661,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Kelp, "S_KELP", + // Animated algae + "S_ANIMALGAETOP1", + "S_ANIMALGAETOP2", + "S_ANIMALGAESEG", + // DSZ Stalagmites "S_DSZSTALAGMITE", "S_DSZ2STALAGMITE", @@ -5744,6 +5810,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CACTI7", "S_CACTI8", "S_CACTI9", + "S_CACTI10", + "S_CACTI11", + "S_CACTITINYSEG", + "S_CACTISMALLSEG", // Warning signs sprites "S_ARIDSIGN_CAUTION", @@ -7265,6 +7335,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_EGGTRAP", "MT_BOSS3WAYPOINT", "MT_BOSS9GATHERPOINT", + "MT_BOSSJUNK", // Boss 1 "MT_EGGMOBILE", @@ -7276,17 +7347,13 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Boss 2 "MT_EGGMOBILE2", "MT_EGGMOBILE2_POGO", - "MT_BOSSTANK1", - "MT_BOSSTANK2", - "MT_BOSSSPIGOT", "MT_GOOP", "MT_GOOPTRAIL", // Boss 3 "MT_EGGMOBILE3", - "MT_PROPELLER", "MT_FAKEMOBILE", - "MT_SHOCK", + "MT_SHOCKWAVE", // Boss 4 "MT_EGGMOBILE4", @@ -7297,6 +7364,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s // Boss 5 "MT_FANG", + "MT_BROKENROBOT", + "MT_VWREF", + "MT_VWREB", + "MT_PROJECTORLIGHT", "MT_FBOMB", "MT_TNTDUST", // also used by barrel "MT_FSGNA", @@ -7495,11 +7566,15 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SEAWEED", // DSZ Seaweed "MT_WATERDRIP", // Dripping Water source "MT_WATERDROP", // Water drop from dripping water - "MT_CORAL1", // Coral 1 - "MT_CORAL2", // Coral 2 - "MT_CORAL3", // Coral 3 + "MT_CORAL1", // Coral + "MT_CORAL2", + "MT_CORAL3", + "MT_CORAL4", + "MT_CORAL5", "MT_BLUECRYSTAL", // Blue Crystal "MT_KELP", // Kelp + "MT_ANIMALGAETOP", // Animated algae top + "MT_ANIMALGAESEG", // Animated algae segment "MT_DSZSTALAGMITE", // Deep Sea 1 Stalagmite "MT_DSZ2STALAGMITE", // Deep Sea 2 Stalagmite "MT_LIGHTBEAM", // DSZ Light beam @@ -7559,6 +7634,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_CACTI7", "MT_CACTI8", "MT_CACTI9", + "MT_CACTI10", + "MT_CACTI11", + "MT_CACTITINYSEG", + "MT_CACTISMALLSEG", "MT_ARIDSIGN_CAUTION", "MT_ARIDSIGN_CACTI", "MT_ARIDSIGN_SHARPTURN", @@ -8539,15 +8618,6 @@ struct { {"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED}, {"LF2_WIDEICON",LF2_WIDEICON}, - // NiGHTS grades - {"GRADE_F",GRADE_F}, - {"GRADE_E",GRADE_E}, - {"GRADE_D",GRADE_D}, - {"GRADE_C",GRADE_C}, - {"GRADE_B",GRADE_B}, - {"GRADE_A",GRADE_A}, - {"GRADE_S",GRADE_S}, - // Emeralds {"EMERALD1",EMERALD1}, {"EMERALD2",EMERALD2}, @@ -9371,6 +9441,19 @@ static fixed_t find_const(const char **rword) free(word); return 0; } + else if (fastncmp("GRADE_",word,6)) + { + char *p = word+6; + for (i = 0; NIGHTSGRADE_LIST[i]; i++) + if (*p == NIGHTSGRADE_LIST[i]) + { + free(word); + return i; + } + const_warning("NiGHTS grade",word); + free(word); + return 0; + } for (i = 0; INT_CONST[i].n; i++) if (fastcmp(word,INT_CONST[i].n)) { free(word); @@ -9819,6 +9902,18 @@ static inline int lib_getenum(lua_State *L) if (mathlib) return luaL_error(L, "skincolor '%s' could not be found.\n", word); return 0; } + else if (fastncmp("GRADE_",word,6)) + { + p = word+6; + for (i = 0; NIGHTSGRADE_LIST[i]; i++) + if (*p == NIGHTSGRADE_LIST[i]) + { + lua_pushinteger(L, i); + return 1; + } + if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word); + return 0; + } else if (fastncmp("MN_",word,3)) { p = word+3; for (i = 0; i < NUMMENUTYPES; i++) diff --git a/src/doomdef.h b/src/doomdef.h index 6e7db2143..8d44d0896 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -506,6 +506,9 @@ INT32 I_GetKey(void); #define max(x, y) (((x) > (y)) ? (x) : (y)) #endif +// Max gamepad/joysticks that can be detected/used. +#define MAX_JOYSTICKS 4 + // Floating point comparison epsilons from float.h #ifndef FLT_EPSILON #define FLT_EPSILON 1.1920928955078125e-7f @@ -616,4 +619,8 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// SRB2CB itself ported this from PrBoom+ #define NEWCLIP +#ifndef HAVE_PNG +#define NO_PNG_LUMPS +#endif + #endif // __DOOMDEF__ diff --git a/src/doomstat.h b/src/doomstat.h index b6c376d1c..57e37f72d 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -333,6 +333,8 @@ typedef struct UINT32 muspostbosspos; ///< Post-bossdeath position UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds. + SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on) + // Lua stuff. // (This is not ifdeffed so the map header structure can stay identical, just in case.) UINT8 numCustomOptions; ///< Internal. For Lua custom value support. @@ -418,6 +420,10 @@ extern UINT16 emeralds; #define EMERALD7 64 #define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) +// yes, even in non HAVE_BLUA +#define NUM_LUABANKS 16 // please only make this number go up between versions, never down. you'll break saves otherwise. also, must fit in UINT8 +extern INT32 luabanks[NUM_LUABANKS]; + extern INT32 nummaprings; //keep track of spawned rings/coins /** Time attack information, currently a very small structure. diff --git a/src/f_finale.c b/src/f_finale.c index da042abeb..ee22ecb2f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1584,22 +1584,22 @@ void F_StartEnding(void) UINT8 skinnum = players[consoleplayer].skin; spritedef_t *sprdef; spriteframe_t *sprframe; - if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 5) + if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 7) { sprdef = &skins[skinnum].sprites[SPR2_XTRA]; // character head, skin specific - sprframe = &sprdef->spriteframes[2]; - endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); - sprframe = &sprdef->spriteframes[3]; - endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); sprframe = &sprdef->spriteframes[4]; + endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); + sprframe = &sprdef->spriteframes[5]; + endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); + sprframe = &sprdef->spriteframes[6]; endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); } - else // eh, yknow what? too lazy to put MISSINGs here. eggman wins if you don't give your character an ending firework display. + else // Show a star if your character doesn't have an ending firework display. (Basically the MISSINGs for this) { - endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_LEVEL); - endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_LEVEL); - endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_LEVEL); + endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_LEVEL); + endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_LEVEL); + endfwrk[2] = W_CachePatchName("ENDFWRK5", PU_LEVEL); } endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_LEVEL); @@ -2465,6 +2465,11 @@ void F_TitleDemoTicker(void) // ========== // CONTINUE // ========== + +static skin_t *contskins[2]; +static UINT8 cont_spr2[2][6]; +static UINT8 *contcolormaps[2]; + void F_StartContinue(void) { I_Assert(!netgame && !multiplayer); @@ -2488,7 +2493,44 @@ void F_StartContinue(void) S_ChangeMusicInternal("_conti", false); S_StopSounds(); - timetonext = TICRATE*11; + contskins[0] = &skins[players[consoleplayer].skin]; + cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT1, NULL); + cont_spr2[0][2] = contskins[0]->contangle & 7; + contcolormaps[0] = R_GetTranslationColormap(players[consoleplayer].skin, players[consoleplayer].skincolor, GTC_CACHE); + cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes; + cont_spr2[0][5] = max(1, contskins[0]->contspeed); + + if (botskin) + { + INT32 secondplaya; + + if (secondarydisplayplayer != consoleplayer) + secondplaya = secondarydisplayplayer; + else // HACK + secondplaya = 1; + + contskins[1] = &skins[players[secondplaya].skin]; + cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT4, NULL); + cont_spr2[1][2] = (contskins[1]->contangle >> 3) & 7; + contcolormaps[1] = R_GetTranslationColormap(players[secondplaya].skin, players[secondplaya].skincolor, GTC_CACHE); + cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes; + if (cont_spr2[1][0] == SPR2_CNT4) + cont_spr2[1][5] = 4; // sorry, this one is hardcoded + else + cont_spr2[1][5] = max(1, contskins[1]->contspeed); + } + else + { + contskins[1] = NULL; + contcolormaps[1] = NULL; + cont_spr2[1][0] = cont_spr2[1][2] = cont_spr2[1][4] = cont_spr2[1][5] = 0; + } + + cont_spr2[0][1] = cont_spr2[0][3] =\ + cont_spr2[1][1] = cont_spr2[1][3] = 0; + + timetonext = (11*TICRATE)+11; + continuetime = 0; } // @@ -2497,47 +2539,198 @@ void F_StartContinue(void) // void F_ContinueDrawer(void) { - patch_t *contsonic; - INT32 i, x = (BASEVIDWIDTH/2) + 4, ncontinues = players[consoleplayer].continues; - if (ncontinues > 20) - ncontinues = 20; + spritedef_t *sprdef; + spriteframe_t *sprframe; + patch_t *patch; + INT32 i, x = (BASEVIDWIDTH>>1), ncontinues = players[consoleplayer].continues; + char numbuf[9] = "CONTNUM*"; + tic_t timeleft = (timetonext/TICRATE); + INT32 offsx = 0, offsy = 0, lift[2] = {0, 0}; - if (imcontinuing) - contsonic = W_CachePatchName("CONT2", PU_CACHE); - else - contsonic = W_CachePatchName("CONT1", PU_CACHE); + if (continuetime >= 3*TICRATE) + { + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); + return; + } V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - V_DrawCenteredString(BASEVIDWIDTH/2, 100, 0, "CONTINUE?"); - // Draw a Sonic! - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(contsonic->width))/2, 32, 0, contsonic); + if (timetonext >= (11*TICRATE)+10) + return; - // Draw the continue markers! Show continues minus one. - x -= ncontinues * 6; - for (i = 0; i < ncontinues; ++i) - V_DrawContinueIcon(x + (i*12), 140, 0, players[consoleplayer].skin, players[consoleplayer].skincolor); + V_DrawLevelTitle(x - (V_LevelNameWidth("CONTINUE")>>1), 16, 0, "CONTINUE"); - V_DrawCenteredString(BASEVIDWIDTH/2, 168, 0, va("\x82*\x80" " %02d " "\x82*\x80", timetonext/TICRATE)); + // Two stars... + patch = W_CachePatchName("CONTSTAR", PU_CACHE); + V_DrawScaledPatch(x-32, 160, 0, patch); + V_DrawScaledPatch(x+32, 160, 0, patch); + + // Time left! + if (timeleft > 9) + { + numbuf[7] = '1'; + V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + numbuf[7] = '0'; + V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + } + else + { + numbuf[7] = '0'+timeleft; + V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_CACHE)); + } + + // Draw the continue markers! Show continues. + if (ncontinues > 10) + { + if (!(continuetime & 1) || continuetime > 17) + V_DrawContinueIcon(x, 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor); + V_DrawScaledPatch(x+12, 68-2, 0, stlivex); + V_DrawRightAlignedString(x+36, 69-5, 0, + va("%d",(imcontinuing ? ncontinues-1 : ncontinues))); + } + else + { + x += (ncontinues/2) * 30; + if (!(ncontinues & 1)) + x -= 15; + for (i = 0; i < ncontinues; ++i) + { + if (i == (ncontinues/2) && ((continuetime & 1) || continuetime > 17)) + continue; + V_DrawContinueIcon(x - (i*30), 68, 0, players[consoleplayer].skin, players[consoleplayer].skincolor); + } + x = BASEVIDWIDTH>>1; + } + + // Spotlight + V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_CACHE)); + + // warping laser + if (continuetime) + { + INT32 w = min(continuetime, 28), brightness = (continuetime>>1) & 7; + if (brightness > 3) + brightness = 8-brightness; + V_DrawFadeFill(x-w, 0, w<<1, 140, 0, 0, (3+brightness)); + } + + if (contskins[1]) + { + if (continuetime > 15) + { + angle_t work = FixedAngle((10*(continuetime-15))<>ANGLETOFINESHIFT; + offsy = FINESINE(work)<<1; + offsx = (27*FINECOSINE(work))>>1; + } + else + offsx = 27<<(FRACBITS-1); + lift[1] = continuetime-10; + if (lift[1] < 0) + lift[1] = 0; + else if (lift[1] > TICRATE+5) + lift[1] = TICRATE+5; + } + + lift[0] = continuetime-5; + if (lift[0] < 0) + lift[0] = 0; + else if (lift[0] > TICRATE+5) + lift[0] = TICRATE+5; + +#define drawchar(dx, dy, n) {\ + sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\ + sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\ + patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_CACHE);\ + V_DrawFixedPatch((dx), (dy), FRACUNIT, (sprframe->flip & (1<= 0) + drawchar((BASEVIDWIDTH<<(FRACBITS-1))-offsx, ((140-lift[0])< (11*TICRATE)) + V_DrawFadeScreen(31, timetonext-(11*TICRATE)); + if (continuetime > ((3*TICRATE) - 10)) + V_DrawFadeScreen(0, (continuetime - ((3*TICRATE) - 10))); } void F_ContinueTicker(void) { if (!imcontinuing) { - // note the setup to prevent 2x reloading - if (timetonext >= 0) - timetonext--; - if (timetonext == 0) - Command_ExitGame_f(); + if (timetonext > 0) + { + if (!(--timetonext)) + { + Command_ExitGame_f(); + return; + } + } } else { - // note the setup to prevent 2x reloading - if (continuetime >= 0) - continuetime--; - if (continuetime == 0) + if (++continuetime == 3*TICRATE) + { G_Continue(); + return; + } + + if (continuetime > 5 && ((continuetime & 1) || continuetime > TICRATE) && (++cont_spr2[0][2]) >= 8) + cont_spr2[0][2] = 0; + + if (continuetime > 10 && (!(continuetime & 1) || continuetime > TICRATE+5) && (++cont_spr2[1][2]) >= 8) + cont_spr2[1][2] = 0; + + if (continuetime == (3*TICRATE)-10) + S_StartSound(NULL, sfx_cdfm56); // or 31 + else if (continuetime == 5) + { + cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT2, NULL); + cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes; + cont_spr2[0][1] = cont_spr2[0][3] = 0; + cont_spr2[0][5] = 2; + } + else if (continuetime == TICRATE) + { + cont_spr2[0][0] = P_GetSkinSprite2(contskins[0], SPR2_CNT3, NULL); + cont_spr2[0][4] = contskins[0]->sprites[cont_spr2[0][0]].numframes; + cont_spr2[0][1] = cont_spr2[0][3] = 0; + } + else if (contskins[1]) + { + if (continuetime == 10) + { + cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT2, NULL); + cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes; + cont_spr2[1][1] = cont_spr2[1][3] = 0; + cont_spr2[1][5] = 2; + } + else if (continuetime == TICRATE+5) + { + cont_spr2[1][0] = P_GetSkinSprite2(contskins[1], SPR2_CNT3, NULL); + cont_spr2[1][4] = contskins[1]->sprites[cont_spr2[1][0]].numframes; + cont_spr2[1][1] = cont_spr2[1][3] = 0; + } + } + } + + if ((++cont_spr2[0][3]) >= cont_spr2[0][5]) + { + cont_spr2[0][3] = 0; + if (++cont_spr2[0][1] >= cont_spr2[0][4]) + cont_spr2[0][1] = 0; + } + + if (contskins[1] && (++cont_spr2[1][3]) >= cont_spr2[1][5]) + { + cont_spr2[1][3] = 0; + if (++cont_spr2[1][1] >= cont_spr2[1][4]) + cont_spr2[1][1] = 0; } } @@ -2568,8 +2761,9 @@ boolean F_ContinueResponder(event_t *event) keypressed = true; imcontinuing = true; - continuetime = TICRATE; - S_StartSound(NULL, sfx_itemup); + S_StartSound(NULL, sfx_kc6b); + I_FadeSong(0, MUSICRATE, &S_StopMusic); + return true; } diff --git a/src/filesrch.c b/src/filesrch.c index 8f157bdd5..13d73b6f4 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -751,7 +751,7 @@ boolean preparefilemenu(boolean samedepth) } else if (ext == EXT_TXT) { - if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt")) + if (!strncmp(dent->d_name, "log-", 4) || !strcmp(dent->d_name, "errorlog.txt")) ext |= EXT_LOADED; } diff --git a/src/g_game.c b/src/g_game.c index e70241269..6c31ce9e3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -172,6 +172,7 @@ static boolean retrying = false; UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage. UINT16 emeralds; +INT32 luabanks[NUM_LUABANKS]; // yes, even in non HAVE_BLUA UINT32 token; // Number of tokens collected in a level UINT32 tokenlist; // List of tokens collected boolean gottoken; // Did you get a token? Used for end of act @@ -215,7 +216,9 @@ UINT16 spacetimetics = 11*TICRATE + (TICRATE/2); UINT16 extralifetics = 4*TICRATE; UINT16 nightslinktics = 2*TICRATE; -INT32 gameovertics = 15*TICRATE; +INT32 gameovertics = 11*TICRATE; + +UINT8 ammoremovaltics = 2*TICRATE; UINT8 use1upSound = 0; UINT8 maxXtraLife = 2; // Max extra lives from rings @@ -883,6 +886,7 @@ static fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) { boolean forcestrafe = false; + boolean forcefullinput = false; INT32 tspeed, forward, side, axis, altaxis, i; const INT32 speed = 1; // these ones used for multiple conditions @@ -956,6 +960,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) if (turnleft) cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); } + if (twodlevel + || (player->mo && (player->mo->flags2 & MF2_TWOD)) + || (!demoplayback && (player->pflags & PF_SLIDING))) + forcefullinput = true; if (twodlevel || (player->mo && (player->mo->flags2 & MF2_TWOD)) || (!demoplayback && (player->climbing @@ -1169,11 +1177,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // No additional acceleration when moving forward/backward and strafing simultaneously. // do this AFTER we cap to MAXPLMOVE so people can't find ways to cheese around this. - // 9-18-2017: ALSO, only do this when using keys to move. Gamepad analog sticks get severely gimped by this - if (!forcestrafe && (((movefkey || movebkey) && side) || ((strafelkey || straferkey) && forward))) + if (!forcefullinput && forward && side) { - forward = FixedMul(forward, 3*FRACUNIT/4); - side = FixedMul(side, 3*FRACUNIT/4); + angle_t angle = R_PointToAngle2(0, 0, side << FRACBITS, forward << FRACBITS); + INT32 maxforward = abs(P_ReturnThrustY(NULL, angle, MAXPLMOVE)); + INT32 maxside = abs(P_ReturnThrustX(NULL, angle, MAXPLMOVE)); + forward = max(min(forward, maxforward), -maxforward); + side = max(min(side, maxside), -maxside); } //Silly hack to make 2d mode *somewhat* playable with no chasecam. @@ -1209,6 +1219,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) { boolean forcestrafe = false; + boolean forcefullinput = false; INT32 tspeed, forward, side, axis, altaxis, i; const INT32 speed = 1; // these ones used for multiple conditions @@ -1280,6 +1291,10 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) if (turnleft) cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]); } + if (twodlevel + || (player->mo && (player->mo->flags2 & MF2_TWOD)) + || (!demoplayback && (player->pflags & PF_SLIDING))) + forcefullinput = true; if (twodlevel || (player->mo && (player->mo->flags2 & MF2_TWOD)) || player->climbing @@ -1490,11 +1505,13 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) // No additional acceleration when moving forward/backward and strafing simultaneously. // do this AFTER we cap to MAXPLMOVE so people can't find ways to cheese around this. - // 9-18-2017: ALSO, only do this when using keys to move. Gamepad analog sticks get severely gimped by this - if (!forcestrafe && (((movefkey || movebkey) && side) || ((strafelkey || straferkey) && forward))) + if (!forcefullinput && forward && side) { - forward = FixedMul(forward, 3*FRACUNIT/4); - side = FixedMul(side, 3*FRACUNIT/4); + angle_t angle = R_PointToAngle2(0, 0, side << FRACBITS, forward << FRACBITS); + INT32 maxforward = abs(P_ReturnThrustY(NULL, angle, MAXPLMOVE)); + INT32 maxside = abs(P_ReturnThrustX(NULL, angle, MAXPLMOVE)); + forward = max(min(forward, maxforward), -maxforward); + side = max(min(side, maxside), -maxside); } //Silly hack to make 2d mode *somewhat* playable with no chasecam. @@ -2081,6 +2098,7 @@ static inline void G_PlayerFinishLevel(INT32 player) p->mo->flags2 &= ~MF2_SHADOW; // cancel invisibility P_FlashPal(p, 0, 0); // Resets + p->starpostscale = 0; p->starpostangle = 0; p->starposttime = 0; p->starpostx = 0; @@ -2096,7 +2114,7 @@ static inline void G_PlayerFinishLevel(INT32 player) // G_PlayerReborn // Called after a player dies. Almost everything is cleared and initialized. // -void G_PlayerReborn(INT32 player) +void G_PlayerReborn(INT32 player, boolean betweenmaps) { player_t *p; INT32 score; @@ -2127,6 +2145,7 @@ void G_PlayerReborn(INT32 player) INT16 starpostz; INT32 starpostnum; INT32 starpostangle; + fixed_t starpostscale; fixed_t jumpfactor; fixed_t height; fixed_t spinheight; @@ -2143,6 +2162,8 @@ void G_PlayerReborn(INT32 player) boolean outofcoop; INT16 bot; SINT8 pity; + INT16 rings; + INT16 spheres; score = players[player].score; lives = players[player].lives; @@ -2182,6 +2203,7 @@ void G_PlayerReborn(INT32 player) starpostz = players[player].starpostz; starpostnum = players[player].starpostnum; starpostangle = players[player].starpostangle; + starpostscale = players[player].starpostscale; jumpfactor = players[player].jumpfactor; height = players[player].height; spinheight = players[player].spinheight; @@ -2197,6 +2219,17 @@ void G_PlayerReborn(INT32 player) bot = players[player].bot; pity = players[player].pity; + if (betweenmaps || !G_IsSpecialStage(gamemap)) + { + rings = (ultimatemode ? 0 : mapheaderinfo[gamemap-1]->startrings); + spheres = 0; + } + else + { + rings = players[player].rings; + spheres = players[player].spheres; + } + p = &players[player]; memset(p, 0, sizeof (*p)); @@ -2237,6 +2270,7 @@ void G_PlayerReborn(INT32 player) p->starpostz = starpostz; p->starpostnum = starpostnum; p->starpostangle = starpostangle; + p->starpostscale = starpostscale; p->jumpfactor = jumpfactor; p->height = height; p->spinheight = spinheight; @@ -2250,6 +2284,8 @@ void G_PlayerReborn(INT32 player) if (bot) p->bot = 1; // reset to AI-controlled p->pity = pity; + p->rings = rings; + p->spheres = spheres; // Don't do anything immediately p->pflags |= PF_USEDOWN; @@ -2257,44 +2293,11 @@ void G_PlayerReborn(INT32 player) p->pflags |= PF_JUMPDOWN; p->playerstate = PST_LIVE; - p->rings = p->spheres = 0; // 0 rings p->panim = PA_IDLE; // standing animation //if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there //p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent - if (p-players == consoleplayer) - { - if (mapmusflags & MUSIC_RELOADRESET) - { - strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); - mapmusname[6] = 0; - mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); - mapmusposition = mapheaderinfo[gamemap-1]->muspos; - } - - // This is in S_Start, but this was not here previously. - // if (cv_resetmusic.value) - // S_StopMusic(); - S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); - } - - if (gametype == GT_COOP) - P_FindEmerald(); // scan for emeralds to hunt for - - // Reset Nights score and max link to 0 on death - p->marescore = p->maxlink = 0; - - // If NiGHTS, find lowest mare to start with. - p->mare = P_FindLowestMare(); - - CONS_Debug(DBG_NIGHTS, M_GetText("Current mare is %d\n"), p->mare); - - if (p->mare == 255) - p->mare = 0; - - p->marelap = p->marebonuslap = 0; - // Check to make sure their color didn't change somehow... if (G_GametypeHasTeams()) { @@ -2313,6 +2316,36 @@ void G_PlayerReborn(INT32 player) CV_SetValue(&cv_playercolor2, skincolor_blueteam); } } + + if (betweenmaps) + return; + + if (p-players == consoleplayer) + { + if (mapmusflags & MUSIC_RELOADRESET) + { + strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); + mapmusname[6] = 0; + mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); + mapmusposition = mapheaderinfo[gamemap-1]->muspos; + } + + // This is in S_Start, but this was not here previously. + // if (RESETMUSIC) + // S_StopMusic(); + S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); + } + + if (gametype == GT_COOP) + P_FindEmerald(); // scan for emeralds to hunt for + + // If NiGHTS, find lowest mare to start with. + p->mare = P_FindLowestMare(); + + CONS_Debug(DBG_NIGHTS, M_GetText("Current mare is %d\n"), p->mare); + + if (p->mare == 255) + p->mare = 0; } // @@ -2368,8 +2401,6 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) P_SpawnPlayer(playernum); - players[playernum].rings = mapheaderinfo[gamemap-1]->startrings; - if (starpost) //Don't even bother with looking for a place to spawn. { P_MovePlayerToStarpost(playernum); @@ -2592,7 +2623,7 @@ void G_DoReborn(INT32 playernum) if (countdowntimeup || (!(netgame || multiplayer) && gametype == GT_COOP)) resetlevel = true; - else if (gametype == GT_COOP && (netgame || multiplayer)) + else if (gametype == GT_COOP && (netgame || multiplayer) && !G_IsSpecialStage(gamemap)) { boolean notgameover = true; @@ -2655,6 +2686,7 @@ void G_DoReborn(INT32 playernum) { if (!playeringame[i]) continue; + players[i].starpostscale = 0; players[i].starpostangle = 0; players[i].starposttime = 0; players[i].starpostx = 0; @@ -2777,6 +2809,7 @@ void G_AddPlayer(INT32 playernum) if (!(cv_coopstarposts.value && (gametype == GT_COOP) && (p->starpostnum < players[i].starpostnum))) continue; + p->starpostscale = players[i].starpostscale; p->starposttime = players[i].starposttime; p->starpostx = players[i].starpostx; p->starposty = players[i].starposty; @@ -3285,9 +3318,11 @@ void G_LoadGameSettings(void) { // defaults spstage_start = 1; - sstage_start = smpstage_start = 50; - sstage_end = smpstage_end = 56; // 7 special stages in vanilla SRB2 + sstage_start = 50; + sstage_end = 56; // 7 special stages in vanilla SRB2 sstage_end++; // plus one weirdo + smpstage_start = 60; + smpstage_end = 66; // 7 multiplayer special stages too // initialize free sfx slots for skin sounds S_InitRuntimeSounds(); @@ -3778,7 +3813,29 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) // File end marker check CHECKPOS - if (READUINT8(save_p) != 0x1d) BADSAVE; + switch (READUINT8(save_p)) + { + case 0xb7: + { + UINT8 i, banksinuse; + CHECKPOS + banksinuse = READUINT8(save_p); + CHECKPOS + if (banksinuse > NUM_LUABANKS) + BADSAVE + for (i = 0; i < banksinuse; i++) + { + (void)READINT32(save_p); + CHECKPOS + } + if (READUINT8(save_p) != 0x1d) + BADSAVE + } + case 0x1d: + break; + default: + BADSAVE + } // done saved = FIL_WriteFile(backup, savebuffer, length); @@ -3862,7 +3919,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean for (i = 0; i < MAXPLAYERS; i++) { players[i].playerstate = PST_REBORN; - players[i].starpostangle = players[i].starpostnum = players[i].starposttime = 0; + players[i].starpostscale = players[i].starpostangle = players[i].starpostnum = players[i].starposttime = 0; players[i].starpostx = players[i].starposty = players[i].starpostz = 0; if (netgame || multiplayer) @@ -4573,7 +4630,7 @@ void G_GhostTicker(void) default: case GHC_RETURNSKIN: g->mo->skin = g->oldmo.skin; - // fallthru + /* FALLTHRU */ case GHC_NORMAL: // Go back to skin color g->mo->color = g->oldmo.color; break; diff --git a/src/g_game.h b/src/g_game.h index 4b63bc180..df1301dd7 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -51,6 +51,7 @@ extern tic_t levelstarttic; // for modding? extern INT16 prevmap, nextmap; extern INT32 gameovertics; +extern UINT8 ammoremovaltics; extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) extern INT16 rw_maximums[NUM_WEAPONS]; extern INT32 pausedelay; @@ -99,7 +100,7 @@ extern INT32 localaiming, localaiming2; // should be an angle_t but signed // void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo); void G_DoReborn(INT32 playernum); -void G_PlayerReborn(INT32 player); +void G_PlayerReborn(INT32 player, boolean betweenmaps); void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean skipprecutscene, boolean FLS); char *G_BuildMapTitle(INT32 mapnum); diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 6bc2c712e..02df290b8 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -30,6 +30,7 @@ #include "../z_zone.h" #include "../v_video.h" #include "../r_draw.h" +#include "../p_setup.h" //Hurdler: 25/04/2000: used for new colormap code in hardware mode //static UINT8 *gr_colormap = NULL; // by default it must be NULL ! (because colormap tables are not initialized) @@ -60,7 +61,6 @@ static const INT32 format2bpp[16] = 2, //14 GR_TEXFMT_AP_88 }; - // This code was originally placed directly in HWR_DrawPatchInCache. // It is now split from it for my sanity! (and the sanity of others) // -- Monster Iestyn (13/02/19) @@ -138,18 +138,37 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm // Alam: SRB2 uses Mingw, HUGS switch (bpp) { - case 2 : texelu16 = (UINT16)((alpha<<8) | texel); + case 2 : // uhhhhhhhh.......... + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha); + texelu16 = (UINT16)((alpha<<8) | texel); memcpy(dest, &texelu16, sizeof(UINT16)); break; case 3 : colortemp = V_GetColor(texel); + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + { + RGBA_t rgbatexel; + rgbatexel.rgba = *(UINT32 *)dest; + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; case 4 : colortemp = V_GetColor(texel); colortemp.s.alpha = alpha; + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + { + RGBA_t rgbatexel; + rgbatexel.rgba = *(UINT32 *)dest; + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + } memcpy(dest, &colortemp, sizeof(RGBA_t)); break; // default is 1 - default: *dest = texel; + default: + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + *dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha); + else + *dest = texel; break; } @@ -233,18 +252,37 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, // Alam: SRB2 uses Mingw, HUGS switch (bpp) { - case 2 : texelu16 = (UINT16)((alpha<<8) | texel); + case 2 : // uhhhhhhhh.......... + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + texel = ASTBlendPixel_8bpp(*(dest+1), texel, originPatch->style, originPatch->alpha); + texelu16 = (UINT16)((alpha<<8) | texel); memcpy(dest, &texelu16, sizeof(UINT16)); break; case 3 : colortemp = V_GetColor(texel); + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + { + RGBA_t rgbatexel; + rgbatexel.rgba = *(UINT32 *)dest; + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + } memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); break; case 4 : colortemp = V_GetColor(texel); colortemp.s.alpha = alpha; + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + { + RGBA_t rgbatexel; + rgbatexel.rgba = *(UINT32 *)dest; + colortemp.rgba = ASTBlendPixel(rgbatexel, colortemp, originPatch->style, originPatch->alpha); + } memcpy(dest, &colortemp, sizeof(RGBA_t)); break; // default is 1 - default: *dest = texel; + default: + if ((originPatch != NULL) && (originPatch->style != AST_COPY)) + *dest = ASTBlendPixel_8bpp(*dest, texel, originPatch->style, originPatch->alpha); + else + *dest = texel; break; } @@ -331,16 +369,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, if (texture->width <= 0 || texture->height <= 0) return; - /*if ((patch->style == AST_TRANSLUCENT) && (patch->alpha <= (10*255/11))) // Alpha style set to translucent? Is the alpha small enough for translucency? - { - if (patch->alpha < 255/11) // Is the patch way too translucent? Don't render then. - continue; - ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawTransFlippedColumnInCache : HWR_DrawTransColumnInCache; - } - else*/ - { - ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache; - } + ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache; x1 = patch->originx; width = SHORT(realpatch->width); @@ -420,6 +449,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight, GrTexInfo *grInfo) { +#ifdef GLIDE_API_COMPATIBILITY // Build the full textures from patches. static const GrLOD_t gr_lods[9] = { @@ -456,6 +486,9 @@ static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight, INT32 j,k; INT32 max,min; +#else + (void)grInfo; +#endif // find a power of 2 width/height if (cv_grrounddown.value) @@ -511,6 +544,7 @@ static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight, } else { +#ifdef GLIDE_API_COMPATIBILITY //size up to nearest power of 2 blockwidth = 1; while (blockwidth < originalwidth) @@ -528,9 +562,14 @@ static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight, if (blockheight > 2048) blockheight = 2048; //I_Error("3D GenerateTexture : too big"); +#else + blockwidth = originalwidth; + blockheight = originalheight; +#endif } // do the boring LOD stuff.. blech! +#ifdef GLIDE_API_COMPATIBILITY if (blockwidth >= blockheight) { max = blockwidth; @@ -562,6 +601,7 @@ static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight, if (blockwidth < blockheight) j += 4; grInfo->aspectRatioLog2 = gr_aspects[j].aspect; +#endif blocksize = blockwidth * blockheight; @@ -650,7 +690,12 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) // Composite the columns together. for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { + size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump); realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); +#ifndef NO_PNG_LUMPS + if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) + realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); +#endif HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, @@ -679,6 +724,13 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm { INT32 newwidth, newheight; +#ifndef NO_PNG_LUMPS + // lump is a png so convert it + size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum); + if ((patch != NULL) && R_IsLumpPNG((const UINT8 *)patch, len)) + patch = R_PNGToPatch((const UINT8 *)patch, len, NULL, true); +#endif + // don't do it twice (like a cache) if (grMipmap->width == 0) { @@ -756,11 +808,13 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm static size_t gr_numtextures; static GLTexture_t *gr_textures; // for ALL Doom textures +static GLTexture_t *gr_textures2; void HWR_InitTextureCache(void) { gr_numtextures = 0; gr_textures = NULL; + gr_textures2 = NULL; } @@ -799,7 +853,10 @@ void HWR_FreeTextureCache(void) // texturecache info, we can free it if (gr_textures) free(gr_textures); + if (gr_textures2) + free(gr_textures2); gr_textures = NULL; + gr_textures2 = NULL; gr_numtextures = 0; } @@ -817,6 +874,9 @@ void HWR_PrepLevelCache(size_t pnumtextures) gr_textures = calloc(pnumtextures, sizeof (*gr_textures)); if (gr_textures == NULL) I_Error("3D can't alloc gr_textures"); + gr_textures2 = calloc(pnumtextures, sizeof (*gr_textures2)); + if (gr_textures2 == NULL) + I_Error("3D can't alloc gr_textures2"); } void HWR_SetPalette(RGBA_t *palette) @@ -847,7 +907,7 @@ GLTexture_t *HWR_GetTexture(INT32 tex) GLTexture_t *grtex; #ifdef PARANOIA if ((unsigned)tex >= gr_numtextures) - I_Error(" HWR_GetTexture: tex >= numtextures\n"); + I_Error("HWR_GetTexture: tex >= numtextures\n"); #endif grtex = &gr_textures[tex]; @@ -862,15 +922,39 @@ GLTexture_t *HWR_GetTexture(INT32 tex) return grtex; } +// HWR_RenderPlane and HWR_RenderPolyObjectPlane need this to get the flat dimensions from a patch. +lumpnum_t gr_patchflat; + +static void HWR_LoadPatchFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) +{ + UINT8 *flat; + patch_t *patch = (patch_t *)W_CacheLumpNum(flatlumpnum, PU_STATIC); + size_t lumplength = W_LumpLength(flatlumpnum); + +#ifndef NO_PNG_LUMPS + if (R_IsLumpPNG((UINT8 *)patch, lumplength)) + patch = R_PNGToPatch((UINT8 *)patch, lumplength, NULL, false); +#endif + + grMipmap->width = (UINT16)SHORT(patch->width); + grMipmap->height = (UINT16)SHORT(patch->height); + + flat = Z_Malloc(grMipmap->width * grMipmap->height, PU_HWRCACHE, &grMipmap->grInfo.data); + memset(flat, TRANSPARENTPIXEL, grMipmap->width * grMipmap->height); + + R_PatchToFlat(patch, flat); +} static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) { size_t size, pflatsize; // setup the texture info +#ifdef GLIDE_API_COMPATIBILITY grMipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64; grMipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_64; grMipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; +#endif grMipmap->grInfo.format = GR_TEXFMT_P_8; grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED; @@ -900,15 +984,20 @@ static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) pflatsize = 64; break; } - grMipmap->width = (UINT16)pflatsize; - grMipmap->height = (UINT16)pflatsize; - // the flat raw data needn't be converted with palettized textures - W_ReadLump(flatlumpnum, Z_Malloc(W_LumpLength(flatlumpnum), - PU_HWRCACHE, &grMipmap->grInfo.data)); + if (R_CheckIfPatch(flatlumpnum)) + HWR_LoadPatchFlat(grMipmap, flatlumpnum); + else + { + grMipmap->width = (UINT16)pflatsize; + grMipmap->height = (UINT16)pflatsize; + + // the flat raw data needn't be converted with palettized textures + W_ReadLump(flatlumpnum, Z_Malloc(W_LumpLength(flatlumpnum), + PU_HWRCACHE, &grMipmap->grInfo.data)); + } } - // Download a Doom 'flat' to the hardware cache and make it ready for use void HWR_GetFlat(lumpnum_t flatlumpnum) { @@ -923,6 +1012,52 @@ void HWR_GetFlat(lumpnum_t flatlumpnum) // The system-memory data can be purged now. Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED); + + gr_patchflat = 0; + if (R_CheckIfPatch(flatlumpnum)) + gr_patchflat = flatlumpnum; +} + +static void HWR_LoadTextureFlat(GLMipmap_t *grMipmap, INT32 texturenum) +{ + UINT8 *flat; + + // setup the texture info +#ifdef GLIDE_API_COMPATIBILITY + grMipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64; + grMipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_64; + grMipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; +#endif + grMipmap->grInfo.format = GR_TEXFMT_P_8; + grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED; + + grMipmap->width = (UINT16)textures[texturenum]->width; + grMipmap->height = (UINT16)textures[texturenum]->height; + + flat = Z_Malloc(grMipmap->width * grMipmap->height, PU_HWRCACHE, &grMipmap->grInfo.data); + memset(flat, TRANSPARENTPIXEL, grMipmap->width * grMipmap->height); + + R_TextureToFlat(texturenum, flat); +} + +void HWR_GetTextureFlat(INT32 texturenum) +{ + GLTexture_t *grtex; +#ifdef PARANOIA + if ((unsigned)texturenum >= gr_numtextures) + I_Error("HWR_GetTextureFlat: texturenum >= numtextures\n"); +#endif + if (texturenum == 0 || texturenum == -1) + return; + grtex = &gr_textures2[texturenum]; + + if (!grtex->mipmap.grInfo.data && !grtex->mipmap.downloaded) + HWR_LoadTextureFlat(&grtex->mipmap, texturenum); + + HWD.pfnSetTexture(&grtex->mipmap); + + // The system-memory data can be purged now. + Z_ChangeTag(grtex->mipmap.grInfo.data, PU_HWRCACHE_UNLOCKED); } // diff --git a/src/hardware/hw_glide.h b/src/hardware/hw_glide.h index 2625d5864..bf91229ef 100644 --- a/src/hardware/hw_glide.h +++ b/src/hardware/hw_glide.h @@ -59,9 +59,11 @@ typedef FxI32 GrTextureFormat_t; typedef struct { +#ifdef GLIDE_API_COMPATIBILITY GrLOD_t smallLodLog2; GrLOD_t largeLodLog2; GrAspectRatio_t aspectRatioLog2; +#endif GrTextureFormat_t format; void *data; } GrTexInfo; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 9656e54e9..c7b06edfd 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -101,6 +101,7 @@ void HWR_FreeTextureCache(void); void HWR_FreeExtraSubsectors(void); void HWR_GetFlat(lumpnum_t flatlumpnum); +void HWR_GetTextureFlat(INT32 texturenum); GLTexture_t *HWR_GetTexture(INT32 tex); void HWR_GetPatch(GLPatch_t *gpatch); void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap); @@ -114,6 +115,8 @@ void HWR_GetFadeMask(lumpnum_t fademasklumpnum); // -------- // hw_draw.c // -------- +extern lumpnum_t gr_patchflat; + extern float gr_patch_scalex; extern float gr_patch_scaley; diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 1d0b79882..c1aff8858 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -188,18 +188,18 @@ light_t *t_lspr[NUMSPRITES] = // Boss 1, (Greenflower) &lspr[NOLIGHT], // SPR_EGGM + &lspr[NOLIGHT], // SPR_EGLZ // Boss 2, (Techno Hill) &lspr[NOLIGHT], // SPR_EGGN - &lspr[NOLIGHT], // SPR_TNKA - &lspr[NOLIGHT], // SPR_TNKB - &lspr[NOLIGHT], // SPR_SPNK + &lspr[NOLIGHT], // SPR_TANK &lspr[NOLIGHT], // SPR_GOOP // Boss 3 (Deep Sea) &lspr[NOLIGHT], // SPR_EGGO - &lspr[NOLIGHT], // SPR_PRPL + &lspr[NOLIGHT], // SPR_SEBH &lspr[NOLIGHT], // SPR_FAKE + &lspr[NOLIGHT], // SPR_SHCK // Boss 4 (Castle Eggman) &lspr[NOLIGHT], // SPR_EGGP @@ -207,11 +207,15 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_EGR1 // Boss 5 (Arid Canyon) - &lspr[NOLIGHT], //SPR_FANG // replaces EGGQ - &lspr[NOLIGHT], //SPR_FBOM - &lspr[NOLIGHT], //SPR_FSGN - &lspr[REDBALL_L], //SPR_BARX // bomb explosion (also used by barrel) - &lspr[NOLIGHT], //SPR_BARD // bomb dust (also used by barrel) + &lspr[NOLIGHT], // SPR_FANG // replaces EGGQ + &lspr[NOLIGHT], // SPR_BRKN + &lspr[NOLIGHT], // SPR_WHAT + &lspr[INVINCIBLE_L], // SPR_VWRE + &lspr[INVINCIBLE_L], // SPR_PROJ + &lspr[NOLIGHT], // SPR_FBOM + &lspr[NOLIGHT], // SPR_FSGN + &lspr[REDBALL_L], // SPR_BARX // bomb explosion (also used by barrel) + &lspr[NOLIGHT], // SPR_BARD // bomb dust (also used by barrel) // Boss 6 (Red Volcano) &lspr[NOLIGHT], // SPR_EEGR @@ -1234,9 +1238,11 @@ static void HWR_SetLight(void) lightmappatch.height = 128; lightmappatch.mipmap.width = 128; lightmappatch.mipmap.height = 128; +#ifdef GLIDE_API_COMPATIBILITY lightmappatch.mipmap.grInfo.smallLodLog2 = GR_LOD_LOG2_128; lightmappatch.mipmap.grInfo.largeLodLog2 = GR_LOD_LOG2_128; lightmappatch.mipmap.grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; +#endif lightmappatch.mipmap.flags = 0; //TF_WRAPXY; // DEBUG: view the overdraw ! } HWD.pfnSetTexture(&lightmappatch.mipmap); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c600800fd..4a075d376 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -70,9 +70,9 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); #endif #ifdef SORTING -void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, +void HWR_AddTransparentFloor(lumpnum_t lumpnum, INT32 texturenum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap); -void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, +void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, INT32 texturenum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap); #else static void HWR_Add3DWater(lumpnum_t lumpnum, extrasubsector_t *xsub, fixed_t fixedheight, @@ -522,7 +522,7 @@ static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color) // Let's see if this c // HWR_RenderPlane : Render a floor or ceiling convex polygon // -----------------+ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, - FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, boolean fogplane, extracolormap_t *planecolormap) + FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, INT32 texturenum, sector_t *FOFsector, UINT8 alpha, boolean fogplane, extracolormap_t *planecolormap) { polyvertex_t * pv; float height; //constant y for all points on the convex flat polygon @@ -530,8 +530,9 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is INT32 nrPlaneVerts; //verts original define of convex flat polygon INT32 i; float flatxref,flatyref; - float fflatsize; + float fflatwidth, fflatheight; INT32 flatflag; + boolean texflat = true; size_t len; float scrollx = 0.0f, scrolly = 0.0f; angle_t angle = 0; @@ -540,6 +541,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is #ifdef ESLOPE pslope_t *slope = NULL; #endif + patch_t *patch; static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; @@ -580,9 +582,10 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is if (nrPlaneVerts < 3) //not even a triangle ? return; - if (nrPlaneVerts > (INT32)UINT16_MAX) // FIXME: exceeds plVerts size + // This check is so inconsistent between functions, it hurts. + if (nrPlaneVerts > INT16_MAX) // FIXME: exceeds plVerts size { - CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, UINT16_MAX); + CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, INT16_MAX); return; } @@ -599,38 +602,47 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is switch (len) { case 4194304: // 2048x2048 lump - fflatsize = 2048.0f; - flatflag = 2047; + fflatwidth = fflatheight = 2048.0f; break; case 1048576: // 1024x1024 lump - fflatsize = 1024.0f; - flatflag = 1023; + fflatwidth = fflatheight = 1024.0f; break; case 262144:// 512x512 lump - fflatsize = 512.0f; - flatflag = 511; + fflatwidth = fflatheight = 512.0f; break; case 65536: // 256x256 lump - fflatsize = 256.0f; - flatflag = 255; + fflatwidth = fflatheight = 256.0f; break; case 16384: // 128x128 lump - fflatsize = 128.0f; - flatflag = 127; + fflatwidth = fflatheight = 128.0f; break; case 1024: // 32x32 lump - fflatsize = 32.0f; - flatflag = 31; + fflatwidth = fflatheight = 32.0f; break; default: // 64x64 lump - fflatsize = 64.0f; - flatflag = 63; + fflatwidth = fflatheight = 64.0f; break; } + flatflag = ((INT32)fflatwidth)-1; + + if (texturenum != 0 && texturenum != -1) + { + fflatwidth = textures[texturenum]->width; + fflatheight = textures[texturenum]->height; + } + else if (gr_patchflat && R_CheckIfPatch(gr_patchflat)) // Just in case? + { + patch = (patch_t *)W_CacheLumpNum(gr_patchflat, PU_STATIC); + fflatwidth = SHORT(patch->width); + fflatheight = SHORT(patch->height); + } + else + texflat = false; + // reference point for flat texture coord for each vertex around the polygon - flatxref = (float)(((fixed_t)pv->x & (~flatflag)) / fflatsize); - flatyref = (float)(((fixed_t)pv->y & (~flatflag)) / fflatsize); + flatxref = (float)(((fixed_t)pv->x & (~flatflag)) / fflatwidth); + flatyref = (float)(((fixed_t)pv->y & (~flatflag)) / fflatheight); // transform v3d = planeVerts; @@ -639,14 +651,14 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight; angle = FOFsector->floorpic_angle; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight; angle = FOFsector->ceilingpic_angle; } } @@ -654,14 +666,14 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatheight; angle = gr_frontsector->floorpic_angle; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatheight; angle = gr_frontsector->ceilingpic_angle; } } @@ -680,17 +692,24 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++) { // Hurdler: add scrolling texture on floor/ceiling - v3d->sow = (float)((pv->x / fflatsize) - flatxref + scrollx); - v3d->tow = (float)(-(pv->y / fflatsize) + flatyref + scrolly); - - //v3d->sow = (float)(pv->x / fflatsize); - //v3d->tow = (float)(pv->y / fflatsize); + if (texflat) + { + v3d->sow = (float)(pv->x / fflatwidth) + scrollx; + v3d->tow = -(float)(pv->y / fflatheight) + scrolly; + } + else + { + v3d->sow = (float)((pv->x / fflatwidth) - flatxref + scrollx); + v3d->tow = (float)(flatyref - (pv->y / fflatheight) + scrolly); + } // Need to rotate before translate if (angle) // Only needs to be done if there's an altered angle { tempxsow = FLOAT_TO_FIXED(v3d->sow); tempytow = FLOAT_TO_FIXED(v3d->tow); + if (texflat) + tempytow = -tempytow; v3d->sow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); v3d->tow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle)))); } @@ -3164,21 +3183,23 @@ static inline void HWR_AddPolyObjectSegs(void) #ifdef POLYOBJECTS_PLANES static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, - FBITFIELD blendmode, UINT8 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, + FBITFIELD blendmode, UINT8 lightlevel, lumpnum_t lumpnum, INT32 texturenum, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap) { float height; //constant y for all points on the convex flat polygon FOutVector *v3d; INT32 i; float flatxref,flatyref; - float fflatsize; + float fflatwidth, fflatheight; INT32 flatflag; + boolean texflat = true; size_t len; float scrollx = 0.0f, scrolly = 0.0f; angle_t angle = 0; FSurfaceInfo Surf; fixed_t tempxsow, tempytow; size_t nrPlaneVerts; + patch_t *patch; static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; @@ -3209,38 +3230,47 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, switch (len) { case 4194304: // 2048x2048 lump - fflatsize = 2048.0f; - flatflag = 2047; + fflatwidth = fflatheight = 2048.0f; break; case 1048576: // 1024x1024 lump - fflatsize = 1024.0f; - flatflag = 1023; + fflatwidth = fflatheight = 1024.0f; break; case 262144:// 512x512 lump - fflatsize = 512.0f; - flatflag = 511; + fflatwidth = fflatheight = 512.0f; break; case 65536: // 256x256 lump - fflatsize = 256.0f; - flatflag = 255; + fflatwidth = fflatheight = 256.0f; break; case 16384: // 128x128 lump - fflatsize = 128.0f; - flatflag = 127; + fflatwidth = fflatheight = 128.0f; break; case 1024: // 32x32 lump - fflatsize = 32.0f; - flatflag = 31; + fflatwidth = fflatheight = 32.0f; break; default: // 64x64 lump - fflatsize = 64.0f; - flatflag = 63; + fflatwidth = fflatheight = 64.0f; break; } + flatflag = ((INT32)fflatwidth)-1; + + if (texturenum != 0 && texturenum != -1) + { + fflatwidth = textures[texturenum]->width; + fflatheight = textures[texturenum]->height; + } + else if (gr_patchflat && R_CheckIfPatch(gr_patchflat)) // Just in case? + { + patch = (patch_t *)W_CacheLumpNum(gr_patchflat, PU_STATIC); + fflatwidth = SHORT(patch->width); + fflatheight = SHORT(patch->height); + } + else + texflat = false; + // reference point for flat texture coord for each vertex around the polygon - flatxref = (float)(((fixed_t)FIXED_TO_FLOAT(polysector->origVerts[0].x) & (~flatflag)) / fflatsize); - flatyref = (float)(((fixed_t)FIXED_TO_FLOAT(polysector->origVerts[0].y) & (~flatflag)) / fflatsize); + flatxref = (float)((polysector->origVerts[0].x & (~flatflag)) / fflatwidth); + flatyref = (float)((polysector->origVerts[0].y & (~flatflag)) / fflatheight); // transform v3d = planeVerts; @@ -3249,14 +3279,14 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatheight; angle = FOFsector->floorpic_angle>>ANGLETOFINESHIFT; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(FOFsector->ceiling_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(FOFsector->ceiling_yoffs)/fflatheight; angle = FOFsector->ceilingpic_angle>>ANGLETOFINESHIFT; } } @@ -3264,14 +3294,14 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, { if (!isceiling) // it's a floor { - scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatheight; angle = gr_frontsector->floorpic_angle>>ANGLETOFINESHIFT; } else // it's a ceiling { - scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatsize; - scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatsize; + scrollx = FIXED_TO_FLOAT(gr_frontsector->ceiling_xoffs)/fflatwidth; + scrolly = FIXED_TO_FLOAT(gr_frontsector->ceiling_yoffs)/fflatheight; angle = gr_frontsector->ceilingpic_angle>>ANGLETOFINESHIFT; } } @@ -3294,15 +3324,26 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, for (i = 0; i < (INT32)nrPlaneVerts; i++,v3d++) { - // Hurdler: add scrolling texture on floor/ceiling - v3d->sow = (float)((FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatsize) - flatxref + scrollx); // Go from the polysector's original vertex locations - v3d->tow = (float)(flatyref - (FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatsize) + scrolly); // Means the flat is offset based on the original vertex locations + // Go from the polysector's original vertex locations + // Means the flat is offset based on the original vertex locations + if (texflat) + { + v3d->sow = (float)(FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) + scrollx; + v3d->tow = -(float)(FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly; + } + else + { + v3d->sow = (float)((FIXED_TO_FLOAT(polysector->origVerts[i].x) / fflatwidth) - flatxref + scrollx); + v3d->tow = (float)(flatyref - (FIXED_TO_FLOAT(polysector->origVerts[i].y) / fflatheight) + scrolly); + } // Need to rotate before translate if (angle) // Only needs to be done if there's an altered angle { tempxsow = FLOAT_TO_FIXED(v3d->sow); tempytow = FLOAT_TO_FIXED(v3d->tow); + if (texflat) + tempytow = -tempytow; v3d->sow = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); v3d->tow = (FIXED_TO_FLOAT(-FixedMul(tempxsow, FINESINE(angle)) - FixedMul(tempytow, FINECOSINE(angle)))); } @@ -3333,6 +3374,7 @@ static void HWR_AddPolyObjectPlanes(void) { size_t i; sector_t *polyobjsector; + INT32 light = 0; // Polyobject Planes need their own function for drawing because they don't have extrasubsectors by themselves // It should be okay because polyobjects should always be convex anyway @@ -3351,19 +3393,23 @@ static void HWR_AddPolyObjectPlanes(void) && polyobjsector->floorheight >= gr_frontsector->floorheight && (viewz < polyobjsector->floorheight)) { + light = R_GetPlaneLight(gr_frontsector, polyobjsector->floorheight, true); if (po_ptrs[i]->translucency > 0) { FSurfaceInfo Surf; - FBITFIELD blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); - HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], false, polyobjsector->floorheight, - polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL); + FBITFIELD blendmode; + memset(&Surf, 0x00, sizeof(Surf)); + blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); + HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, levelflats[polyobjsector->floorpic].texturenum, po_ptrs[i], false, polyobjsector->floorheight, + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.FlatColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); } else { HWR_GetFlat(levelflats[polyobjsector->floorpic].lumpnum); + HWR_GetTextureFlat(levelflats[polyobjsector->floorpic].texturenum); HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude, - polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum, - polyobjsector, 255, NULL); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), levelflats[polyobjsector->floorpic].lumpnum, levelflats[polyobjsector->floorpic].texturenum, + polyobjsector, 255, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); } } @@ -3371,21 +3417,23 @@ static void HWR_AddPolyObjectPlanes(void) && polyobjsector->ceilingheight <= gr_frontsector->ceilingheight && (viewz > polyobjsector->ceilingheight)) { + light = R_GetPlaneLight(gr_frontsector, polyobjsector->ceilingheight, true); if (po_ptrs[i]->translucency > 0) { FSurfaceInfo Surf; FBITFIELD blendmode; memset(&Surf, 0x00, sizeof(Surf)); blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf); - HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], true, polyobjsector->ceilingheight, - polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL); + HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, levelflats[polyobjsector->floorpic].texturenum, po_ptrs[i], true, polyobjsector->ceilingheight, + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), Surf.FlatColor.s.alpha, polyobjsector, blendmode, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); } else { HWR_GetFlat(levelflats[polyobjsector->ceilingpic].lumpnum); + HWR_GetTextureFlat(levelflats[polyobjsector->ceilingpic].texturenum); HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude, - polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum, - polyobjsector, 255, NULL); + (light == -1 ? gr_frontsector->lightlevel : *gr_frontsector->lightlist[light].lightlevel), levelflats[polyobjsector->floorpic].lumpnum, levelflats[polyobjsector->floorpic].texturenum, + polyobjsector, 255, (light == -1 ? gr_frontsector->extra_colormap : *gr_frontsector->lightlist[light].extra_colormap)); } } } @@ -3536,11 +3584,12 @@ static void HWR_Subsector(size_t num) if (sub->validcount != validcount) { HWR_GetFlat(levelflats[gr_frontsector->floorpic].lumpnum); + HWR_GetTextureFlat(levelflats[gr_frontsector->floorpic].texturenum); HWR_RenderPlane(gr_frontsector, &extrasubsectors[num], false, // Hack to make things continue to work around slopes. locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight, // We now return you to your regularly scheduled rendering. - PF_Occlude, floorlightlevel, levelflats[gr_frontsector->floorpic].lumpnum, NULL, 255, false, floorcolormap); + PF_Occlude, floorlightlevel, levelflats[gr_frontsector->floorpic].lumpnum, levelflats[gr_frontsector->floorpic].texturenum, NULL, 255, false, floorcolormap); } } else @@ -3558,11 +3607,12 @@ static void HWR_Subsector(size_t num) if (sub->validcount != validcount) { HWR_GetFlat(levelflats[gr_frontsector->ceilingpic].lumpnum); + HWR_GetTextureFlat(levelflats[gr_frontsector->ceilingpic].texturenum); HWR_RenderPlane(NULL, &extrasubsectors[num], true, // Hack to make things continue to work around slopes. locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight, // We now return you to your regularly scheduled rendering. - PF_Occlude, ceilinglightlevel, levelflats[gr_frontsector->ceilingpic].lumpnum,NULL, 255, false, ceilingcolormap); + PF_Occlude, ceilinglightlevel, levelflats[gr_frontsector->ceilingpic].lumpnum, levelflats[gr_frontsector->ceilingpic].texturenum, NULL, 255, false, ceilingcolormap); } } else @@ -3621,7 +3671,7 @@ static void HWR_Subsector(size_t num) else alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG); - HWR_AddTransparentFloor(0, + HWR_AddTransparentFloor(0, 0, &extrasubsectors[num], false, *rover->bottomheight, @@ -3640,6 +3690,7 @@ static void HWR_Subsector(size_t num) rover->alpha-1, rover->master->frontsector); #else HWR_AddTransparentFloor(levelflats[*rover->bottompic].lumpnum, + levelflats[*rover->bottompic].texturenum, &extrasubsectors[num], false, *rover->bottomheight, @@ -3651,8 +3702,9 @@ static void HWR_Subsector(size_t num) else { HWR_GetFlat(levelflats[*rover->bottompic].lumpnum); + HWR_GetTextureFlat(levelflats[*rover->bottompic].texturenum); light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); - HWR_RenderPlane(NULL, &extrasubsectors[num], false, *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum, + HWR_RenderPlane(NULL, &extrasubsectors[num], false, *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum, levelflats[*rover->bottompic].texturenum, rover->master->frontsector, 255, false, *gr_frontsector->lightlist[light].extra_colormap); } } @@ -3684,7 +3736,7 @@ static void HWR_Subsector(size_t num) else alpha = HWR_FogBlockAlpha(*gr_frontsector->lightlist[light].lightlevel, NORMALFOG); - HWR_AddTransparentFloor(0, + HWR_AddTransparentFloor(0, 0, &extrasubsectors[num], true, *rover->topheight, @@ -3703,6 +3755,7 @@ static void HWR_Subsector(size_t num) rover->alpha-1, rover->master->frontsector); #else HWR_AddTransparentFloor(levelflats[*rover->toppic].lumpnum, + levelflats[*rover->bottompic].texturenum, &extrasubsectors[num], true, *rover->topheight, @@ -3715,8 +3768,9 @@ static void HWR_Subsector(size_t num) else { HWR_GetFlat(levelflats[*rover->toppic].lumpnum); + HWR_GetTextureFlat(levelflats[*rover->toppic].texturenum); light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); - HWR_RenderPlane(NULL, &extrasubsectors[num], true, *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum, + HWR_RenderPlane(NULL, &extrasubsectors[num], true, *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum, levelflats[*rover->toppic].texturenum, rover->master->frontsector, 255, false, *gr_frontsector->lightlist[light].extra_colormap); } } @@ -5045,6 +5099,7 @@ typedef struct fixed_t fixedheight; INT32 lightlevel; lumpnum_t lumpnum; + INT32 texturenum; INT32 alpha; sector_t *FOFSector; FBITFIELD blend; @@ -5063,6 +5118,7 @@ typedef struct fixed_t fixedheight; INT32 lightlevel; lumpnum_t lumpnum; + INT32 texturenum; INT32 alpha; sector_t *FOFSector; FBITFIELD blend; @@ -5093,7 +5149,7 @@ static INT32 drawcount = 0; #define MAX_TRANSPARENTFLOOR 512 // This will likely turn into a copy of HWR_Add3DWater and replace it. -void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, +void HWR_AddTransparentFloor(lumpnum_t lumpnum, INT32 texturenum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap) { static size_t allocedplanes = 0; @@ -5112,6 +5168,7 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean planeinfo[numplanes].fixedheight = fixedheight; planeinfo[numplanes].lightlevel = lightlevel; planeinfo[numplanes].lumpnum = lumpnum; + planeinfo[numplanes].texturenum = texturenum; planeinfo[numplanes].xsub = xsub; planeinfo[numplanes].alpha = alpha; planeinfo[numplanes].FOFSector = FOFSector; @@ -5125,7 +5182,7 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean // Adding this for now until I can create extrasubsector info for polyobjects // When that happens it'll just be done through HWR_AddTransparentFloor and HWR_RenderPlane -void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, +void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, INT32 texturenum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap) { static size_t allocedpolyplanes = 0; @@ -5144,6 +5201,7 @@ void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, polyplaneinfo[numpolyplanes].fixedheight = fixedheight; polyplaneinfo[numpolyplanes].lightlevel = lightlevel; polyplaneinfo[numpolyplanes].lumpnum = lumpnum; + polyplaneinfo[numpolyplanes].texturenum = texturenum; polyplaneinfo[numpolyplanes].polysector = polysector; polyplaneinfo[numpolyplanes].alpha = alpha; polyplaneinfo[numpolyplanes].FOFSector = FOFSector; @@ -5305,9 +5363,12 @@ static void HWR_CreateDrawNodes(void) gr_frontsector = NULL; if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture)) + { HWR_GetFlat(sortnode[sortindex[i]].plane->lumpnum); + HWR_GetTextureFlat(sortnode[sortindex[i]].plane->texturenum); + } HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel, - sortnode[sortindex[i]].plane->lumpnum, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->fogplane, sortnode[sortindex[i]].plane->planecolormap); + sortnode[sortindex[i]].plane->lumpnum, sortnode[sortindex[i]].plane->texturenum, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->fogplane, sortnode[sortindex[i]].plane->planecolormap); } else if (sortnode[sortindex[i]].polyplane) { @@ -5315,9 +5376,12 @@ static void HWR_CreateDrawNodes(void) gr_frontsector = NULL; if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture)) + { HWR_GetFlat(sortnode[sortindex[i]].polyplane->lumpnum); + HWR_GetTextureFlat(sortnode[sortindex[i]].polyplane->texturenum); + } HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel, - sortnode[sortindex[i]].polyplane->lumpnum, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap); + sortnode[sortindex[i]].polyplane->lumpnum, sortnode[sortindex[i]].polyplane->texturenum, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap); } else if (sortnode[sortindex[i]].wall) { diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index d4728315a..cd1b957f0 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -26,6 +26,7 @@ #include #include +#include "../d_main.h" #include "../doomdef.h" #include "../doomstat.h" #include "../fastcmp.h" @@ -70,6 +71,10 @@ #endif #endif +#ifndef errno +#include "errno.h" +#endif + #define NUMVERTEXNORMALS 162 float avertexnormals[NUMVERTEXNORMALS][3] = { {-0.525731f, 0.000000f, 0.850651f}, @@ -294,7 +299,8 @@ static md2_model_t *md2_readModel(const char *filename) if (model == NULL) return 0; - file = fopen(filename, "rb"); + //Filename checking fixed ~Monster Iestyn and Golden + file = fopen(va("%s"PATHSEP"%s", srb2home, filename), "rb"); if (!file) { free(model); @@ -523,7 +529,8 @@ static GrTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ #endif #endif png_FILE_p png_FILE; - char *pngfilename = va("md2/%s", filename); + //Filename checking fixed ~Monster Iestyn and Golden + char *pngfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); FIL_ForceExtension(pngfilename, ".png"); png_FILE = fopen(pngfilename, "rb"); @@ -651,7 +658,8 @@ static GrTextureFormat_t PCX_Load(const char *filename, int *w, int *h, size_t pw, ph, size, ptr = 0; INT32 ch, rep; FILE *file; - char *pcxfilename = va("md2/%s", filename); + //Filename checking fixed ~Monster Iestyn and Golden + char *pcxfilename = va("%s"PATHSEP"md2"PATHSEP"%s", srb2home, filename); FIL_ForceExtension(pcxfilename, ".pcx"); file = fopen(pcxfilename, "rb"); @@ -747,10 +755,12 @@ static void md2_loadTexture(md2_t *model) grpatch->mipmap.width = (UINT16)w; grpatch->mipmap.height = (UINT16)h; +#ifdef GLIDE_API_COMPATIBILITY // not correct! grpatch->mipmap.grInfo.smallLodLog2 = GR_LOD_LOG2_256; grpatch->mipmap.grInfo.largeLodLog2 = GR_LOD_LOG2_256; grpatch->mipmap.grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; +#endif } HWD.pfnSetTexture(&grpatch->mipmap); HWR_UnlockCachedPatch(grpatch); @@ -798,10 +808,12 @@ static void md2_loadBlendTexture(md2_t *model) grpatch->mipmap.width = (UINT16)w; grpatch->mipmap.height = (UINT16)h; +#ifdef GLIDE_API_COMPATIBILITY // not correct! grpatch->mipmap.grInfo.smallLodLog2 = GR_LOD_LOG2_256; grpatch->mipmap.grInfo.largeLodLog2 = GR_LOD_LOG2_256; grpatch->mipmap.grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; +#endif } HWD.pfnSetTexture(&grpatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary HWR_UnlockCachedPatch(grpatch); @@ -841,11 +853,12 @@ void HWR_InitMD2(void) } // read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { - CONS_Printf("%s", M_GetText("Error while loading md2.dat\n")); + CONS_Printf("%s %s\n", M_GetText("Error while loading md2.dat:"), strerror(errno)); nomd2s = true; return; } @@ -907,7 +920,8 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup CONS_Printf("AddPlayerMD2()...\n"); // read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { @@ -952,7 +966,8 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu return; // Read the md2.dat file - f = fopen("md2.dat", "rt"); + //Filename checking fixed ~Monster Iestyn and Golden + f = fopen(va("%s"PATHSEP"%s", srb2home, "md2.dat"), "rt"); if (!f) { @@ -1198,7 +1213,7 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p if (!md2 || !skin) return 0; - if ((unsigned)(spr2 & ~FF_SPR2SUPER) >= free_spr2) + if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2) return 0; while (!(md2->model->spr2frames[spr2*2 + 1]) diff --git a/src/info.c b/src/info.c index 4a02e1d0a..b2e6d5689 100644 --- a/src/info.c +++ b/src/info.c @@ -75,19 +75,19 @@ char sprnames[NUMSPRITES + 1][5] = "JETF", // Boss jet fumes // Boss 1 (Greenflower) - "EGGM", + "EGGM", // Boss 1 + "EGLZ", // Boss 1 Junk // Boss 2 (Techno Hill) "EGGN", // Boss 2 - "TNKA", // Boss 2 Tank 1 - "TNKB", // Boss 2 Tank 2 - "SPNK", // Boss 2 Spigot + "TANK", // Boss 2 Junk "GOOP", // Boss 2 Goop // Boss 3 (Deep Sea) "EGGO", // Boss 3 - "PRPL", // Boss 3 Propeller + "SEBH", // Boss 3 Junk "FAKE", // Boss 3 Fakemobile + "SHCK", // Boss 3 Shockwave // Boss 4 (Castle Eggman) "EGGP", @@ -96,6 +96,10 @@ char sprnames[NUMSPRITES + 1][5] = // Boss 5 (Arid Canyon) "FANG", // replaces EGGQ + "BRKN", // broken robot chunk + "WHAT", // alart + "VWRE", + "PROJ", // projector light "FBOM", "FSGN", "BARX", // bomb explosion (also used by barrel) @@ -216,11 +220,11 @@ char sprnames[NUMSPRITES + 1][5] = "GARG", // Deep Sea Gargoyle "SEWE", // Deep Sea Seaweed "DRIP", // Dripping water - "CRL1", // Coral 1 - "CRL2", // Coral 2 - "CRL3", // Coral 3 + "CORL", // Coral "BCRY", // Blue Crystal "KELP", // Kelp + "ALGA", // Animated algae top + "ALGB", // Animated algae segment "DSTG", // DSZ Stalagmites "LIBE", // DSZ Light beam @@ -250,7 +254,7 @@ char sprnames[NUMSPRITES + 1][5] = // Arid Canyon Scenery "BTBL", // Big tumbleweed "STBL", // Small tumbleweed - "CACT", // Cacti sprites + "CACT", // Cacti "WWSG", // Caution Sign "WWS2", // Cacti Sign "WWS3", // Sharp Turn Sign @@ -585,8 +589,14 @@ char spr2names[NUMPLAYERSPRITES][5] = "TALA", "TALB", + "CNT1", + "CNT2", + "CNT3", + "CNT4", + "SIGN", "LIFE", + "XTRA", }; playersprite_t free_spr2 = SPR2_FIRSTFREESLOT; @@ -682,8 +692,14 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_TAL9, // SPR2_TALA, SPR2_TAL0, // SPR2_TALB, + SPR2_WAIT, // SPR2_CNT1, + SPR2_FALL, // SPR2_CNT2, + SPR2_SPNG, // SPR2_CNT3, + SPR2_CNT1, // SPR2_CNT4, + 0, // SPR2_SIGN, 0, // SPR2_LIFE, + 0, // SPR2_XTRA (should never be referenced) }; @@ -736,7 +752,7 @@ state_t states[NUMSTATES] = // CA_FLY/CA_SWIM {SPR_PLAY, SPR2_FLY , 2, {NULL}, 0, 0, S_PLAY_FLY}, // S_PLAY_FLY - {SPR_PLAY, SPR2_SWIM, 2, {NULL}, 0, 0, S_PLAY_SWIM}, // S_PLAY_SWIM + {SPR_PLAY, SPR2_SWIM, 4, {NULL}, 0, 0, S_PLAY_SWIM}, // S_PLAY_SWIM {SPR_PLAY, SPR2_TIRE, 12, {NULL}, 0, 0, S_PLAY_FLY_TIRED}, // S_PLAY_FLY_TIRED // CA_GLIDEANDCLIMB @@ -1203,49 +1219,58 @@ state_t states[NUMSTATES] = {SPR_BOM3, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_SONIC3KBOSSEXPLOSION6}, // S_SONIC3KBOSSEXPLOSION5 {SPR_BOM3, FF_FULLBRIGHT|5, 4, {NULL}, 0, 0, S_NULL}, // S_SONIC3KBOSSEXPLOSION6 - {SPR_JETF, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_JETFUME2}, // S_JETFUME1 - {SPR_NULL, 0, 1, {NULL}, 0, 0, S_JETFUME1}, // S_JETFUME2 + {SPR_JETF, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 2, 1, S_NULL}, // S_JETFUME1 // Boss 1 {SPR_EGGM, 0, 1, {A_Boss1Chase}, 0, 0, S_EGGMOBILE_STND}, // S_EGGMOBILE_STND + {SPR_EGGM, FF_ANIMATE|17, 35, {A_FaceTarget}, 1, 2, S_EGGMOBILE_STND}, // S_EGGMOBILE_ROFL {SPR_EGGM, 1, 3, {A_FaceTarget}, 0, 0, S_EGGMOBILE_LATK2}, // S_EGGMOBILE_LATK1 {SPR_EGGM, 2, 15, {NULL}, 0, 0, S_EGGMOBILE_LATK3}, // S_EGGMOBILE_LATK2 - {SPR_EGGM, 3, 2, {A_FaceTarget}, 0, 0, S_EGGMOBILE_LATK4}, // S_EGGMOBILE_LATK3 - {SPR_EGGM, 4, 1, {NULL}, 0, 0, S_EGGMOBILE_LATK5}, // S_EGGMOBILE_LATK4 - {SPR_EGGM, 5, 1, {NULL}, 0, 0, S_EGGMOBILE_LATK6}, // S_EGGMOBILE_LATK5 - {SPR_EGGM, 6, 1, {NULL}, 0, 0, S_EGGMOBILE_LATK7}, // S_EGGMOBILE_LATK6 - {SPR_EGGM, 7, 1, {NULL}, 0, 0, S_EGGMOBILE_LATK8}, // S_EGGMOBILE_LATK7 - {SPR_EGGM, 8, 45, {A_Boss1Laser}, MT_LASER, 0, S_EGGMOBILE_LATK9}, // S_EGGMOBILE_LATK8 - {SPR_EGGM, 9, 10, {NULL}, 0, 0, S_EGGMOBILE_LATK10}, // S_EGGMOBILE_LATK9 - {SPR_EGGM, 10, 2, {NULL}, 0, 0, S_EGGMOBILE_STND}, // S_EGGMOBILE_LATK10 - {SPR_EGGM, 11, 3, {A_FaceTarget}, 0, 0, S_EGGMOBILE_RATK2}, // S_EGGMOBILE_RATK1 - {SPR_EGGM, 12, 15, {NULL}, 0, 0, S_EGGMOBILE_RATK3}, // S_EGGMOBILE_RATK2 - {SPR_EGGM, 13, 2, {A_FaceTarget}, 0, 0, S_EGGMOBILE_RATK4}, // S_EGGMOBILE_RATK3 - {SPR_EGGM, 14, 1, {NULL}, 0, 0, S_EGGMOBILE_RATK5}, // S_EGGMOBILE_RATK4 - {SPR_EGGM, 15, 1, {NULL}, 0, 0, S_EGGMOBILE_RATK6}, // S_EGGMOBILE_RATK5 - {SPR_EGGM, 16, 1, {NULL}, 0, 0, S_EGGMOBILE_RATK7}, // S_EGGMOBILE_RATK6 - {SPR_EGGM, 17, 1, {NULL}, 0, 0, S_EGGMOBILE_RATK8}, // S_EGGMOBILE_RATK7 - {SPR_EGGM, 18, 45, {A_Boss1Laser}, MT_LASER, 1, S_EGGMOBILE_RATK9}, // S_EGGMOBILE_RATK8 - {SPR_EGGM, 19, 10, {NULL}, 0, 0, S_EGGMOBILE_RATK10}, // S_EGGMOBILE_RATK9 - {SPR_EGGM, 20, 2, {NULL}, 0, 0, S_EGGMOBILE_STND}, // S_EGGMOBILE_RATK10 - {SPR_EGGM, 3, 12, {NULL}, 0, 0, S_EGGMOBILE_PANIC2}, // S_EGGMOBILE_PANIC1 - {SPR_EGGM, 4, 45, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC3}, // S_EGGMOBILE_PANIC2 - {SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC4}, // S_EGGMOBILE_PANIC3 - {SPR_EGGM, 4, 45, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC5 }, // S_EGGMOBILE_PANIC4 - {SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC6}, // S_EGGMOBILE_PANIC5 - {SPR_EGGM, 4, 45, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC7 }, // S_EGGMOBILE_PANIC6 - {SPR_EGGM, 0, 35, {NULL}, 0, 0, S_EGGMOBILE_STND }, // S_EGGMOBILE_PANIC7 - {SPR_EGGM, 21, 24, {A_Pain}, 0, 0, S_EGGMOBILE_PAIN2}, // S_EGGMOBILE_PAIN - {SPR_EGGM, 21, 16, {A_SkullAttack}, 1, 1, S_EGGMOBILE_STND}, // S_EGGMOBILE_PAIN2 - {SPR_EGGM, 22, 2, {A_Fall}, 0, 0, S_EGGMOBILE_DIE2}, // S_EGGMOBILE_DIE1 - {SPR_EGGM, 22, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE3}, // S_EGGMOBILE_DIE2 - {SPR_EGGM, 22, 0, {A_Repeat}, 17, S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE4}, // S_EGGMOBILE_DIE3 - {SPR_EGGM, 22, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE_DIE4 - {SPR_EGGM, 23, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_FLEE2}, // S_EGGMOBILE_FLEE1 - {SPR_EGGM, 24, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_FLEE1}, // S_EGGMOBILE_FLEE2 + {SPR_EGGM, 3, 2, {NULL}, 0, 0, S_EGGMOBILE_LATK4}, // S_EGGMOBILE_LATK3 + {SPR_EGGM, 4, 2, {A_FaceTarget}, 0, 0, S_EGGMOBILE_LATK5}, // S_EGGMOBILE_LATK4 + {SPR_EGGM, 6, 0, {A_PrepareRepeat}, 45, 0, S_EGGMOBILE_LATK6}, // S_EGGMOBILE_LATK5 + {SPR_EGGM, 5, 1, {A_Boss1Laser}, MT_LASER, 0, S_EGGMOBILE_LATK7}, // S_EGGMOBILE_LATK6 + {SPR_EGGM, 6, 1, {A_Boss1Laser}, MT_LASER, (1<<16), S_EGGMOBILE_LATK8}, // S_EGGMOBILE_LATK7 + {SPR_EGGM, 5, 0, {A_Repeat}, 45, S_EGGMOBILE_LATK6, S_EGGMOBILE_LATK9}, // S_EGGMOBILE_LATK8 + {SPR_EGGM, 8, 2, {NULL}, 0, 0, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_LATK9 + {SPR_EGGM, 9, 3, {A_FaceTarget}, 0, 0, S_EGGMOBILE_RATK2}, // S_EGGMOBILE_RATK1 + {SPR_EGGM, 10, 15, {NULL}, 0, 0, S_EGGMOBILE_RATK3}, // S_EGGMOBILE_RATK2 + {SPR_EGGM, 11, 2, {NULL}, 0, 0, S_EGGMOBILE_RATK4}, // S_EGGMOBILE_RATK3 + {SPR_EGGM, 12, 2, {A_FaceTarget}, 0, 0, S_EGGMOBILE_RATK5}, // S_EGGMOBILE_RATK4 + {SPR_EGGM, 14, 0, {A_PrepareRepeat}, 45, 0, S_EGGMOBILE_RATK6}, // S_EGGMOBILE_RATK5 + {SPR_EGGM, 13, 1, {A_Boss1Laser}, MT_LASER, 1, S_EGGMOBILE_RATK7}, // S_EGGMOBILE_RATK6 + {SPR_EGGM, 14, 1, {A_Boss1Laser}, MT_LASER, 1|(1<<16), S_EGGMOBILE_RATK8}, // S_EGGMOBILE_RATK7 + {SPR_EGGM, 13, 0, {A_Repeat}, 45, S_EGGMOBILE_RATK6, S_EGGMOBILE_RATK9}, // S_EGGMOBILE_RATK8 + {SPR_EGGM, 16, 2, {NULL}, 0, 0, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_RATK9 + {SPR_EGGM, 0, 0, {A_PrepareRepeat}, 45, 0, S_EGGMOBILE_PANIC2}, // S_EGGMOBILE_PANIC1 + {SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget}, 3, 4, S_EGGMOBILE_PANIC3}, // S_EGGMOBILE_PANIC2 + {SPR_EGGM, 7, 1, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC4}, // S_EGGMOBILE_PANIC3 + {SPR_EGGM, 6, 1, {A_Boss1Laser}, MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC5}, // S_EGGMOBILE_PANIC4 + {SPR_EGGM, 6, 0, {A_Repeat}, 45, S_EGGMOBILE_PANIC3, S_EGGMOBILE_PANIC6}, // S_EGGMOBILE_PANIC5 + {SPR_EGGM, 0, 0, {A_PrepareRepeat}, 45, 0, S_EGGMOBILE_PANIC7}, // S_EGGMOBILE_PANIC6 + {SPR_EGGM, FF_ANIMATE|9, 16, {A_FaceTarget}, 3, 4, S_EGGMOBILE_PANIC8}, // S_EGGMOBILE_PANIC7 + {SPR_EGGM, 15, 1, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC9}, // S_EGGMOBILE_PANIC8 + {SPR_EGGM, 14, 1, {A_Boss1Laser}, MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC10}, // S_EGGMOBILE_PANIC9 + {SPR_EGGM, 14, 0, {A_Repeat}, 45, S_EGGMOBILE_PANIC8, S_EGGMOBILE_PANIC11}, // S_EGGMOBILE_PANIC10 + {SPR_EGGM, 0, 0, {A_PrepareRepeat}, 45, 0, S_EGGMOBILE_PANIC12}, // S_EGGMOBILE_PANIC11 + {SPR_EGGM, FF_ANIMATE|1, 16, {A_FaceTarget}, 3, 4, S_EGGMOBILE_PANIC13}, // S_EGGMOBILE_PANIC12 + {SPR_EGGM, 7, 1, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC14}, // S_EGGMOBILE_PANIC13 + {SPR_EGGM, 6, 1, {A_Boss1Laser}, MT_LASER, 2|(1<<16), S_EGGMOBILE_PANIC15}, // S_EGGMOBILE_PANIC14 + {SPR_EGGM, 6, 0, {A_Repeat}, 45, S_EGGMOBILE_PANIC13, S_EGGMOBILE_ROFL}, // S_EGGMOBILE_PANIC15 + {SPR_EGGM, 19, 24, {A_Pain}, 0, 0, S_EGGMOBILE_PAIN2}, // S_EGGMOBILE_PAIN + {SPR_EGGM, 19, 16, {A_SkullAttack}, 3, 1, S_EGGMOBILE_STND}, // S_EGGMOBILE_PAIN2 + {SPR_EGGM, 20, 2, {A_Fall}, 17, 0, S_EGGMOBILE_DIE2}, // S_EGGMOBILE_DIE1 + {SPR_EGGM, 20, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE3}, // S_EGGMOBILE_DIE2 + {SPR_EGGM, 20, 0, {A_Repeat}, 17, S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE4}, // S_EGGMOBILE_DIE3 + {SPR_EGGM, 20, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE_DIE4 + {SPR_EGGM, 21, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_FLEE2}, // S_EGGMOBILE_FLEE1 + {SPR_EGGM, 22, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_FLEE1}, // S_EGGMOBILE_FLEE2 {SPR_UNID, 1, 1, {A_UnidusBall}, 2, 0, S_EGGMOBILE_BALL}, // S_EGGMOBILE_BALL {SPR_NULL, 0, 1, {A_FocusTarget}, 0, 0, S_EGGMOBILE_TARGET}, // S_EGGMOBILE_TARGET + {SPR_EGLZ, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSEGLZ1 + {SPR_EGLZ, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSEGLZ2 + // Boss 2 {SPR_EGGN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE2_STND {SPR_EGGN, 1, 4, {NULL}, 0, 0, S_EGGMOBILE2_POGO2}, // S_EGGMOBILE2_POGO1 @@ -1264,9 +1289,9 @@ state_t states[NUMSTATES] = {SPR_EGGN, 6, 2, {A_BossScream}, 0, 0, S_EGGMOBILE2_FLEE2}, // S_EGGMOBILE2_FLEE1 {SPR_EGGN, 7, 2, {A_BossScream}, 0, 0, S_EGGMOBILE2_FLEE1}, // S_EGGMOBILE2_FLEE2 - {SPR_TNKA, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK1 - {SPR_TNKB, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK2 - {SPR_SPNK, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSPIGOT + {SPR_TANK, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK1 + {SPR_TANK, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK2 + {SPR_TANK, 2, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSPIGOT // Boss 2 Goop {SPR_GOOP, 0, 2, {A_SpawnObjectRelative}, 0, MT_GOOPTRAIL, S_GOOP2}, // S_GOOP1 @@ -1276,34 +1301,16 @@ state_t states[NUMSTATES] = // Boss 3 {SPR_EGGO, 0, 1, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_STND - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH2}, // S_EGGMOBILE3_LAUGH1 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH3}, // S_EGGMOBILE3_LAUGH2 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH4}, // S_EGGMOBILE3_LAUGH3 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH5}, // S_EGGMOBILE3_LAUGH4 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_ATK1}, // S_EGGMOBILE3_LAUGH5 - {SPR_EGGO, 1, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK2}, // S_EGGMOBILE3_ATK1 + {SPR_EGGO, FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2}, // S_EGGMOBILE3_SHOCK + {SPR_EGGO, 6|FF_ANIMATE, 24, {NULL}, 1, 2, S_EGGMOBILE3_ATK2}, // S_EGGMOBILE3_ATK1 {SPR_EGGO, 2, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK3A}, // S_EGGMOBILE3_ATK2 {SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 2, S_EGGMOBILE3_ATK3B}, // S_EGGMOBILE3_ATK3A {SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 4, S_EGGMOBILE3_ATK3C}, // S_EGGMOBILE3_ATK3B {SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 3, S_EGGMOBILE3_ATK3D}, // S_EGGMOBILE3_ATK3C {SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 5, S_EGGMOBILE3_ATK4}, // S_EGGMOBILE3_ATK3D {SPR_EGGO, 4, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK5}, // S_EGGMOBILE3_ATK4 - {SPR_EGGO, 5, 2, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH6}, // S_EGGMOBILE3_ATK5 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH7}, // S_EGGMOBILE3_LAUGH6 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH8}, // S_EGGMOBILE3_LAUGH7 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH9}, // S_EGGMOBILE3_LAUGH8 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH10}, // S_EGGMOBILE3_LAUGH9 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH11}, // S_EGGMOBILE3_LAUGH10 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH12}, // S_EGGMOBILE3_LAUGH11 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH13}, // S_EGGMOBILE3_LAUGH12 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH14}, // S_EGGMOBILE3_LAUGH13 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH15}, // S_EGGMOBILE3_LAUGH14 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH16}, // S_EGGMOBILE3_LAUGH15 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH17}, // S_EGGMOBILE3_LAUGH16 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH18}, // S_EGGMOBILE3_LAUGH17 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH19}, // S_EGGMOBILE3_LAUGH18 - {SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH20}, // S_EGGMOBILE3_LAUGH19 - {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_LAUGH20 + {SPR_EGGO, 5, 2, {NULL}, 0, 0, S_EGGMOBILE3_ROFL}, // S_EGGMOBILE3_ATK5 + {SPR_EGGO, 6|FF_ANIMATE, 60, {NULL}, 1, 2, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_ROFL {SPR_EGGO, 8, 1, {A_Boss3TakeDamage}, 0, 0, S_EGGMOBILE3_PAIN2}, // S_EGGMOBILE3_PAIN {SPR_EGGO, 8, 23, {A_Pain}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_PAIN2 {SPR_EGGO, 9, 2, {A_Fall}, 0, 0, S_EGGMOBILE3_DIE2}, // S_EGGMOBILE3_DIE1 @@ -1313,17 +1320,8 @@ state_t states[NUMSTATES] = {SPR_EGGO, 10, 2, {A_BossScream}, 0, 0, S_EGGMOBILE3_FLEE2}, // S_EGGMOBILE3_FLEE1 {SPR_EGGO, 11, 2, {A_BossScream}, 0, 0, S_EGGMOBILE3_FLEE1}, // S_EGGMOBILE3_FLEE2 - // Boss 3 Propeller - {SPR_PRPL, 0, 1, {NULL}, 0, 0, S_PROPELLER2}, // S_PROPELLER1 - {SPR_PRPL, 1, 1, {NULL}, 0, 0, S_PROPELLER3}, // S_PROPELLER2 - {SPR_PRPL, 2, 1, {NULL}, 0, 0, S_PROPELLER4}, // S_PROPELLER3 - {SPR_PRPL, 3, 1, {NULL}, 0, 0, S_PROPELLER5}, // S_PROPELLER4 - {SPR_PRPL, 4, 1, {NULL}, 0, 0, S_PROPELLER6}, // S_PROPELLER5 - {SPR_PRPL, 5, 1, {NULL}, 0, 0, S_PROPELLER7}, // S_PROPELLER6 - {SPR_PRPL, 6, 1, {NULL}, 0, 0, S_PROPELLER1}, // S_PROPELLER7 - // Boss 3 Pinch - {SPR_FAKE, 0, 1, {A_BossJetFume}, 1, 0, S_FAKEMOBILE}, // S_FAKEMOBILE_INIT + {SPR_FAKE, 0, 1, {NULL}, 0, 0, S_FAKEMOBILE}, // S_FAKEMOBILE_INIT {SPR_FAKE, 0, 1, {A_Boss3Path}, 0, 0, S_FAKEMOBILE}, // S_FAKEMOBILE {SPR_FAKE, 0, 22, {NULL}, 0, 0, S_FAKEMOBILE_ATK2}, // S_FAKEMOBILE_ATK1 {SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE_ATK3A}, // S_FAKEMOBILE_ATK2 @@ -1331,33 +1329,41 @@ state_t states[NUMSTATES] = {SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 4, S_FAKEMOBILE_ATK3C}, // S_FAKEMOBILE_ATK3B {SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 3, S_FAKEMOBILE_ATK3D}, // S_FAKEMOBILE_ATK3C {SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE}, // S_FAKEMOBILE_ATK3D - {SPR_FAKE, 0, 1, {NULL}, 0, 0, S_FAKEMOBILE_DIE2}, // S_FAKEMOBILE_DIE1 + {SPR_FAKE, 1, 1, {NULL}, 0, 0, S_FAKEMOBILE_DIE2}, // S_FAKEMOBILE_DIE1 {SPR_NULL, 0, 1, {NULL}, 0, 0, S_FAKEMOBILE_DIE1}, // S_FAKEMOBILE_DIE2 + {SPR_SEBH, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH1 + {SPR_SEBH, 1, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSSEBH2 + + // Boss 3 Shockwave + + {SPR_SHCK, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE2}, // S_SHOCKWAVE1 + {SPR_SHCK, 3|FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 8, {A_Boss3ShockThink}, 4, 2, S_SHOCKWAVE1}, // S_SHOCKWAVE2 + // Boss 4 {SPR_EGGP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_STND {SPR_EGGP, 1, 3, {NULL}, 0, 0, S_EGGMOBILE4_LATK2}, // S_EGGMOBILE4_LATK1 {SPR_EGGP, 2, 15, {NULL}, 0, 0, S_EGGMOBILE4_LATK3}, // S_EGGMOBILE4_LATK2 {SPR_EGGP, 3, 2, {NULL}, 0, 0, S_EGGMOBILE4_LATK4}, // S_EGGMOBILE4_LATK3 - {SPR_EGGP, 4, 4, {NULL}, 0, 0, S_EGGMOBILE4_LATK5}, // S_EGGMOBILE4_LATK4 - {SPR_EGGP, 4, 50, {A_Boss4Reverse}, sfx_mswing, 0, S_EGGMOBILE4_LATK6}, // S_EGGMOBILE4_LATK5 - {SPR_EGGP, 5, 2, {NULL}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_LATK6 - {SPR_EGGP, 6, 3, {NULL}, 0, 0, S_EGGMOBILE4_RATK2}, // S_EGGMOBILE4_RATK1 - {SPR_EGGP, 7, 15, {NULL}, 0, 0, S_EGGMOBILE4_RATK3}, // S_EGGMOBILE4_RATK2 - {SPR_EGGP, 8, 2, {NULL}, 0, 0, S_EGGMOBILE4_RATK4}, // S_EGGMOBILE4_RATK3 - {SPR_EGGP, 9, 4, {NULL}, 0, 0, S_EGGMOBILE4_RATK5}, // S_EGGMOBILE4_RATK4 - {SPR_EGGP, 9,150, {A_Boss4SpeedUp}, sfx_mswing, 0, S_EGGMOBILE4_RATK6}, // S_EGGMOBILE4_RATK5 - {SPR_EGGP,10, 2, {NULL}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_RATK6 - {SPR_EGGP, 0, 20, {A_Boss4Raise}, sfx_doord1, 0, S_EGGMOBILE4_RAISE2}, // S_EGGMOBILE4_RAISE1 - {SPR_EGGP,13|FF_ANIMATE, -1, {NULL}, 1, 10, S_NULL}, // S_EGGMOBILE4_RAISE2 - {SPR_EGGP,11, 0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2}, // S_EGGMOBILE4_PAIN1 - {SPR_EGGP,11, 24, {A_Pain}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_PAIN2 - {SPR_EGGP,12, 2, {A_Fall}, 0, 0, S_EGGMOBILE4_DIE2}, // S_EGGMOBILE4_DIE1 - {SPR_EGGP,12, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE3}, // S_EGGMOBILE4_DIE2 - {SPR_EGGP,12, 0, {A_Repeat}, 17, S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE4}, // S_EGGMOBILE4_DIE3 - {SPR_EGGP,12, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE4_DIE4 - {SPR_EGGP,13, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_FLEE2}, // S_EGGMOBILE4_FLEE1 - {SPR_EGGP,14, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_FLEE1}, // S_EGGMOBILE4_FLEE2 + {SPR_EGGP, 4, 2, {NULL}, 0, 0, S_EGGMOBILE4_LATK5}, // S_EGGMOBILE4_LATK4 + {SPR_EGGP, 5, 50, {A_Boss4Reverse}, sfx_mswing, 0, S_EGGMOBILE4_LATK6}, // S_EGGMOBILE4_LATK5 + {SPR_EGGP, 6, 2, {NULL}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_LATK6 + {SPR_EGGP, 7, 3, {NULL}, 0, 0, S_EGGMOBILE4_RATK2}, // S_EGGMOBILE4_RATK1 + {SPR_EGGP, 8, 15, {NULL}, 0, 0, S_EGGMOBILE4_RATK3}, // S_EGGMOBILE4_RATK2 + {SPR_EGGP, 9, 2, {NULL}, 0, 0, S_EGGMOBILE4_RATK4}, // S_EGGMOBILE4_RATK3 + {SPR_EGGP,10, 2, {NULL}, 0, 0, S_EGGMOBILE4_RATK5}, // S_EGGMOBILE4_RATK4 + {SPR_EGGP,11,150, {A_Boss4SpeedUp}, sfx_mswing, 0, S_EGGMOBILE4_RATK6}, // S_EGGMOBILE4_RATK5 + {SPR_EGGP,12, 2, {NULL}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_RATK6 + {SPR_EGGP,13, 20, {A_Boss4Raise}, sfx_doord1, 0, S_EGGMOBILE4_RAISE2}, // S_EGGMOBILE4_RAISE1 + {SPR_EGGP,15|FF_ANIMATE, -1, {NULL}, 1, 10, S_NULL}, // S_EGGMOBILE4_RAISE2 + {SPR_EGGP,13, 0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2}, // S_EGGMOBILE4_PAIN1 + {SPR_EGGP,13, 24, {A_Pain}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_PAIN2 + {SPR_EGGP,14, 2, {A_Fall}, 0, 0, S_EGGMOBILE4_DIE2}, // S_EGGMOBILE4_DIE1 + {SPR_EGGP,14, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE3}, // S_EGGMOBILE4_DIE2 + {SPR_EGGP,14, 0, {A_Repeat}, 17, S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE4}, // S_EGGMOBILE4_DIE3 + {SPR_EGGP,14, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE4_DIE4 + {SPR_EGGP,15, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_FLEE2}, // S_EGGMOBILE4_FLEE1 + {SPR_EGGP,16, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_FLEE1}, // S_EGGMOBILE4_FLEE2 {SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_MACE {SPR_BMCE, 0, 2, {A_BossScream}, 1, 0, S_EGGMOBILE4_MACE_DIE2}, // S_EGGMOBILE4_MACE_DIE1 {SPR_NULL, 0, 2, {A_BossScream}, 1, 0, S_EGGMOBILE4_MACE_DIE3}, // S_EGGMOBILE4_MACE_DIE2 @@ -1376,6 +1382,28 @@ state_t states[NUMSTATES] = {SPR_EFIR, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_EGGROBOJET // Boss 5 + {SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO0}, // S_FANG_SETUP + + {SPR_NULL, 0, 2, {NULL}, 0, 0, S_FANG_INTRO1}, // S_FANG_INTRO0 + {SPR_NULL, 0, 2, {A_Boss5MakeJunk}, -S_FANG_CLONE1, 0, S_FANG_INTRO2}, // S_FANG_INTRO1 + {SPR_NULL, 0, 0, {A_Repeat}, 25, S_FANG_INTRO1, S_FANG_INTRO3}, // S_FANG_INTRO2 + {SPR_NULL, 0, 0, {A_Boss5MakeJunk}, 0, 1, S_FANG_INTRO4}, // S_FANG_INTRO3 + {SPR_FANG, 30, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5}, // S_FANG_INTRO4 + {SPR_FANG, 27, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO6}, // S_FANG_INTRO5 + {SPR_FANG, 28, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO7}, // S_FANG_INTRO6 + {SPR_FANG, 29, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO8}, // S_FANG_INTRO7 + {SPR_FANG, 30, 1, {A_Boss5CheckOnGround}, S_FANG_INTRO9, 0, S_FANG_INTRO5}, // S_FANG_INTRO8 + {SPR_FANG, 23|FF_ANIMATE, 50, {NULL}, 1, 4, S_FANG_INTRO10}, // S_FANG_INTRO9 + {SPR_FANG, 25, 5, {NULL}, 0, 0, S_FANG_INTRO11}, // S_FANG_INTRO10 + {SPR_FANG, 26, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12}, // S_FANG_INTRO11 + {SPR_FANG, 31|FF_ANIMATE, 50, {NULL}, 3, 4, S_FANG_IDLE1}, // S_FANG_INTRO12 + + {SPR_FANG, 11, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2}, // S_FANG_CLONE1 + {SPR_FANG, 11, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3}, // S_FANG_INTRO2 + {SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4}, // S_FANG_CLONE3 + {SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4}, // S_FANG_CLONE4 + + {SPR_FANG, 0, 0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1}, // S_FANG_IDLE0 {SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2}, // S_FANG_IDLE1 {SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3}, // S_FANG_IDLE2 {SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE4}, // S_FANG_IDLE3 @@ -1450,8 +1478,8 @@ state_t states[NUMSTATES] = {SPR_FANG, 21, 0, {A_DoNPCPain}, 0, 0, S_FANG_DIE2}, // S_FANG_DIE1 {SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2 - {SPR_FANG, 22, 0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3 - {SPR_FANG, 22, 104, {NULL}, 0, 0, S_FANG_DIE5}, // S_FANG_DIE4 + {SPR_FANG, 22, 0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3 + {SPR_FANG, 22, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5}, // S_FANG_DIE4 {SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5 {SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6 @@ -1465,6 +1493,26 @@ state_t states[NUMSTATES] = {SPR_FANG, 17, 7*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FANG_KO + {SPR_NULL, 0, -1, {A_RandomStateRange}, S_BROKENROBOTA, S_BROKENROBOTF, S_NULL}, // S_BROKENROBOTRANDOM + {SPR_BRKN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTA + {SPR_BRKN, 4|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTB + {SPR_BRKN, 8|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTC + {SPR_BRKN, 12|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTD + {SPR_BRKN, 16|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTE + {SPR_BRKN, 20|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 3, 4, S_NULL}, // S_BROKENROBOTF + + {SPR_WHAT, FF_ANIMATE|FF_FULLBRIGHT, 4, {NULL}, 1, 2, S_ALART2}, // S_ALART1 + {SPR_WHAT, 2|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL}, // S_ALART2 + + {SPR_VWRE, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREF + {SPR_VWRE, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREB + + {SPR_PROJ, FF_TRANS20|FF_FULLBRIGHT, 4, {NULL}, 0, 0, S_PROJECTORLIGHT2}, // S_PROJECTORLIGHT1 + {SPR_PROJ, 1|FF_TRANS40|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_PROJECTORLIGHT3}, // S_PROJECTORLIGHT2 + {SPR_PROJ, 2|FF_TRANS20|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_PROJECTORLIGHT4}, // S_PROJECTORLIGHT3 + {SPR_PROJ, 3|FF_TRANS40|FF_FULLBRIGHT, 2, {A_Repeat}, 39, S_PROJECTORLIGHT2, S_PROJECTORLIGHT5}, // S_PROJECTORLIGHT4 + {SPR_PROJ, 4|FF_TRANS60|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_PROJECTORLIGHT5 + {SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1 {SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2 {SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2}, // S_FBOMB_EXPL1 @@ -1624,7 +1672,7 @@ state_t states[NUMSTATES] = {SPR_FLME, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_CYBRAKDEMONFLAMESHOT_FLY3}, // S_CYBRAKDEMONFLAMESHOT_FLY3 {SPR_FLME, FF_FULLBRIGHT|2, 0, {A_SpawnObjectRelative}, 0, MT_CYBRAKDEMON_FLAMEREST, S_NULL}, // S_CYBRAKDEMONFLAMESHOT_DIE - {SPR_FLAM, FF_FULLBRIGHT, 0, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST + {SPR_FLAM, FF_FULLBRIGHT, 1, {A_SetFuse}, 10*TICRATE, 0, S_FLAMEREST}, // S_CYBRAKDEMONFLAMEREST {SPR_ELEC, 0 + FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_INIT2}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1 {SPR_ELEC, 0 + FF_FULLBRIGHT, 0, {A_RemoteAction}, -1, S_CYBRAKDEMON_INVINCIBLERIZE, S_CYBRAKDEMONELECTRICBARRIER_PLAYSOUND}, // S_CYBRAKDEMONELECTRICBARRIER_INIT2 @@ -1756,18 +1804,8 @@ state_t states[NUMSTATES] = {SPR_METL, 11, 1, {A_BossScream}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 {SPR_METL, 11, 7, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE2 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 2, 1, {NULL}, 0, 0, S_MSSHIELD_F4}, // S_MSSHIELD_F3 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 3, 1, {NULL}, 0, 0, S_MSSHIELD_F5}, // S_MSSHIELD_F4 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 4, 1, {NULL}, 0, 0, S_MSSHIELD_F6}, // S_MSSHIELD_F5 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 5, 1, {NULL}, 0, 0, S_MSSHIELD_F7}, // S_MSSHIELD_F6 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 6, 1, {NULL}, 0, 0, S_MSSHIELD_F8}, // S_MSSHIELD_F7 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 7, 1, {NULL}, 0, 0, S_MSSHIELD_F9}, // S_MSSHIELD_F8 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 8, 1, {NULL}, 0, 0, S_MSSHIELD_F10}, // S_MSSHIELD_F9 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 9, 1, {NULL}, 0, 0, S_MSSHIELD_F11}, // S_MSSHIELD_F10 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|10, 1, {NULL}, 0, 0, S_MSSHIELD_F12}, // S_MSSHIELD_F11 - {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|11, 1, {NULL}, 0, 0, S_MSSHIELD_F1}, // S_MSSHIELD_F12 + {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30|FF_ANIMATE, -1, {NULL}, 11, 1, S_NULL}, // S_MSSHIELD_F1 + {SPR_MSCF, FF_FULLBRIGHT|FF_ANIMATE|12, -1, {NULL}, 8, 2, S_NULL}, // S_MSSHIELD_F2 // Ring {SPR_RING, FF_ANIMATE|FF_GLOBALANIM, -1, {NULL}, 23, 1, S_RING}, // S_RING @@ -2202,14 +2240,12 @@ state_t states[NUMSTATES] = {SPR_DRIP, FF_TRANS30|4, 1, {NULL}, 0, 0, S_DRIPC2}, // S_DRIPC1 {SPR_DRIP, FF_TRANS30|5, 1, {NULL}, 0, 0, S_NULL}, // S_DRIPC2 - // Coral 1 - {SPR_CRL1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL1 - - // Coral 2 - {SPR_CRL2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL2 - - // Coral 3 - {SPR_CRL3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL3 + // Coral + {SPR_CORL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL1 + {SPR_CORL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL2 + {SPR_CORL, 2, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL3 + {SPR_CORL, 3, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL4 + {SPR_CORL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CORAL5 // Blue Crystal {SPR_BCRY, FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_BLUECRYSTAL1 @@ -2217,6 +2253,11 @@ state_t states[NUMSTATES] = // Kelp {SPR_KELP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KELP + // Animated algae + {SPR_ALGA, 0, 1, {A_ConnectToGround}, MT_ANIMALGAESEG, 0, S_ANIMALGAETOP2}, // S_ANIMALGAETOP1 + {SPR_ALGA, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL}, // S_ANIMALGAETOP2 + {SPR_ALGB, 0|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 11, 4, S_NULL}, // S_ANIMALGAESEG + // DSZ Stalagmites {SPR_DSTG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DSZSTALAGMITE {SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DSZ2STALAGMITE @@ -2361,16 +2402,20 @@ state_t states[NUMSTATES] = {SPR_STBL, 6, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL8}, // S_LITTLETUMBLEWEED_ROLL7 {SPR_STBL, 7, 5, {NULL}, 0, 0, S_LITTLETUMBLEWEED_ROLL1}, // S_LITTLETUMBLEWEED_ROLL8 - // Cacti Sprites - {SPR_CACT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI1 - {SPR_CACT, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI2 - {SPR_CACT, 2, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI3 - {SPR_CACT, 3, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI4 + // Cacti + {SPR_CACT, 0, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI1 + {SPR_CACT, 1, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI2 + {SPR_CACT, 2, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI3 + {SPR_CACT, 3, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI4 {SPR_CACT, 4, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI5 {SPR_CACT, 5, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI6 {SPR_CACT, 6, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI7 {SPR_CACT, 7, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI8 {SPR_CACT, 8, -1, {NULL}, 0, 0, S_NULL}, // S_CACTI9 + {SPR_CACT, 9, -1, {A_ConnectToGround}, MT_CACTITINYSEG, 0, S_NULL}, // S_CACTI10 + {SPR_CACT, 10, -1, {A_ConnectToGround}, MT_CACTISMALLSEG, 0, S_NULL}, // S_CACTI11 + {SPR_CACT, 11, -1, {NULL}, 0, 0, S_NULL}, // S_CACTITINYSEG + {SPR_CACT, 12, -1, {NULL}, 0, 0, S_NULL}, // S_CACTISMALLSEG // Warning Signs {SPR_WWSG, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDSIGN_CAUTION @@ -3872,21 +3917,21 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 1, {A_RockSpawn}, 0, 0, S_ROCKSPAWN}, // S_ROCKSPAWN {SPR_ROIA, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEA - {SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEB - {SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEC - {SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLED - {SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEE - {SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEF - {SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEG - {SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEH - {SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEI - {SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEJ - {SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEK - {SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEL - {SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEM - {SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEN - {SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEO - {SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEP + {SPR_ROIB, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEB + {SPR_ROIC, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEC + {SPR_ROID, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLED + {SPR_ROIE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEE + {SPR_ROIF, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEF + {SPR_ROIG, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEG + {SPR_ROIH, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEH + {SPR_ROII, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEI + {SPR_ROIJ, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEJ + {SPR_ROIK, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEK + {SPR_ROIL, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEL + {SPR_ROIM, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEM + {SPR_ROIN, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEN + {SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEO + {SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_ROCKCRUMBLEP {SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS @@ -5051,7 +5096,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 34*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_SLIDEME, // flags @@ -5328,6 +5373,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BOSSJUNK + -1, // doomednum + S_BOSSEGLZ1, // spawnstate + 1, // 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*FRACUNIT, // radius + 64*FRACUNIT, // height + 2, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_EGGMOBILE 200, // doomednum S_EGGMOBILE_STND, // spawnstate @@ -5517,87 +5589,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE2_POGO5 // raisestate }, - { // MT_BOSSTANK1 - -1, // doomednum - S_BOSSTANK1, // spawnstate - 1, // 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*FRACUNIT, // radius - 64*FRACUNIT, // height - 0, // display offset - 100, // mass - 1, // damage - sfx_None, // activesound - MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT, // flags - S_NULL // raisestate - }, - - { // MT_BOSSTANK2 - -1, // doomednum - S_BOSSTANK2, // spawnstate - 1, // 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*FRACUNIT, // radius - 64*FRACUNIT, // height - 0, // display offset - 100, // mass - 1, // damage - sfx_None, // activesound - MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT, // flags - S_NULL // raisestate - }, - - { // MT_BOSSSPIGOT - -1, // doomednum - S_BOSSSPIGOT, // spawnstate - 1, // 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*FRACUNIT, // radius - 24*FRACUNIT, // height - 0, // display offset - 100, // mass - 1, // damage - sfx_None, // activesound - MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT, // flags - S_NULL // raisestate - }, - { // MT_GOOP -1, // doomednum S_GOOP1, // spawnstate @@ -5661,10 +5652,10 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // reactiontime sfx_None, // attacksound S_EGGMOBILE3_PAIN, // painstate - MT_PROPELLER, // painchance + MT_NULL, // painchance sfx_dmpain, // painsound S_NULL, // meleestate - S_EGGMOBILE3_LAUGH1,// missilestate + S_EGGMOBILE3_SHOCK, // missilestate S_EGGMOBILE3_DIE1, // deathstate S_EGGMOBILE3_FLEE1, // xdeathstate sfx_s3kb4, // deathsound @@ -5676,34 +5667,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 3, // damage sfx_telept, // activesound MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_BOSS|MF_NOCLIPHEIGHT, // flags - S_EGGMOBILE3_LAUGH20 // raisestate - }, - - { // MT_PROPELLER - -1, // doomednum - S_PROPELLER1, // 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 - 1, // speed - 4*FRACUNIT, // radius - 4*FRACUNIT, // height - 0, // display offset - 4, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags - S_NULL // raisestate + S_EGGMOBILE3_ROFL // raisestate }, { // MT_FAKEMOBILE @@ -5715,7 +5679,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate - MT_PROPELLER, // painchance + MT_NULL, // painchance sfx_s3k7b, // painsound S_NULL, // meleestate S_FAKEMOBILE_ATK1, // missilestate @@ -5733,30 +5697,30 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_SHOCK + { // MT_SHOCKWAVE -1, // doomednum - S_THUNDERCOIN_SPARK, // spawnstate + S_SHOCKWAVE1, // spawnstate 1000, // spawnhealth S_NULL, // seestate - sfx_None, // seesound + sfx_s3k5e, // seesound 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 0, // painchance + 8*TICRATE, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate S_SPRK1, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound - 10*FRACUNIT, // speed - 16*FRACUNIT, // radius - 35*FRACUNIT, // height + 12*FRACUNIT, // speed + 48*FRACUNIT, // radius + 8*FRACUNIT, // height 0, // display offset DMG_ELECTRIC|(sfx_buzz2<<8), // mass - 20, // damage + 3, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_MISSILE|MF_PAIN|MF_NOGRAVITY|MF_PAPERCOLLISION, // flags S_NULL // raisestate }, @@ -5897,7 +5861,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FANG 204, // doomednum - S_FANG_IDLE1, // spawnstate + S_FANG_SETUP, // spawnstate 8, // spawnhealth S_FANG_PATHINGSTART1, // seestate sfx_None, // seesound @@ -5918,10 +5882,118 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 3, // damage sfx_boingf, // activesound - MF_SPECIAL|MF_BOSS|MF_SHOOTABLE|MF_GRENADEBOUNCE, // flags + MF_RUNSPAWNFUNC|MF_SPECIAL|MF_BOSS|MF_SHOOTABLE|MF_GRENADEBOUNCE|MF_NOCLIPTHING, // flags -- MF_NOCLIPTHING will be removed after intro event ends S_NULL // raisestate }, + { // MT_BROKENROBOT + -1, // doomednum + S_BROKENROBOTRANDOM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_ambint, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 255, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 1000, // mass + 0, // damage + sfx_crumbl, // activesound + MF_RUNSPAWNFUNC|MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_VWREF + -1, // doomednum + S_VWREF, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 42*FRACUNIT, // radius + 12*FRACUNIT, // height + 1, // display offset + 1000, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_VWREB + -1, // doomednum + S_VWREB, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 42*FRACUNIT, // radius + 12*FRACUNIT, // height + -1, // display offset + 1000, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PROJECTORLIGHT + -1, // doomednum + S_PROJECTORLIGHT1, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 3, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 42*FRACUNIT, // radius + 52*FRACUNIT, // height + -1, // display offset + 1000, // mass + 8, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_FBOMB -1, // doomednum S_FBOMB1, // spawnstate @@ -6776,8 +6848,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 16*FRACUNIT, // radius + 32*FRACUNIT, // height 0, // display offset 100, // mass 1, // damage @@ -6857,8 +6929,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_ncitem, // deathsound 1, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 16*FRACUNIT, // radius + 30*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage @@ -9395,7 +9467,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 20, // damage sfx_None, // activesound - MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + MF_PAIN|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP, // flags S_NULL // raisestate }, @@ -10313,7 +10385,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_SPAWNCEILING|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_SPAWNCEILING|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -10340,7 +10412,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_SCENERY, // flags + MF_SPECIAL|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10361,13 +10433,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 29*FRACUNIT, // radius + 40*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10388,13 +10460,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 30*FRACUNIT, // radius + 53*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10415,13 +10487,67 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height + 28*FRACUNIT, // radius + 41*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CORAL4 + 1014, // doomednum + S_CORAL4, // 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 + 56*FRACUNIT, // radius + 112*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CORAL5 + 1015, // doomednum + S_CORAL5, // 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 + 56*FRACUNIT, // radius + 112*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -10448,13 +10574,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, { // MT_KELP 1007, // doomednum - S_KELP, // spawnstate + S_KELP, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10469,19 +10595,73 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 292*FRACUNIT, // height + 16*FRACUNIT, // radius + 292*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_NOBLOCKMAP, // flags + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_ANIMALGAETOP + 1013, // doomednum + S_ANIMALGAETOP1, // 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 + 48*FRACUNIT, // radius + 120*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIP|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_ANIMALGAESEG + -1, // doomednum + S_ANIMALGAESEG, // 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 + 48*FRACUNIT, // radius + 120*FRACUNIT, // height + 0, // display offset + 4, // mass + 0, // damage + sfx_None, // activesound + MF_NOCLIP|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, { // MT_DSZSTALAGMITE 1008, // doomednum - S_DSZSTALAGMITE, // spawnstate + S_DSZSTALAGMITE,// spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10497,12 +10677,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 8*FRACUNIT, // radius - 116*FRACUNIT, // height + 116*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_SOLID, // flags + MF_SCENERY|MF_SOLID, // flags S_NULL // raisestate }, @@ -10524,18 +10704,18 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 8*FRACUNIT, // radius - 116*FRACUNIT, // height + 116*FRACUNIT, // height 0, // display offset 4, // mass 0, // damage sfx_None, // activesound - MF_SCENERY|MF_SOLID, // flags + MF_SCENERY|MF_SOLID, // flags S_NULL // raisestate }, { // MT_LIGHTBEAM 1010, // doomednum - S_LIGHTBEAM1, // spawnstate + S_LIGHTBEAM1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -10550,7 +10730,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius + 16*FRACUNIT, // radius 16*FRACUNIT, // height 0, // display offset 4, // mass @@ -10616,7 +10796,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_FLAMEPARTICLE -1, // doomednum - S_FLAMEPARTICLE, // spawnstate + S_FLAMEPARTICLE,// spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -11738,13 +11918,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 13*FRACUNIT, // radius + 24*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11765,13 +11945,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 64*FRACUNIT, // height + 15*FRACUNIT, // radius + 52*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11792,13 +11972,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 13*FRACUNIT, // radius + 24*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11819,13 +11999,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 16*FRACUNIT, // radius - 80*FRACUNIT, // height + 15*FRACUNIT, // radius + 52*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound - MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, @@ -11849,7 +12029,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // radius 96*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11876,7 +12056,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 20*FRACUNIT, // radius 128*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11901,9 +12081,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 24*FRACUNIT, // radius - 224*FRACUNIT, // height + 224*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11928,9 +12108,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 24*FRACUNIT, // radius - 256*FRACUNIT, // height + 256*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags @@ -11957,13 +12137,121 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 48*FRACUNIT, // radius 96*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_SOLID|MF_SCENERY|MF_PAIN, // flags S_NULL // raisestate }, + { // MT_CACTI10 + 1230, // doomednum + S_CACTI10, // 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 + 13*FRACUNIT, // radius + 28*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_CACTI11 + 1231, // doomednum + S_CACTI11, // 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 + 15*FRACUNIT, // radius + 60*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_PAIN|MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_CACTITINYSEG + -1, // doomednum + S_CACTITINYSEG, // 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 + 13*FRACUNIT, // radius + 28*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_CACTISMALLSEG + -1, // doomednum + S_CACTISMALLSEG, // 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 + 15*FRACUNIT, // radius + 60*FRACUNIT, // height + 0, // display offset + DMG_SPIKE, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + { // MT_ARIDSIGN_CAUTION 1212, // doomednum S_ARIDSIGN_CAUTION, // spawnstate diff --git a/src/info.h b/src/info.h index aad778823..6b2de6ac9 100644 --- a/src/info.h +++ b/src/info.h @@ -138,6 +138,7 @@ void A_SetReactionTime(); void A_Boss1Spikeballs(); void A_Boss3TakeDamage(); void A_Boss3Path(); +void A_Boss3ShockThink(); void A_LinedefExecute(); void A_PlaySeeSound(); void A_PlayAttackSound(); @@ -252,6 +253,7 @@ void A_Boss5CheckOnGround(); void A_Boss5CheckFalling(); void A_Boss5PinchShot(); void A_Boss5MakeItRain(); +void A_Boss5MakeJunk(); void A_LookForBetter(); void A_Boss5BombExplode(); void A_DustDevilThink(); @@ -329,19 +331,19 @@ typedef enum sprite SPR_JETF, // Boss jet fumes // Boss 1 (Greenflower) - SPR_EGGM, + SPR_EGGM, // Boss 1 + SPR_EGLZ, // Boss 1 Junk // Boss 2 (Techno Hill) SPR_EGGN, // Boss 2 - SPR_TNKA, // Boss 2 Tank 1 - SPR_TNKB, // Boss 2 Tank 2 - SPR_SPNK, // Boss 2 Spigot + SPR_TANK, // Boss 2 Junk SPR_GOOP, // Boss 2 Goop // Boss 3 (Deep Sea) SPR_EGGO, // Boss 3 - SPR_PRPL, // Boss 3 Propeller + SPR_SEBH, // Boss 3 Junk SPR_FAKE, // Boss 3 Fakemobile + SPR_SHCK, // Boss 3 Shockwave // Boss 4 (Castle Eggman) SPR_EGGP, @@ -350,6 +352,10 @@ typedef enum sprite // Boss 5 (Arid Canyon) SPR_FANG, // replaces EGGQ + SPR_BRKN, + SPR_WHAT, + SPR_VWRE, + SPR_PROJ, // projector light SPR_FBOM, SPR_FSGN, SPR_BARX, // bomb explosion (also used by barrel) @@ -470,11 +476,11 @@ typedef enum sprite SPR_GARG, // Deep Sea Gargoyle SPR_SEWE, // Deep Sea Seaweed SPR_DRIP, // Dripping water - SPR_CRL1, // Coral 1 - SPR_CRL2, // Coral 2 - SPR_CRL3, // Coral 3 + SPR_CORL, // Coral SPR_BCRY, // Blue Crystal SPR_KELP, // Kelp + SPR_ALGA, // Animated algae top + SPR_ALGB, // Animated algae segment SPR_DSTG, // DSZ Stalagmites SPR_LIBE, // DSZ Light beam @@ -504,7 +510,7 @@ typedef enum sprite // Arid Canyon Scenery SPR_BTBL, // Big tumbleweed SPR_STBL, // Small tumbleweed - SPR_CACT, // Cacti sprites + SPR_CACT, // Cacti SPR_WWSG, // Caution Sign SPR_WWS2, // Cacti Sign SPR_WWS3, // Sharp Turn Sign @@ -849,9 +855,15 @@ typedef enum playersprite SPR2_TALA, SPR2_TALB, + SPR2_CNT1, // continue disappointment + SPR2_CNT2, // continue lift + SPR2_CNT3, // continue spin + SPR2_CNT4, // continue "soooooooniiic!" tugging + SPR2_SIGN, // end sign head SPR2_LIFE, // life monitor icon - SPR2_XTRA, // stuff that isn't in-game - keep this last in the list + + SPR2_XTRA, // stuff that isn't in-map - "would this ever need an md2 or variable length animation?" SPR2_FIRSTFREESLOT, SPR2_LASTFREESLOT = 0x7f, @@ -1365,10 +1377,10 @@ typedef enum state S_SONIC3KBOSSEXPLOSION6, S_JETFUME1, - S_JETFUME2, // Boss 1 S_EGGMOBILE_STND, + S_EGGMOBILE_ROFL, S_EGGMOBILE_LATK1, S_EGGMOBILE_LATK2, S_EGGMOBILE_LATK3, @@ -1378,7 +1390,6 @@ typedef enum state S_EGGMOBILE_LATK7, S_EGGMOBILE_LATK8, S_EGGMOBILE_LATK9, - S_EGGMOBILE_LATK10, S_EGGMOBILE_RATK1, S_EGGMOBILE_RATK2, S_EGGMOBILE_RATK3, @@ -1388,7 +1399,6 @@ typedef enum state S_EGGMOBILE_RATK7, S_EGGMOBILE_RATK8, S_EGGMOBILE_RATK9, - S_EGGMOBILE_RATK10, S_EGGMOBILE_PANIC1, S_EGGMOBILE_PANIC2, S_EGGMOBILE_PANIC3, @@ -1396,6 +1406,14 @@ typedef enum state S_EGGMOBILE_PANIC5, S_EGGMOBILE_PANIC6, S_EGGMOBILE_PANIC7, + S_EGGMOBILE_PANIC8, + S_EGGMOBILE_PANIC9, + S_EGGMOBILE_PANIC10, + S_EGGMOBILE_PANIC11, + S_EGGMOBILE_PANIC12, + S_EGGMOBILE_PANIC13, + S_EGGMOBILE_PANIC14, + S_EGGMOBILE_PANIC15, S_EGGMOBILE_PAIN, S_EGGMOBILE_PAIN2, S_EGGMOBILE_DIE1, @@ -1407,6 +1425,9 @@ typedef enum state S_EGGMOBILE_BALL, S_EGGMOBILE_TARGET, + S_BOSSEGLZ1, + S_BOSSEGLZ2, + // Boss 2 S_EGGMOBILE2_STND, S_EGGMOBILE2_POGO1, @@ -1437,11 +1458,7 @@ typedef enum state // Boss 3 S_EGGMOBILE3_STND, - S_EGGMOBILE3_LAUGH1, - S_EGGMOBILE3_LAUGH2, - S_EGGMOBILE3_LAUGH3, - S_EGGMOBILE3_LAUGH4, - S_EGGMOBILE3_LAUGH5, + S_EGGMOBILE3_SHOCK, S_EGGMOBILE3_ATK1, S_EGGMOBILE3_ATK2, S_EGGMOBILE3_ATK3A, @@ -1450,21 +1467,7 @@ typedef enum state S_EGGMOBILE3_ATK3D, S_EGGMOBILE3_ATK4, S_EGGMOBILE3_ATK5, - S_EGGMOBILE3_LAUGH6, - S_EGGMOBILE3_LAUGH7, - S_EGGMOBILE3_LAUGH8, - S_EGGMOBILE3_LAUGH9, - S_EGGMOBILE3_LAUGH10, - S_EGGMOBILE3_LAUGH11, - S_EGGMOBILE3_LAUGH12, - S_EGGMOBILE3_LAUGH13, - S_EGGMOBILE3_LAUGH14, - S_EGGMOBILE3_LAUGH15, - S_EGGMOBILE3_LAUGH16, - S_EGGMOBILE3_LAUGH17, - S_EGGMOBILE3_LAUGH18, - S_EGGMOBILE3_LAUGH19, - S_EGGMOBILE3_LAUGH20, + S_EGGMOBILE3_ROFL, S_EGGMOBILE3_PAIN, S_EGGMOBILE3_PAIN2, S_EGGMOBILE3_DIE1, @@ -1474,15 +1477,6 @@ typedef enum state S_EGGMOBILE3_FLEE1, S_EGGMOBILE3_FLEE2, - // Boss 3 Propeller - S_PROPELLER1, - S_PROPELLER2, - S_PROPELLER3, - S_PROPELLER4, - S_PROPELLER5, - S_PROPELLER6, - S_PROPELLER7, - // Boss 3 Pinch S_FAKEMOBILE_INIT, S_FAKEMOBILE, @@ -1495,6 +1489,13 @@ typedef enum state S_FAKEMOBILE_DIE1, S_FAKEMOBILE_DIE2, + S_BOSSSEBH1, + S_BOSSSEBH2, + + // Boss 3 Shockwave + S_SHOCKWAVE1, + S_SHOCKWAVE2, + // Boss 4 S_EGGMOBILE4_STND, S_EGGMOBILE4_LATK1, @@ -1537,6 +1538,25 @@ typedef enum state S_EGGROBOJET, // Boss 5 + S_FANG_SETUP, + S_FANG_INTRO0, + S_FANG_INTRO1, + S_FANG_INTRO2, + S_FANG_INTRO3, + S_FANG_INTRO4, + S_FANG_INTRO5, + S_FANG_INTRO6, + S_FANG_INTRO7, + S_FANG_INTRO8, + S_FANG_INTRO9, + S_FANG_INTRO10, + S_FANG_INTRO11, + S_FANG_INTRO12, + S_FANG_CLONE1, + S_FANG_CLONE2, + S_FANG_CLONE3, + S_FANG_CLONE4, + S_FANG_IDLE0, S_FANG_IDLE1, S_FANG_IDLE2, S_FANG_IDLE3, @@ -1608,6 +1628,26 @@ typedef enum state S_FANG_FLEEBOUNCE2, S_FANG_KO, + S_BROKENROBOTRANDOM, + S_BROKENROBOTA, + S_BROKENROBOTB, + S_BROKENROBOTC, + S_BROKENROBOTD, + S_BROKENROBOTE, + S_BROKENROBOTF, + + S_ALART1, + S_ALART2, + + S_VWREF, + S_VWREB, + + S_PROJECTORLIGHT1, + S_PROJECTORLIGHT2, + S_PROJECTORLIGHT3, + S_PROJECTORLIGHT4, + S_PROJECTORLIGHT5, + S_FBOMB1, S_FBOMB2, S_FBOMB_EXPL1, @@ -1898,16 +1938,6 @@ typedef enum state S_MSSHIELD_F1, S_MSSHIELD_F2, - S_MSSHIELD_F3, - S_MSSHIELD_F4, - S_MSSHIELD_F5, - S_MSSHIELD_F6, - S_MSSHIELD_F7, - S_MSSHIELD_F8, - S_MSSHIELD_F9, - S_MSSHIELD_F10, - S_MSSHIELD_F11, - S_MSSHIELD_F12, // Ring S_RING, @@ -2341,14 +2371,12 @@ typedef enum state S_DRIPC1, S_DRIPC2, - // Coral 1 + // Coral S_CORAL1, - - // Coral 2 S_CORAL2, - - // Coral 3 S_CORAL3, + S_CORAL4, + S_CORAL5, // Blue Crystal S_BLUECRYSTAL1, @@ -2356,6 +2384,11 @@ typedef enum state // Kelp, S_KELP, + // Animated algae + S_ANIMALGAETOP1, + S_ANIMALGAETOP2, + S_ANIMALGAESEG, + // DSZ Stalagmites S_DSZSTALAGMITE, S_DSZ2STALAGMITE, @@ -2490,7 +2523,7 @@ typedef enum state S_LITTLETUMBLEWEED_ROLL7, S_LITTLETUMBLEWEED_ROLL8, - // Cacti Sprites + // Cacti S_CACTI1, S_CACTI2, S_CACTI3, @@ -2500,8 +2533,12 @@ typedef enum state S_CACTI7, S_CACTI8, S_CACTI9, + S_CACTI10, + S_CACTI11, + S_CACTITINYSEG, + S_CACTISMALLSEG, - // Warning signs sprites + // Warning signs S_ARIDSIGN_CAUTION, S_ARIDSIGN_CACTI, S_ARIDSIGN_SHARPTURN, @@ -4043,6 +4080,7 @@ typedef enum mobj_type MT_EGGTRAP, MT_BOSS3WAYPOINT, MT_BOSS9GATHERPOINT, + MT_BOSSJUNK, // Boss 1 MT_EGGMOBILE, @@ -4054,17 +4092,13 @@ typedef enum mobj_type // Boss 2 MT_EGGMOBILE2, MT_EGGMOBILE2_POGO, - MT_BOSSTANK1, - MT_BOSSTANK2, - MT_BOSSSPIGOT, MT_GOOP, MT_GOOPTRAIL, // Boss 3 MT_EGGMOBILE3, - MT_PROPELLER, MT_FAKEMOBILE, - MT_SHOCK, + MT_SHOCKWAVE, // Boss 4 MT_EGGMOBILE4, @@ -4075,6 +4109,10 @@ typedef enum mobj_type // Boss 5 MT_FANG, + MT_BROKENROBOT, + MT_VWREF, + MT_VWREB, + MT_PROJECTORLIGHT, MT_FBOMB, MT_TNTDUST, // also used by barrel MT_FSGNA, @@ -4273,11 +4311,15 @@ typedef enum mobj_type MT_SEAWEED, // DSZ Seaweed MT_WATERDRIP, // Dripping Water source MT_WATERDROP, // Water drop from dripping water - MT_CORAL1, // Coral 1 - MT_CORAL2, // Coral 2 - MT_CORAL3, // Coral 3 + MT_CORAL1, // Coral + MT_CORAL2, + MT_CORAL3, + MT_CORAL4, + MT_CORAL5, MT_BLUECRYSTAL, // Blue Crystal MT_KELP, // Kelp + MT_ANIMALGAETOP, // Animated algae top + MT_ANIMALGAESEG, // Animated algae segment MT_DSZSTALAGMITE, // Deep Sea 1 Stalagmite MT_DSZ2STALAGMITE, // Deep Sea 2 Stalagmite MT_LIGHTBEAM, // DSZ Light beam @@ -4328,15 +4370,19 @@ typedef enum mobj_type // Arid Canyon Scenery MT_BIGTUMBLEWEED, MT_LITTLETUMBLEWEED, - MT_CACTI1, - MT_CACTI2, - MT_CACTI3, - MT_CACTI4, - MT_CACTI5, // Harmful Cactus 1 - MT_CACTI6, // Harmful Cactus 2 - MT_CACTI7, // Harmful Cactus 3 - MT_CACTI8, // Harmful Cactus 4 - MT_CACTI9, // Harmful Cactus 5 + MT_CACTI1, // Tiny Red Flower Cactus + MT_CACTI2, // Small Red Flower Cactus + MT_CACTI3, // Tiny Blue Flower Cactus + MT_CACTI4, // Small Blue Flower Cactus + MT_CACTI5, // Prickly Pear + MT_CACTI6, // Barrel Cactus + MT_CACTI7, // Tall Barrel Cactus + MT_CACTI8, // Armed Cactus + MT_CACTI9, // Ball Cactus + MT_CACTI10, // Tiny Cactus + MT_CACTI11, // Small Cactus + MT_CACTITINYSEG, // Tiny Cactus Segment + MT_CACTISMALLSEG, // Small Cactus Segment MT_ARIDSIGN_CAUTION, // Caution Sign MT_ARIDSIGN_CACTI, // Cacti Sign MT_ARIDSIGN_SHARPTURN, // Sharp Turn Sign diff --git a/src/lua_baselib.c b/src/lua_baselib.c index cfe0844ee..8f173e32e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -182,6 +182,8 @@ static const struct { {META_CAMERA, "camera_t"}, {META_ACTION, "action"}, + + {META_LUABANKS, "luabanks[]"}, {NULL, NULL} }; @@ -228,6 +230,18 @@ static int lib_isPlayerAdmin(lua_State *L) return 1; } +static int lib_reserveLuabanks(lua_State *L) +{ + static boolean reserved = false; + if (!lua_lumploading) + return luaL_error(L, "luabanks[] cannot be reserved from within a hook or coroutine!"); + if (reserved) + return luaL_error(L, "luabanks[] has already been reserved! Only one savedata-enabled mod at a time may use this feature."); + reserved = true; + LUA_PushUserdata(L, &luabanks, META_LUABANKS); + return 1; +} + // M_RANDOM ////////////// @@ -2733,6 +2747,7 @@ static luaL_Reg lib[] = { {"chatprintf", lib_chatprintf}, {"userdataType", lib_userdataType}, {"IsPlayerAdmin", lib_isPlayerAdmin}, + {"reserveLuabanks", lib_reserveLuabanks}, // m_random {"P_RandomFixed",lib_pRandomFixed}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index c6856b426..9e74dac76 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -308,6 +308,8 @@ static int lib_cvRegisterVar(lua_State *L) #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e); #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) + memset(cvar, 0x00, sizeof(consvar_t)); // zero everything by default + lua_pushnil(L); while (lua_next(L, 1)) { // stack: cvar table, cvar userdata, key/index, value @@ -395,6 +397,13 @@ static int lib_cvRegisterVar(lua_State *L) #undef FIELDERROR #undef TYPEERROR + if (!cvar->name) + return luaL_error(L, M_GetText("Variable has no name!\n")); + if ((cvar->flags & CV_NOINIT) && !(cvar->flags & CV_CALL)) + return luaL_error(L, M_GetText("Variable %s has CV_NOINIT without CV_CALL\n"), cvar->name); + if ((cvar->flags & CV_CALL) && !cvar->func) + return luaL_error(L, M_GetText("Variable %s has CV_CALL without a function\n"), cvar->name); + // stack: cvar table, cvar userdata lua_getfield(L, LUA_REGISTRYINDEX, "CV_Vars"); I_Assert(lua_istable(L, 3)); diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 77f37f8ec..8ef0bafcf 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -18,6 +18,7 @@ #include "p_mobj.h" #include "p_local.h" #include "z_zone.h" +#include "doomstat.h" // luabanks[] #include "lua_script.h" #include "lua_libs.h" @@ -146,7 +147,7 @@ static int lib_getSpr2default(lua_State *L) return luaL_error(L, "spr2defaults[] invalid index"); if (i >= free_spr2) - return 0; + return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, 0, free_spr2-1); lua_pushinteger(L, spr2defaults[i]); return 1; @@ -1026,6 +1027,61 @@ static int sfxinfo_num(lua_State *L) return 1; } +////////////// +// LUABANKS // +////////////// + +static int lib_getluabanks(lua_State *L) +{ + UINT8 i; + + lua_remove(L, 1); // don't care about luabanks[] dummy userdata. + + if (lua_isnumber(L, 1)) + i = lua_tonumber(L, 1); + else + return luaL_error(L, "luabanks[] invalid index"); + + if (i >= NUM_LUABANKS) + luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS-1); + + lua_pushinteger(L, luabanks[i]); + return 1; +} + +static int lib_setluabanks(lua_State *L) +{ + UINT8 i; + INT32 j = 0; + + if (hud_running) + return luaL_error(L, "Do not alter luabanks[] in HUD rendering code!"); + + lua_remove(L, 1); // don't care about luabanks[] dummy userdata. + + if (lua_isnumber(L, 1)) + i = lua_tonumber(L, 1); + else + return luaL_error(L, "luabanks[] invalid index"); + + if (i >= NUM_LUABANKS) + luaL_error(L, "luabanks[] index %d out of range (%d - %d)", i, 0, NUM_LUABANKS-1); + + if (lua_isnumber(L, 2)) + j = lua_tonumber(L, 2); + else + return luaL_error(L, "luabanks[] invalid set"); + + luabanks[i] = j; + return 0; +} + +static int lib_luabankslen(lua_State *L) +{ + lua_pushinteger(L, NUM_LUABANKS); + return 1; +} + ////////////////////////////// // // Now push all these functions into the Lua state! @@ -1147,6 +1203,18 @@ int LUA_InfoLib(lua_State *L) lua_pushvalue(L, -1); lua_setglobal(L, "S_sfx"); lua_setglobal(L, "sfxinfo"); + + luaL_newmetatable(L, META_LUABANKS); + lua_pushcfunction(L, lib_getluabanks); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_setluabanks); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, lib_luabankslen); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + return 0; } diff --git a/src/lua_libs.h b/src/lua_libs.h index 827c1d798..7609971ce 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -67,6 +67,8 @@ extern lua_State *gL; #define META_ACTION "ACTIONF_T*" +#define META_LUABANKS "LUABANKS[]*" + boolean luaL_checkboolean(lua_State *L, int narg); int LUA_EnumLib(lua_State *L); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 74b259921..dbb69b7e2 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2017,6 +2017,8 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->muspostbosspos); else if (fastcmp(field,"muspostbossfadein")) lua_pushinteger(L, header->muspostbossfadein); + else if (fastcmp(field,"musforcereset")) + lua_pushinteger(L, header->musforcereset); else if (fastcmp(field,"forcecharacter")) lua_pushstring(L, header->forcecharacter); else if (fastcmp(field,"weather")) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index b7bdaa1be..dd9959afb 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -136,6 +136,12 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->currentweapon); else if (fastcmp(field,"ringweapons")) lua_pushinteger(L, plr->ringweapons); + else if (fastcmp(field,"ammoremoval")) + lua_pushinteger(L, plr->ammoremoval); + else if (fastcmp(field,"ammoremovaltimer")) + lua_pushinteger(L, plr->ammoremovaltimer); + else if (fastcmp(field,"ammoremovalweapon")) + lua_pushinteger(L, plr->ammoremovalweapon); else if (fastcmp(field,"powers")) LUA_PushUserdata(L, plr->powers, META_POWERS); else if (fastcmp(field,"pflags")) @@ -256,6 +262,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->starposttime); else if (fastcmp(field,"starpostangle")) lua_pushangle(L, plr->starpostangle); + else if (fastcmp(field,"starpostscale")) + lua_pushfixed(L, plr->starpostscale); else if (fastcmp(field,"angle_pos")) lua_pushangle(L, plr->angle_pos); else if (fastcmp(field,"old_angle_pos")) @@ -428,6 +436,12 @@ static int player_set(lua_State *L) plr->currentweapon = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"ringweapons")) plr->ringweapons = (INT32)luaL_checkinteger(L, 3); + else if (fastcmp(field,"ammoremoval")) + plr->ammoremoval = (UINT16)luaL_checkinteger(L, 3); + else if (fastcmp(field,"ammoremovaltimer")) + plr->ammoremovaltimer = (tic_t)luaL_checkinteger(L, 3); + else if (fastcmp(field,"ammoremovalweapon")) + plr->ammoremovalweapon = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"powers")) return NOSET; else if (fastcmp(field,"pflags")) @@ -558,6 +572,8 @@ static int player_set(lua_State *L) plr->starposttime = (tic_t)luaL_checkinteger(L, 3); else if (fastcmp(field,"starpostangle")) plr->starpostangle = luaL_checkangle(L, 3); + else if (fastcmp(field,"starpostscale")) + plr->starpostscale = luaL_checkfixed(L, 3); else if (fastcmp(field,"angle_pos")) plr->angle_pos = luaL_checkangle(L, 3); else if (fastcmp(field,"old_angle_pos")) diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index a28f6a359..7f68905aa 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -52,6 +52,8 @@ enum skin { skin_supercolor, skin_prefoppositecolor, skin_highresscale, + skin_contspeed, + skin_contangle, skin_soundsid, skin_availability }; @@ -88,6 +90,8 @@ static const char *const skin_opt[] = { "supercolor", "prefoppositecolor", "highresscale", + "contspeed", + "contangle", "soundsid", "availability", NULL}; @@ -199,6 +203,12 @@ static int skin_get(lua_State *L) case skin_highresscale: lua_pushinteger(L, skin->highresscale); break; + case skin_contspeed: + lua_pushinteger(L, skin->contspeed); + break; + case skin_contangle: + lua_pushinteger(L, skin->contangle); + break; case skin_soundsid: LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID); break; diff --git a/src/m_cheat.c b/src/m_cheat.c index 29e8c8a02..bb757839a 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -746,6 +746,18 @@ void Command_Weather_f(void) P_SwitchWeather(atoi(COM_Argv(1))); } +void Command_Toggletwod_f(void) +{ + player_t *p = &players[consoleplayer]; + + REQUIRE_DEVMODE; + REQUIRE_INLEVEL; + REQUIRE_SINGLEPLAYER; + + if (p->mo) + p->mo->flags2 ^= MF2_TWOD; +} + #ifdef _DEBUG // You never thought you needed this, did you? >=D // Yes, this has the specific purpose of completely screwing you up @@ -819,6 +831,12 @@ void Command_Savecheckpoint_f(void) players[consoleplayer].starposty = players[consoleplayer].mo->y>>FRACBITS; players[consoleplayer].starpostz = players[consoleplayer].mo->floorz>>FRACBITS; players[consoleplayer].starpostangle = players[consoleplayer].mo->angle; + players[consoleplayer].starpostscale = players[consoleplayer].mo->destscale; + if (players[consoleplayer].mo->flags2 & MF2_OBJECTFLIP) + { + players[consoleplayer].starpostscale *= -1; + players[consoleplayer].starpostz += players[consoleplayer].mo->height; + } CONS_Printf(M_GetText("Temporary checkpoint created at %d, %d, %d\n"), players[consoleplayer].starpostx, players[consoleplayer].starposty, players[consoleplayer].starpostz); } diff --git a/src/m_cheat.h b/src/m_cheat.h index aa9b0bfeb..f5d59120b 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -64,6 +64,7 @@ void Command_Teleport_f(void); void Command_RTeleport_f(void); void Command_Skynum_f(void); void Command_Weather_f(void); +void Command_Toggletwod_f(void); #ifdef _DEBUG void Command_CauseCfail_f(void); #endif diff --git a/src/m_menu.c b/src/m_menu.c index 128b15a76..1ab361b80 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -66,6 +66,13 @@ // And just some randomness for the exits. #include "m_random.h" +#if defined(HAVE_SDL) +#include "SDL.h" +#if SDL_VERSION_ATLEAST(2,0,0) +#include "sdl/sdlmain.h" // JOYSTICK_HOTPLUG +#endif +#endif + #ifdef PC_DOS #include // for snprintf int snprintf(char *str, size_t n, const char *fmt, ...); @@ -118,7 +125,7 @@ const char *quitmsg[NUM_QUITMESSAGES]; // Stuff for customizing the player select screen Tails 09-22-2003 description_t description[MAXSKINS]; -INT16 char_on = -1, startchar = 1; +INT16 char_on = -1, startchar = 0; static char *char_notes = NULL; static fixed_t char_scroll = 0; @@ -136,7 +143,7 @@ typedef enum levellist_mode_t levellistmode = LLM_CREATESERVER; UINT8 maplistoption = 0; -static char joystickInfo[8][29]; +static char joystickInfo[MAX_JOYSTICKS+1][29]; #ifndef NONET static UINT32 serverlistpage; #endif @@ -265,6 +272,7 @@ static void M_ServerOptions(INT32 choice); #ifndef NONET static void M_StartServerMenu(INT32 choice); static void M_ConnectMenu(INT32 choice); +static void M_ConnectMenuModChecks(INT32 choice); static void M_Refresh(INT32 choice); static void M_Connect(INT32 choice); static void M_ChooseRoom(INT32 choice); @@ -275,9 +283,10 @@ menu_t MP_MainDef; // Split into multiple parts due to size // Controls menu_t OP_ChangeControlsDef; -menu_t OP_MPControlsDef, OP_CameraControlsDef, OP_MiscControlsDef; +menu_t OP_MPControlsDef, OP_MiscControlsDef; menu_t OP_P1ControlsDef, OP_P2ControlsDef, OP_MouseOptionsDef; menu_t OP_Mouse2OptionsDef, OP_Joystick1Def, OP_Joystick2Def; +menu_t OP_CameraOptionsDef, OP_Camera2OptionsDef; static void M_VideoModeMenu(INT32 choice); static void M_Setup1PControlsMenu(INT32 choice); static void M_Setup2PControlsMenu(INT32 choice); @@ -307,7 +316,8 @@ static void M_Addons(INT32 choice); static void M_AddonsOptions(INT32 choice); static patch_t *addonsp[NUM_EXT+5]; -#define numaddonsshown 4 +#define addonmenusize 9 // number of items actually displayed in the addons menu view, formerly (2*numaddonsshown + 1) +#define numaddonsshown 4 // number of items to each side of the currently selected item, unless at top/bottom ends of directory static void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlight, boolean allowlowercase); @@ -884,12 +894,12 @@ static menuitem_t MP_SplitServerMenu[] = static menuitem_t MP_MainMenu[] = { - {IT_HEADER, NULL, "Host a game", NULL, 0}, - {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 12}, - {IT_STRING|IT_CALL, NULL, "Splitscreen...", M_StartSplitServerMenu, 22}, - {IT_HEADER, NULL, "Join a game", NULL, 40}, - {IT_STRING|IT_CALL, NULL, "Server browser...", M_ConnectMenu, 52}, - {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 62}, + {IT_HEADER, NULL, "Join a game", NULL, 0}, + {IT_STRING|IT_CALL, NULL, "Server browser...", M_ConnectMenuModChecks, 12}, + {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 22}, + {IT_HEADER, NULL, "Host a game", NULL, 54}, + {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 66}, + {IT_STRING|IT_CALL, NULL, "Splitscreen...", M_StartSplitServerMenu, 76}, {IT_HEADER, NULL, "Player setup", NULL, 94}, {IT_STRING|IT_CALL, NULL, "Player 1...", M_SetupMultiPlayer, 106}, {IT_STRING|IT_CALL, NULL, "Player 2... ", M_SetupMultiPlayer2, 116}, @@ -948,7 +958,7 @@ enum static menuitem_t MP_RoomMenu[] = { - {IT_STRING | IT_CALL, NULL, "", M_ChooseRoom, 9}, + {IT_STRING | IT_CALL, NULL, "", M_ChooseRoom, 9}, {IT_DISABLED, NULL, "", M_ChooseRoom, 18}, {IT_DISABLED, NULL, "", M_ChooseRoom, 27}, {IT_DISABLED, NULL, "", M_ChooseRoom, 36}, @@ -1002,13 +1012,11 @@ static menuitem_t OP_P1ControlsMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Mouse Options...", &OP_MouseOptionsDef, 20}, {IT_SUBMENU | IT_STRING, NULL, "Gamepad Options...", &OP_Joystick1Def , 30}, - {IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam , 50}, - {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam , 60}, - {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 70}, + {IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_CameraOptionsDef, 50}, - //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog, 90}, - {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar, 90}, - {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake, 100}, + //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog, 100}, + {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar, 70}, + {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake, 80}, }; static menuitem_t OP_P2ControlsMenu[] = @@ -1017,13 +1025,11 @@ static menuitem_t OP_P2ControlsMenu[] = {IT_SUBMENU | IT_STRING, NULL, "Second Mouse Options...", &OP_Mouse2OptionsDef, 20}, {IT_SUBMENU | IT_STRING, NULL, "Second Gamepad Options...", &OP_Joystick2Def , 30}, - {IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam2 , 50}, - {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam2 , 60}, - {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 70}, + {IT_SUBMENU | IT_STRING, NULL, "Camera Options...", &OP_Camera2OptionsDef, 50}, - //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog2, 90}, - {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar2, 90}, - {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake2, 100}, + //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog2, 100}, + {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar2, 70}, + {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake2, 80}, }; static menuitem_t OP_ChangeControlsMenu[] = @@ -1113,14 +1119,7 @@ static menuitem_t OP_Joystick2Menu[] = {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130}, }; -static menuitem_t OP_JoystickSetMenu[] = -{ - {IT_CALL | IT_NOTHING, "None", NULL, M_AssignJoystick, '0'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '1'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '2'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '3'}, - {IT_CALL | IT_NOTHING, "", NULL, M_AssignJoystick, '4'}, -}; +static menuitem_t OP_JoystickSetMenu[1+MAX_JOYSTICKS]; static menuitem_t OP_MouseOptionsMenu[] = { @@ -1152,6 +1151,34 @@ static menuitem_t OP_Mouse2OptionsMenu[] = NULL, "Mouse Y Sensitivity", &cv_mouseysens2, 80}, }; +static menuitem_t OP_CameraOptionsMenu[] = +{ + {IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam , 10}, + {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam , 20}, + {IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam_orbit , 30}, + {IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam_adjust, 40}, + + {IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam_dist, 60}, + {IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam_height, 70}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Speed", &cv_cam_speed, 80}, + + {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 100}, +}; + +static menuitem_t OP_Camera2OptionsMenu[] = +{ + {IT_STRING | IT_CVAR, NULL, "Third-person Camera" , &cv_chasecam2 , 10}, + {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam2 , 20}, + {IT_STRING | IT_CVAR, NULL, "Orbital Looking" , &cv_cam2_orbit , 30}, + {IT_STRING | IT_CVAR, NULL, "Downhill Slope Adjustment", &cv_cam2_adjust, 40}, + + {IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Distance", &cv_cam2_dist, 60}, + {IT_STRING | IT_CVAR | IT_CV_INTEGERSTEP, NULL, "Camera Height", &cv_cam2_height, 70}, + {IT_STRING | IT_CVAR | IT_CV_FLOATSLIDER, NULL, "Camera Speed", &cv_cam2_speed, 80}, + + {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 100}, +}; + static menuitem_t OP_VideoOptionsMenu[] = { {IT_HEADER, NULL, "Screen", NULL, 0}, @@ -1322,6 +1349,12 @@ static menuitem_t OP_SoundOptionsMenu[] = #define OPENMPT_MENUOFFSET 0 #endif +#ifdef HAVE_MIXERX +#define MIXERX_MENUOFFSET 81 +#else +#define MIXERX_MENUOFFSET 0 +#endif + static menuitem_t OP_SoundAdvancedMenu[] = { #ifdef HAVE_OPENMPT @@ -1333,12 +1366,15 @@ static menuitem_t OP_SoundAdvancedMenu[] = {IT_HEADER, NULL, "MIDI Settings", NULL, OPENMPT_MENUOFFSET+10}, {IT_STRING | IT_CVAR, NULL, "MIDI Player", &cv_midiplayer, OPENMPT_MENUOFFSET+22}, {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "FluidSynth Sound Font File", &cv_midisoundfontpath, OPENMPT_MENUOFFSET+34}, - {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "TiMidity++ Config Folder", &cv_miditimiditypath, OPENMPT_MENUOFFSET+61} + {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "TiMidity++ Config Folder", &cv_miditimiditypath, OPENMPT_MENUOFFSET+61}, #endif + + {IT_HEADER, NULL, "Miscellaneous", NULL, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET+10}, + {IT_STRING | IT_CVAR, NULL, "Let Levels Force Reset Music", &cv_resetmusicbyheader, OPENMPT_MENUOFFSET+MIXERX_MENUOFFSET+22}, }; #undef OPENMPT_MENUOFFSET - +#undef MIXERX_MENUOFFSET #endif static menuitem_t OP_DataOptionsMenu[] = @@ -1353,36 +1389,39 @@ static menuitem_t OP_ScreenshotOptionsMenu[] = { {IT_HEADER, NULL, "General", NULL, 0}, {IT_STRING|IT_CVAR, NULL, "Use color profile", &cv_screenshot_colorprofile, 6}, - {IT_STRING|IT_CVAR, NULL, "Storage Location", &cv_screenshot_option, 11}, - {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_screenshot_folder, 16}, - {IT_HEADER, NULL, "Screenshots (F8)", NULL, 30}, - {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memory, 36}, - {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_level, 41}, - {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategy, 46}, - {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bits, 51}, + {IT_HEADER, NULL, "Screenshots (F8)", NULL, 16}, + {IT_STRING|IT_CVAR, NULL, "Storage Location", &cv_screenshot_option, 22}, + {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_screenshot_folder, 27}, + {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memory, 42}, + {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_level, 47}, + {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategy, 52}, + {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bits, 57}, - {IT_HEADER, NULL, "Movie Mode (F9)", NULL, 60}, - {IT_STRING|IT_CVAR, NULL, "Capture Mode", &cv_moviemode, 66}, + {IT_HEADER, NULL, "Movie Mode (F9)", NULL, 64}, + {IT_STRING|IT_CVAR, NULL, "Storage Location", &cv_movie_option, 70}, + {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_movie_folder, 75}, + {IT_STRING|IT_CVAR, NULL, "Capture Mode", &cv_moviemode, 90}, - {IT_STRING|IT_CVAR, NULL, "Region Optimizing", &cv_gif_optimize, 71}, - {IT_STRING|IT_CVAR, NULL, "Downscaling", &cv_gif_downscale, 76}, + {IT_STRING|IT_CVAR, NULL, "Region Optimizing", &cv_gif_optimize, 95}, + {IT_STRING|IT_CVAR, NULL, "Downscaling", &cv_gif_downscale, 100}, - {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memorya, 71}, - {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_levela, 76}, - {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategya, 81}, - {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bitsa, 86}, + {IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memorya, 95}, + {IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_levela, 100}, + {IT_STRING|IT_CVAR, NULL, "Strategy", &cv_zlib_strategya, 105}, + {IT_STRING|IT_CVAR, NULL, "Window Size", &cv_zlib_window_bitsa, 110}, }; enum { op_screenshot_colorprofile = 1, - op_screenshot_folder = 3, - op_screenshot_capture = 10, - op_screenshot_gif_start = 11, - op_screenshot_gif_end = 12, - op_screenshot_apng_start = 13, - op_screenshot_apng_end = 16, + op_screenshot_folder = 4, + op_movie_folder = 11, + op_screenshot_capture = 12, + op_screenshot_gif_start = 13, + op_screenshot_gif_end = 14, + op_screenshot_apng_start = 15, + op_screenshot_apng_end = 18, }; static menuitem_t OP_EraseDataMenu[] = @@ -1877,6 +1916,13 @@ menu_t OP_JoystickSetDef = 0, NULL }; +menu_t OP_CameraOptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P1CONTROLS << 6) + (MN_OP_P1CAMERA << 12), + "M_CONTRO", OP_CameraOptionsMenu, &OP_P1ControlsDef, 35, 30); +menu_t OP_Camera2OptionsDef = DEFAULTMENUSTYLE( + MN_OP_MAIN + (MN_OP_P2CONTROLS << 6) + (MN_OP_P2CAMERA << 12), + "M_CONTRO", OP_Camera2OptionsMenu, &OP_P2ControlsDef, 35, 30); + menu_t OP_VideoOptionsDef = { @@ -2200,6 +2246,12 @@ void Addons_option_Onchange(void) (cv_addons_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); } +void Moviemode_option_Onchange(void) +{ + OP_ScreenshotOptionsMenu[op_movie_folder].status = + (cv_movie_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); +} + // ========================================================================== // END ORGANIZATION STUFF. // ========================================================================== @@ -2738,13 +2790,27 @@ static void M_ChangeCvar(INT32 choice) ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_INVISSLIDER) ||((currentMenu->menuitems[itemOn].status & IT_CVARTYPE) == IT_CV_NOMOD)) { - CV_SetValue(cv,cv->value+(choice)); + if (cv->flags & CV_FLOAT && (currentMenu->menuitems[itemOn].status & IT_CV_FLOATSLIDER) == IT_CV_FLOATSLIDER) + { + char s[20]; + sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); + CV_Set(cv,s); + } + else + CV_SetValue(cv,cv->value+(choice)); } else if (cv->flags & CV_FLOAT) { - char s[20]; - sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); - CV_Set(cv,s); + if (currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP) + { + CV_SetValue(cv,FIXED_TO_FLOAT(cv->value)+(choice)); + } + else + { + char s[20]; + sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); + CV_Set(cv,s); + } } else CV_AddValue(cv,choice); @@ -3478,6 +3544,8 @@ void M_Ticker(void) // void M_Init(void) { + int i; + CV_RegisterVar(&cv_nextmap); CV_RegisterVar(&cv_newgametype); CV_RegisterVar(&cv_chooseskin); @@ -3527,6 +3595,17 @@ void M_Init(void) OP_ScreenshotOptionsMenu[op_screenshot_colorprofile].status = IT_GRAYEDOUT; #endif + /* + Well the menu sucks for forcing us to have an item set + at all if every item just calls the same function, and + nothing more. Now just automate the definition. + */ + for (i = 0; i <= MAX_JOYSTICKS; ++i) + { + OP_JoystickSetMenu[i].status = ( IT_NOTHING|IT_CALL ); + OP_JoystickSetMenu[i].itemaction = M_AssignJoystick; + } + #ifndef NONET CV_RegisterVar(&cv_serversort); #endif @@ -3634,7 +3713,12 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) for (i = 0; cv->PossibleValue[i+1].strvalue; i++); - if ((range = atoi(cv->defaultvalue)) != cv->value) + if (cv->flags & CV_FLOAT) + range = (INT32)(atof(cv->defaultvalue)*FRACUNIT); + else + range = atoi(cv->defaultvalue); + + if (range != cv->value) { range = ((range - cv->PossibleValue[0].value) * 100 / (cv->PossibleValue[i].value - cv->PossibleValue[0].value)); @@ -4510,6 +4594,9 @@ static boolean M_CanShowLevelOnPlatter(INT32 mapnum, INT32 gt) if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) return false; + if (G_IsSpecialStage(mapnum+1)) + return false; + if (gt == GT_COOP && (mapheaderinfo[mapnum]->typeoflevel & TOL_COOP)) return true; @@ -5603,7 +5690,7 @@ static boolean M_AddonsRefresh(void) { S_StartSound(NULL, sfx_lose); if (refreshdirmenu & REFRESHDIR_MAX) - message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you want to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); + message = va("%c%s\x80\nMaximum number of add-ons reached.\nA file could not be loaded.\nIf you wish to play with this add-on, restart the game to clear existing ones.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); else message = va("%c%s\x80\nA file was not loaded.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname); } @@ -5629,7 +5716,8 @@ static boolean M_AddonsRefresh(void) static void M_DrawAddons(void) { INT32 x, y; - ssize_t i, m; + size_t i, m; + size_t t, b; // top and bottom item #s to draw in directory const UINT8 *flashcol = NULL; UINT8 hilicol; @@ -5668,52 +5756,63 @@ static void M_DrawAddons(void) hilicol = 0; // white +#define boxwidth (MAXSTRINGLENGTH*8+6) + + // draw the file path and the top white + black lines of the box V_DrawString(x-21, (y - 16) + (lsheadingheight - 12), highlightflags|V_ALLOWLOWERCASE, M_AddonsHeaderPath()); - V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), MAXSTRINGLENGTH*8+6, 1, hilicol); - V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), MAXSTRINGLENGTH*8+6, 1, 30); + V_DrawFill(x-21, (y - 16) + (lsheadingheight - 3), boxwidth, 1, hilicol); + V_DrawFill(x-21, (y - 16) + (lsheadingheight - 2), boxwidth, 1, 30); m = (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1); // addons menu back color - V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 159); + V_DrawFill(x-21, y - 1, boxwidth, m, 159); - // scrollbar! - if (sizedirmenu <= (2*numaddonsshown + 1)) - i = 0; + // The directory is too small for a scrollbar, so just draw a tall white line + if (sizedirmenu <= addonmenusize) + { + t = 0; // first item + b = sizedirmenu - 1; // last item + i = 0; // "scrollbar" at "top" position + } else { - ssize_t q = m; - m = ((2*numaddonsshown + 1) * m)/sizedirmenu; + size_t q = m; + m = (addonmenusize * m)/sizedirmenu; // height of scroll bar if (dir_on[menudepthleft] <= numaddonsshown) // all the way up - i = 0; - else if (sizedirmenu <= (dir_on[menudepthleft] + numaddonsshown + 1)) // all the way down - i = q-m; - else - i = ((dir_on[menudepthleft] - numaddonsshown) * (q-m))/(sizedirmenu - (2*numaddonsshown + 1)); + { + t = 0; // first item + b = addonmenusize - 1; //9th item + i = 0; // scrollbar at top position + } + else if (dir_on[menudepthleft] >= sizedirmenu - (numaddonsshown + 1)) // all the way down + { + t = sizedirmenu - addonmenusize; // # 9th last + b = sizedirmenu - 1; // last item + i = q-m; // scrollbar at bottom position + } + else // somewhere in the middle + { + t = dir_on[menudepthleft] - numaddonsshown; // 4 items above + b = dir_on[menudepthleft] + numaddonsshown; // 4 items below + i = (t * (q-m))/(sizedirmenu - addonmenusize); // calculate position of scrollbar + } } - V_DrawFill(x + MAXSTRINGLENGTH*8+5 - 21, (y - 1) + i, 1, m, hilicol); + // draw the scrollbar! + V_DrawFill((x-21) + boxwidth-1, (y - 1) + i, 1, m, hilicol); - // get bottom... - m = dir_on[menudepthleft] + numaddonsshown + 1; - if (m > (ssize_t)sizedirmenu) - m = sizedirmenu; +#undef boxwidth - // then compute top and adjust bottom if needed! - if (m < (2*numaddonsshown + 1)) - { - m = min(sizedirmenu, 2*numaddonsshown + 1); - i = 0; - } - else - i = m - (2*numaddonsshown + 1); - - if (i != 0) + // draw up arrow that bobs up and down + if (t != 0) V_DrawString(19, y+4 - (skullAnimCounter/5), highlightflags, "\x1A"); + // make the selection box flash yellow if (skullAnimCounter < 4) flashcol = V_GetStringColormap(highlightflags); - for (; i < m; i++) + // draw icons and item names + for (i = t; i <= b; i++) { UINT32 flags = V_ALLOWLOWERCASE; if (y > BASEVIDHEIGHT) break; @@ -5729,12 +5828,14 @@ static void M_DrawAddons(void) else V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[(type & ~EXT_LOADED)]); + // draw selection box for the item currently selected if ((size_t)i == dir_on[menudepthleft]) { V_DrawFixedPatch((x-(16+4))< (charsonside*2 + 3)) V_DrawString(x, y+4, flags, va("%.*s...%s", charsonside, dirmenu[i]+DIR_STRING, dirmenu[i]+DIR_STRING+dirmenu[i][DIR_LEN]-(charsonside+1))); @@ -5746,9 +5847,11 @@ static void M_DrawAddons(void) y += 16; } - if (m != (ssize_t)sizedirmenu) + // draw down arrow that bobs down and up + if (b != sizedirmenu) V_DrawString(19, y-12 + (skullAnimCounter/5), highlightflags, "\x1B"); + // draw search box y = BASEVIDHEIGHT - currentMenu->y + 1; M_DrawTextBox(x - (21 + 5), y, MAXSTRINGLENGTH, 1); @@ -5760,9 +5863,11 @@ static void M_DrawAddons(void) V_DrawCharacter(x - 18 + V_StringWidth(menusearch+1, 0), y + 8, '_' | 0x80, false); + // draw search icon x -= (21 + 5 + 16); V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]); + // draw save icon x = BASEVIDWIDTH - x - 16; V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); @@ -6885,6 +6990,7 @@ static void M_StartTutorial(INT32 choice) tutorialmode = true; // turn on tutorial mode emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); M_ClearMenus(true); gamecomplete = false; cursaveslot = 0; @@ -7051,7 +7157,7 @@ static void M_DrawLoadGameData(void) } } - y -= 13; + y -= 4; // character heads, lives, and continues { @@ -7060,7 +7166,7 @@ static void M_DrawLoadGameData(void) patch_t *patch; UINT8 *colormap = NULL; - INT32 tempx = (x+40)<highresscale, 0, patch, colormap); Z_Free(colormap); - tempx -= (15<spriteframes[0]; patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); - if ((calc = SHORT(patch->topoffset) - 42) > 0) - tempy += ((4+calc)<highresscale, flip, patch, colormap); skipsign: - y += 25; + y += 16; tempx = x + 10; if (savegameinfo[savetodraw].lives != INFLIVES @@ -7293,7 +7397,29 @@ static void M_ReadSavegameInfo(UINT32 slot) // File end marker check CHECKPOS - if (READUINT8(save_p) != 0x1d) BADSAVE; + switch (READUINT8(save_p)) + { + case 0xb7: + { + UINT8 i, banksinuse; + CHECKPOS + banksinuse = READUINT8(save_p); + CHECKPOS + if (banksinuse > NUM_LUABANKS) + BADSAVE + for (i = 0; i < banksinuse; i++) + { + (void)READINT32(save_p); + CHECKPOS + } + if (READUINT8(save_p) != 0x1d) + BADSAVE + } + case 0x1d: + break; + default: + BADSAVE + } // done Z_Free(savebuffer); @@ -8479,8 +8605,8 @@ static void M_NightsAttack(INT32 choice) M_PatchSkinNameTable(); G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching - M_SetupNextMenu(&SP_NightsAttackDef); titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please + M_SetupNextMenu(&SP_NightsAttackDef); if (!M_CanShowLevelInList(cv_nextmap.value-1, -1) && levelselect.rows[0].maplist[0]) CV_SetValue(&cv_nextmap, levelselect.rows[0].maplist[0]); else @@ -8495,6 +8621,7 @@ static void M_ChooseNightsAttack(INT32 choice) char nameofdemo[256]; (void)choice; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); M_ClearMenus(true); modeattacking = ATTACKING_NIGHTS; @@ -8519,6 +8646,7 @@ static void M_ChooseTimeAttack(INT32 choice) char nameofdemo[256]; (void)choice; emeralds = 0; + memset(&luabanks, 0, sizeof(luabanks)); M_ClearMenus(true); modeattacking = ATTACKING_RECORD; @@ -8872,7 +9000,7 @@ static void M_DrawConnectMenu(void) // Room name if (ms_RoomId < 0) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey, - V_YELLOWMAP, (itemOn == mp_connect_room) ? "" : ""); else V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ConnectMenu[mp_connect_room].alphaKey, V_YELLOWMAP, room_list[menuRoomIndex].name); @@ -9022,11 +9150,32 @@ static void M_ConnectMenu(INT32 choice) // first page of servers serverlistpage = 0; - M_SetupNextMenu(&MP_ConnectDef); + if (ms_RoomId < 0) + { + M_RoomMenu(0); // Select a room instead of staring at an empty list + // This prevents us from returning to the modified game alert. + currentMenu->prevMenu = &MP_MainDef; + } + else + M_SetupNextMenu(&MP_ConnectDef); itemOn = 0; M_Refresh(0); } +static void M_ConnectMenuModChecks(INT32 choice) +{ + (void)choice; + // okay never mind we want to COMMUNICATE to the player pre-emptively instead of letting them try and then get confused when it doesn't work + + if (modifiedgame) + { + M_StartMessage(M_GetText("Add-ons are currently loaded.\n\nYou will only be able to join a server if\nit has the same ones loaded in the same order, which may be unlikely.\n\nIf you wish to play on other servers,\nrestart the game to clear existing add-ons.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER); + return; + } + + M_ConnectMenu(-1); +} + static UINT32 roomIds[NUM_LIST_ROOMS]; static void M_RoomMenu(INT32 choice) @@ -9081,7 +9230,16 @@ static void M_ChooseRoom(INT32 choice) } serverlistpage = 0; - M_SetupNextMenu(currentMenu->prevMenu); + /* + We were on the Multiplayer menu? That means that we must have been trying to + view the server browser, but we hadn't selected a room yet. So we need to go + to the browser next, not back there. + */ + if (currentMenu->prevMenu == &MP_MainDef) + M_SetupNextMenu(&MP_ConnectDef); + else + M_SetupNextMenu(currentMenu->prevMenu); + if (currentMenu == &MP_ConnectDef) M_Refresh(0); } @@ -9140,7 +9298,7 @@ static void M_DrawServerMenu(void) M_DrawLevelPlatterHeader(currentMenu->y - lsheadingheight/2, "Server settings", true, false); if (ms_RoomId < 0) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, - V_YELLOWMAP, (itemOn == mp_server_room) ? "" : ""); else V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, V_YELLOWMAP, room_list[menuRoomIndex].name); @@ -9247,7 +9405,7 @@ static void M_StartServerMenu(INT32 choice) // CONNECT VIA IP // ============== -static char setupm_ip[16]; +static char setupm_ip[28]; // Draw the funky Connect IP menu. Tails 11-19-2002 // So much work for such a little thing! @@ -9259,30 +9417,26 @@ static void M_DrawMPMainMenu(void) // use generic drawer for cursor, items and title M_DrawGenericMenu(); -#if MAXPLAYERS == 32 - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+12, - ((itemOn == 1) ? V_YELLOWMAP : 0), "(2-32 players)"); -#else -Update the maxplayers label... -#endif + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+66, + ((itemOn == 4) ? V_YELLOWMAP : 0), va("(2-%d players)", MAXPLAYERS)); - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+22, - ((itemOn == 2) ? V_YELLOWMAP : 0), "(2 players)"); + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+76, + ((itemOn == 5) ? V_YELLOWMAP : 0), "(2 players)"); V_DrawRightAlignedString(BASEVIDWIDTH-x, y+116, ((itemOn == 8) ? V_YELLOWMAP : 0), "(splitscreen)"); - y += 62; + y += 22; V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 159); // draw name string - V_DrawString(x+8,y+12, V_MONOSPACE, setupm_ip); + V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, setupm_ip); // draw text cursor for name - if (itemOn == 5 //0 + if (itemOn == 2 //0 && skullAnimCounter < 4) //blink cursor - V_DrawCharacter(x+8+V_StringWidth(setupm_ip, V_MONOSPACE),y+12,'_',false); + V_DrawCharacter(x+8+V_StringWidth(setupm_ip, V_ALLOWLOWERCASE),y+12,'_',false); } // Tails 11-19-2002 @@ -9353,10 +9507,11 @@ static void M_HandleConnectIP(INT32 choice) default: l = strlen(setupm_ip); - if (l >= 16-1) + if (l >= 28-1) break; - if (choice == 46 || (choice >= 48 && choice <= 57)) // Rudimentary number and period enforcing + // Rudimentary number and period enforcing - also allows letters so hostnames can be used instead + if ((choice >= '-' && choice <= ':') || (choice >= 'A' && choice <= 'Z') || (choice >= 'a' && choice <= 'z')) { S_StartSound(NULL,sfx_menu1); // Tails setupm_ip[l] = (char)choice; @@ -9858,18 +10013,33 @@ static void M_ScreenshotOptions(INT32 choice) static void M_DrawJoystick(void) { - INT32 i; + INT32 i, compareval2, compareval; // draw title (or big pic) M_DrawMenuTitle(); - for (i = 0; i <= 4; i++) // See MAX_JOYSTICKS + for (i = 0; i <= MAX_JOYSTICKS; i++) // See MAX_JOYSTICKS { M_DrawTextBox(OP_JoystickSetDef.x-8, OP_JoystickSetDef.y+LINEHEIGHT*i-12, 28, 1); //M_DrawSaveLoadBorder(OP_JoystickSetDef.x+4, OP_JoystickSetDef.y+1+LINEHEIGHT*i); - if ((setupcontrols_secondaryplayer && (i == cv_usejoystick2.value)) - || (!setupcontrols_secondaryplayer && (i == cv_usejoystick.value))) +#ifdef JOYSTICK_HOTPLUG + if (atoi(cv_usejoystick2.string) > I_NumJoys()) + compareval2 = atoi(cv_usejoystick2.string); + else + compareval2 = cv_usejoystick2.value; + + if (atoi(cv_usejoystick.string) > I_NumJoys()) + compareval = atoi(cv_usejoystick.string); + else + compareval = cv_usejoystick.value; +#else + compareval2 = cv_usejoystick2.value; + compareval = cv_usejoystick.value +#endif + + if ((setupcontrols_secondaryplayer && (i == compareval2)) + || (!setupcontrols_secondaryplayer && (i == compareval))) V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,V_GREENMAP,joystickInfo[i]); else V_DrawString(OP_JoystickSetDef.x, OP_JoystickSetDef.y+LINEHEIGHT*i-4,0,joystickInfo[i]); @@ -9882,7 +10052,7 @@ static void M_DrawJoystick(void) } } -static void M_SetupJoystickMenu(INT32 choice) +void M_SetupJoystickMenu(INT32 choice) { INT32 i = 0; const char *joyNA = "Unavailable"; @@ -9891,12 +10061,27 @@ static void M_SetupJoystickMenu(INT32 choice) strcpy(joystickInfo[i], "None"); - for (i = 1; i < 8; i++) + for (i = 1; i <= MAX_JOYSTICKS; i++) { if (i <= n && (I_GetJoyName(i)) != NULL) strncpy(joystickInfo[i], I_GetJoyName(i), 28); else strcpy(joystickInfo[i], joyNA); + +#ifdef JOYSTICK_HOTPLUG + // We use cv_usejoystick.string as the USER-SET var + // and cv_usejoystick.value as the INTERNAL var + // + // In practice, if cv_usejoystick.string == 0, this overrides + // cv_usejoystick.value and always disables + // + // Update cv_usejoystick.string here so that the user can + // properly change this value. + if (i == cv_usejoystick.value) + CV_SetValue(&cv_usejoystick, i); + if (i == cv_usejoystick2.value) + CV_SetValue(&cv_usejoystick2, i); +#endif } M_SetupNextMenu(&OP_JoystickSetDef); @@ -9926,10 +10111,76 @@ static void M_Setup2PJoystickMenu(INT32 choice) static void M_AssignJoystick(INT32 choice) { +#ifdef JOYSTICK_HOTPLUG + INT32 oldchoice, oldstringchoice; + INT32 numjoys = I_NumJoys(); + + if (setupcontrols_secondaryplayer) + { + oldchoice = oldstringchoice = atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value; + CV_SetValue(&cv_usejoystick2, choice); + + // Just in case last-minute changes were made to cv_usejoystick.value, + // update the string too + // But don't do this if we're intentionally setting higher than numjoys + if (choice <= numjoys) + { + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + // reset this so the comparison is valid + if (oldchoice > numjoys) + oldchoice = cv_usejoystick2.value; + + if (oldchoice != choice) + { + if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device + CV_SetValue(&cv_usejoystick2, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); + + if (oldstringchoice == + (atoi(cv_usejoystick2.string) > numjoys ? atoi(cv_usejoystick2.string) : cv_usejoystick2.value)) + M_StartMessage("This gamepad is used by another\n" + "player. Reset the gamepad\n" + "for that player first.\n\n" + "(Press a key)\n", NULL, MM_NOTHING); + } + } + } + else + { + oldchoice = oldstringchoice = atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value; + CV_SetValue(&cv_usejoystick, choice); + + // Just in case last-minute changes were made to cv_usejoystick.value, + // update the string too + // But don't do this if we're intentionally setting higher than numjoys + if (choice <= numjoys) + { + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + // reset this so the comparison is valid + if (oldchoice > numjoys) + oldchoice = cv_usejoystick.value; + + if (oldchoice != choice) + { + if (choice && oldstringchoice > numjoys) // if we did not select "None", we likely selected a used device + CV_SetValue(&cv_usejoystick, (oldstringchoice > numjoys ? oldstringchoice : oldchoice)); + + if (oldstringchoice == + (atoi(cv_usejoystick.string) > numjoys ? atoi(cv_usejoystick.string) : cv_usejoystick.value)) + M_StartMessage("This gamepad is used by another\n" + "player. Reset the gamepad\n" + "for that player first.\n\n" + "(Press a key)\n", NULL, MM_NOTHING); + } + } + } +#else if (setupcontrols_secondaryplayer) CV_SetValue(&cv_usejoystick2, choice); else CV_SetValue(&cv_usejoystick, choice); +#endif } // ============= diff --git a/src/m_menu.h b/src/m_menu.h index 347725e10..05962d2b1 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -72,10 +72,12 @@ typedef enum MN_OP_P1MOUSE, MN_OP_P1JOYSTICK, MN_OP_JOYSTICKSET, // OP_JoystickSetDef shared with P2 + MN_OP_P1CAMERA, MN_OP_P2CONTROLS, MN_OP_P2MOUSE, MN_OP_P2JOYSTICK, + MN_OP_P2CAMERA, MN_OP_VIDEO, MN_OP_VIDEOMODE, @@ -206,7 +208,6 @@ void M_QuitResponse(INT32 ch); // Determines whether to show a level in the list (platter version does not need to be exposed) boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); - // flags for items in the menu // menu handle (what we do when key is pressed #define IT_TYPE 14 // (2+4+8) @@ -242,6 +243,8 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); #define IT_CV_NOPRINT 1536 #define IT_CV_NOMOD 2048 #define IT_CV_INVISSLIDER 2560 +#define IT_CV_INTEGERSTEP 4096 // if IT_CV_NORMAL and cvar is CV_FLOAT, modify it by 1 instead of 0.0625 +#define IT_CV_FLOATSLIDER 4608 // IT_CV_SLIDER, value modified by 0.0625 instead of 1 (for CV_FLOAT cvars) //call/submenu specific // There used to be a lot more here but ... @@ -309,6 +312,10 @@ extern menu_t *currentMenu; extern menu_t MainDef; extern menu_t SP_LoadDef; +// Call upon joystick hotplug +void M_SetupJoystickMenu(INT32 choice); +extern menu_t OP_JoystickSetDef; + // Stuff for customizing the player select screen typedef struct { @@ -397,6 +404,9 @@ void Screenshot_option_Onchange(void); // Addons menu updating void Addons_option_Onchange(void); +// Moviemode menu updating +void Moviemode_option_Onchange(void); + // These defines make it a little easier to make menus #define DEFAULTMENUSTYLE(id, header, source, prev, x, y)\ {\ diff --git a/src/m_misc.c b/src/m_misc.c index 22e19df73..aaaf30d67 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -108,6 +108,9 @@ consvar_t cv_screenshot_colorprofile = {"screenshot_colorprofile", "Yes", CV_SAV static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}}; consvar_t cv_moviemode = {"moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_movie_option = {"movie_option", "Default", CV_SAVE|CV_CALL, screenshot_cons_t, Moviemode_option_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_movie_folder = {"movie_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; + static CV_PossibleValue_t zlib_mem_level_t[] = { {1, "(Min Memory) 1"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5"}, {6, "6"}, {7, "7"}, @@ -1124,19 +1127,25 @@ static inline moviemode_t M_StartMovieGIF(const char *pathname) void M_StartMovie(void) { #if NUMSCREENS > 2 - const char *pathname = "."; + char pathname[MAX_WADPATH]; if (moviemode) return; - if (cv_screenshot_option.value == 0) - pathname = usehome ? srb2home : srb2path; - else if (cv_screenshot_option.value == 1) - pathname = srb2home; - else if (cv_screenshot_option.value == 2) - pathname = srb2path; - else if (cv_screenshot_option.value == 3 && *cv_screenshot_folder.string != '\0') - pathname = cv_screenshot_folder.string; + if (cv_movie_option.value == 0) + strcpy(pathname, usehome ? srb2home : srb2path); + else if (cv_movie_option.value == 1) + strcpy(pathname, srb2home); + else if (cv_movie_option.value == 2) + strcpy(pathname, srb2path); + else if (cv_movie_option.value == 3 && *cv_movie_folder.string != '\0') + strcpy(pathname, cv_movie_folder.string); + + if (cv_movie_option.value != 3) + { + strcat(pathname, PATHSEP"movies"PATHSEP); + I_mkdir(pathname, 0755); + } if (rendermode == render_none) I_Error("Can't make a movie without a render system\n"); @@ -1474,7 +1483,8 @@ void M_ScreenShot(void) void M_DoScreenShot(void) { #if NUMSCREENS > 2 - const char *freename = NULL, *pathname = "."; + const char *freename = NULL; + char pathname[MAX_WADPATH]; boolean ret = false; UINT8 *linear = NULL; @@ -1486,13 +1496,19 @@ void M_DoScreenShot(void) return; if (cv_screenshot_option.value == 0) - pathname = usehome ? srb2home : srb2path; + strcpy(pathname, usehome ? srb2home : srb2path); else if (cv_screenshot_option.value == 1) - pathname = srb2home; + strcpy(pathname, srb2home); else if (cv_screenshot_option.value == 2) - pathname = srb2path; + strcpy(pathname, srb2path); else if (cv_screenshot_option.value == 3 && *cv_screenshot_folder.string != '\0') - pathname = cv_screenshot_folder.string; + strcpy(pathname, cv_screenshot_folder.string); + + if (cv_screenshot_option.value != 3) + { + strcat(pathname, PATHSEP"screenshots"PATHSEP); + I_mkdir(pathname, 0755); + } #ifdef USE_PNG freename = Newsnapshotfile(pathname,"png"); diff --git a/src/m_misc.h b/src/m_misc.h index 6ac92dbcc..7038e3e48 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -30,7 +30,7 @@ typedef enum { extern moviemode_t moviemode; extern consvar_t cv_screenshot_option, cv_screenshot_folder, cv_screenshot_colorprofile; -extern consvar_t cv_moviemode; +extern consvar_t cv_moviemode, cv_movie_folder, cv_movie_option; extern consvar_t cv_zlib_memory, cv_zlib_level, cv_zlib_strategy, cv_zlib_window_bits; extern consvar_t cv_zlib_memorya, cv_zlib_levela, cv_zlib_strategya, cv_zlib_window_bitsa; extern consvar_t cv_apng_delay; diff --git a/src/m_swap.h b/src/m_swap.h index 2d42f6138..3b50dc623 100644 --- a/src/m_swap.h +++ b/src/m_swap.h @@ -14,29 +14,39 @@ #ifndef __M_SWAP__ #define __M_SWAP__ -#include "endian.h" - // Endianess handling. // WAD files are stored little endian. +#include "endian.h" + +// Little to big endian #ifdef SRB2_BIG_ENDIAN -#define SHORT(x) ((INT16)(\ -(((UINT16)(x) & (UINT16)0x00ffU) << 8) \ -| \ -(((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ + #define SHORT(x) ((INT16)(\ + (((UINT16)(x) & (UINT16)0x00ffU) << 8) \ + | \ + (((UINT16)(x) & (UINT16)0xff00U) >> 8))) \ -#define LONG(x) ((INT32)(\ -(((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ -| \ -(((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ -| \ -(((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ -| \ -(((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) + #define LONG(x) ((INT32)(\ + (((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \ + | \ + (((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \ + | \ + (((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \ + | \ + (((UINT32)(x) & (UINT32)0xff000000UL) >> 24))) #else -#define SHORT(x) ((INT16)(x)) -#define LONG(x) ((INT32)(x)) + #define SHORT(x) ((INT16)(x)) + #define LONG(x) ((INT32)(x)) +#endif + +// Big to little endian +#ifdef SRB2_LITTLE_ENDIAN + #define BIGENDIAN_LONG(x) ((INT32)(((x)>>24)&0xff)|(((x)<<8)&0xff0000)|(((x)>>8)&0xff00)|(((x)<<24)&0xff000000)) + #define BIGENDIAN_SHORT(x) ((INT16)(((x)>>8)|((x)<<8))) +#else + #define BIGENDIAN_LONG(x) ((INT32)(x)) + #define BIGENDIAN_SHORT(x) ((INT16)(x)) #endif #endif diff --git a/src/p_enemy.c b/src/p_enemy.c index 6792623d3..1d14ebfc9 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -170,6 +170,7 @@ void A_SetReactionTime(mobj_t *actor); void A_Boss1Spikeballs(mobj_t *actor); void A_Boss3TakeDamage(mobj_t *actor); void A_Boss3Path(mobj_t *actor); +void A_Boss3ShockThink(mobj_t *actor); void A_LinedefExecute(mobj_t *actor); void A_PlaySeeSound(mobj_t *actor); void A_PlayAttackSound(mobj_t *actor); @@ -282,6 +283,7 @@ void A_Boss5CheckOnGround(mobj_t *actor); void A_Boss5CheckFalling(mobj_t *actor); void A_Boss5PinchShot(mobj_t *actor); void A_Boss5MakeItRain(mobj_t *actor); +void A_Boss5MakeJunk(mobj_t *actor); void A_LookForBetter(mobj_t *actor); void A_Boss5BombExplode(mobj_t *actor); void A_DustDevilThink(mobj_t *actor); @@ -734,6 +736,9 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed if (player->mo->health <= 0) continue; // dead + if (player->bot) + continue; // ignore bots + if (dist > 0 && P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist) continue; // Too far away @@ -3011,16 +3016,19 @@ void A_Boss7FireMissiles(mobj_t *actor) // 0 - Boss 1 Left side // 1 - Boss 1 Right side // 2 - Triple laser -// >3 - Boss 1 Middle +// 3 - Boss 1 Middle +// >=3 - Generic middle // void A_Boss1Laser(mobj_t *actor) { fixed_t x, y, z, floorz, speed; INT32 locvar1 = var1; - INT32 locvar2 = var2; + INT32 locvar2 = (var2 & 65535); + INT32 upperend = (var2>>16); INT32 i; angle_t angle; mobj_t *point; + tic_t dur; #ifdef HAVE_BLUA if (LUA_CallAction("A_Boss1Laser", actor)) @@ -3029,19 +3037,29 @@ void A_Boss1Laser(mobj_t *actor) if (!actor->target) return; + if (actor->state->tics > 1) + dur = actor->tics; + else + { + if ((upperend & 1) && (actor->extravalue2 > 1)) + actor->extravalue2--; + + dur = actor->extravalue2; + } + switch (locvar2) { case 0: - x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + x = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, FixedMul(44*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, FixedMul(44*FRACUNIT, actor->scale)); if (actor->eflags & MFE_VERTICALFLIP) z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height; else z = actor->z + FixedMul(56*FRACUNIT, actor->scale); break; case 1: - x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); - y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(43*FRACUNIT, actor->scale)); + x = actor->x + P_ReturnThrustX(actor, actor->angle-ANGLE_90, FixedMul(44*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle-ANGLE_90, FixedMul(44*FRACUNIT, actor->scale)); if (actor->eflags & MFE_VERTICALFLIP) z = actor->z + actor->height - FixedMul(56*FRACUNIT, actor->scale) - mobjinfo[locvar1].height; else @@ -3056,6 +3074,11 @@ void A_Boss1Laser(mobj_t *actor) A_Boss1Laser(actor); return; break; + case 3: + x = actor->x + P_ReturnThrustX(actor, actor->angle, FixedMul(42*FRACUNIT, actor->scale)); + y = actor->y + P_ReturnThrustY(actor, actor->angle, FixedMul(42*FRACUNIT, actor->scale)); + z = actor->z + actor->height/2; + break; default: x = actor->x; y = actor->y; @@ -3063,28 +3086,20 @@ void A_Boss1Laser(mobj_t *actor) break; } - if (!(actor->flags2 & MF2_FIRING) && actor->tics > 1) + if (!(actor->flags2 & MF2_FIRING) && dur > 1) { actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); if (mobjinfo[locvar1].seesound) S_StartSound(actor, mobjinfo[locvar1].seesound); - if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) - { - point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); - point->angle = actor->angle; - point->fuse = actor->tics+1; - P_SetTarget(&point->target, actor->target); - P_SetTarget(&actor->target, point); - } - } - /* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path - else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) - actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/ - if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH) - angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); - else - angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); + point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); + point->angle = actor->angle; + point->fuse = dur+1; + P_SetTarget(&point->target, actor->target); + P_SetTarget(&actor->target, point); + } + + angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); point = P_SpawnMobj(x, y, z, locvar1); P_SetTarget(&point->target, actor); @@ -3117,7 +3132,7 @@ void A_Boss1Laser(mobj_t *actor) point->fuse = TICRATE; } - if (actor->tics > 1) + if (dur > 1) actor->flags2 |= MF2_FIRING; else actor->flags2 &= ~MF2_FIRING; @@ -3261,6 +3276,7 @@ void A_Boss4Raise(mobj_t *actor) // 0 - Fly at the player // 1 - Fly away from the player // 2 - Strafe in relation to the player +// 3 - Dynamic mode - don't get too close to walls // var2: // 0 - Fly horizontally and vertically // 1 - Fly horizontal-only (momz = 0) @@ -3291,16 +3307,83 @@ void A_SkullAttack(mobj_t *actor) S_StartSound(actor, actor->info->activesound); A_FaceTarget(actor); + dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); + if (locvar1 == 1) actor->angle += ANGLE_180; else if (locvar1 == 2) actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90; + else if (locvar1 == 3) + { + statenum_t oldspawnstate = mobjinfo[MT_NULL].spawnstate; + UINT32 oldflags = mobjinfo[MT_NULL].flags; + fixed_t oldradius = mobjinfo[MT_NULL].radius; + fixed_t oldheight = mobjinfo[MT_NULL].height; + mobj_t *check; + INT32 i, j, k; + boolean allow; + angle_t testang; + + mobjinfo[MT_NULL].spawnstate = S_INVISIBLE; + mobjinfo[MT_NULL].flags = MF_NOGRAVITY|MF_NOTHINK|MF_NOCLIPTHING|MF_NOBLOCKMAP; + mobjinfo[MT_NULL].radius = mobjinfo[actor->type].radius; + mobjinfo[MT_NULL].height = mobjinfo[actor->type].height; + + if (P_RandomChance(FRACUNIT/2)) // port priority 1? + { + i = 9; + j = 27; + } + else + { + i = 27; + j = 9; + } + +#define dostuff(q) check = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_NULL);\ + testang = actor->angle + ((i+(q))*ANG10);\ + allow = (P_TryMove(check,\ + P_ReturnThrustX(check, testang, dist + 2*actor->radius),\ + P_ReturnThrustY(check, testang, dist + 2*actor->radius),\ + true));\ + P_RemoveMobj(check);\ + if (allow)\ + break; + + if (P_RandomChance(FRACUNIT/2)) // port priority 2? + { + for (k = 0; k < 9; k++) + { + dostuff(i+k) + dostuff(i-k) + dostuff(j+k) + dostuff(j-k) + } + } + else + { + for (k = 0; k < 9; k++) + { + dostuff(i-k) + dostuff(i+k) + dostuff(j-k) + dostuff(j+k) + } + } + actor->angle = testang; + +#undef dostuff + + mobjinfo[MT_NULL].spawnstate = oldspawnstate; + mobjinfo[MT_NULL].flags = oldflags; + mobjinfo[MT_NULL].radius = oldradius; + mobjinfo[MT_NULL].height = oldheight; + } an = actor->angle >> ANGLETOFINESHIFT; actor->momx = FixedMul(speed, FINECOSINE(an)); actor->momy = FixedMul(speed, FINESINE(an)); - dist = P_AproxDistance(dest->x - actor->x, dest->y - actor->y); dist = dist / speed; if (dist < 1) @@ -3450,11 +3533,13 @@ void A_Pain(mobj_t *actor) // // Description: Changes a dying object's flags to reflect its having fallen to the ground. // -// var1 = unused +// var1 = value to set repeat to if nonzero // var2 = unused // void A_Fall(mobj_t *actor) { + INT32 locvar1 = var1; + #ifdef HAVE_BLUA if (LUA_CallAction("A_Fall", actor)) return; @@ -3467,6 +3552,9 @@ void A_Fall(mobj_t *actor) // So change this if corpse objects // are meant to be obstacles. + + if (locvar1) + actor->extravalue2 = locvar1; } #define LIVESBOXDISPLAYPLAYER // Use displayplayer instead of closest player @@ -3862,6 +3950,72 @@ bossjustdie: else if (P_MobjWasRemoved(mo)) return; #endif + + // Spawn your junk + switch (mo->type) + { + default: + break; + case MT_EGGMOBILE: // twin laser pods + { + mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSEGLZ1); + + mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSEGLZ2); + } + break; + case MT_EGGMOBILE2: // twin tanks + spigot + { + mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSTANK1); + + mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSTANK2); + + mo2 = P_SpawnMobjFromMobj(mo, 0, 0, + mobjinfo[MT_EGGMOBILE2].height + (32<angle = mo->angle; + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + mo2->momz += mo->momz; + P_SetMobjState(mo2, S_BOSSSPIGOT); + } + break; + case MT_EGGMOBILE3: + { + mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK); + mo2->angle = mo->angle; + P_SetMobjState(mo2, S_BOSSSEBH1); + } + break; + } + + // now do another switch case for escaping switch (mo->type) { case MT_BLACKEGGMAN: @@ -3881,13 +4035,17 @@ bossjustdie: } case MT_FANG: { + if (mo->flags2 & MF2_SLIDEPUSH) + { + P_RemoveMobj(mo); + return; + } if (mo->tracer) { var1 = var2 = 0; A_Boss5Jump(mo); mo->momx = ((16 - 1)*mo->momx)/16; mo->momy = ((16 - 1)*mo->momy)/16; - if (!(mo->flags2 & MF2_AMBUSH)) { const fixed_t time = FixedHypot(mo->tracer->x - mo->x, mo->tracer->y - mo->y)/FixedHypot(mo->momx, mo->momy); const fixed_t speed = 64*FRACUNIT; @@ -3959,7 +4117,7 @@ bossjustdie: mo->movedir = 0; mo->extravalue1 = 35; mo->flags2 |= MF2_BOSSFLEE; - mo->momz = 2*mo->scale; + mo->momz = P_MobjFlip(mo)*2*mo->scale; if (mo->target) { @@ -3977,50 +4135,6 @@ bossjustdie: break; } } - - if (mo->type == MT_EGGMOBILE2) - { - mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->y + P_ReturnThrustY(mo, mo->angle - ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK1].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK1); // Right tank - mo2->angle = mo->angle; - mo2->destscale = mo->scale; - P_SetScale(mo2, mo2->destscale); - if (mo->eflags & MFE_VERTICALFLIP) - { - mo2->eflags |= MFE_VERTICALFLIP; - mo2->flags2 |= MF2_OBJECTFLIP; - } - P_InstaThrust(mo2, mo2->angle - ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale)); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - - mo2 = P_SpawnMobj(mo->x + P_ReturnThrustX(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->y + P_ReturnThrustY(mo, mo->angle + ANGLE_90, FixedMul(32*FRACUNIT, mo->scale)), - mo->z + mo->height/2 + ((mo->eflags & MFE_VERTICALFLIP)? FixedMul(8*FRACUNIT, mo->scale)-mobjinfo[MT_BOSSTANK2].height : -FixedMul(8*FRACUNIT, mo->scale)), MT_BOSSTANK2); // Left tank - mo2->angle = mo->angle; - mo2->destscale = mo->scale; - P_SetScale(mo2, mo2->destscale); - if (mo->eflags & MFE_VERTICALFLIP) - { - mo2->eflags |= MFE_VERTICALFLIP; - mo2->flags2 |= MF2_OBJECTFLIP; - } - P_InstaThrust(mo2, mo2->angle + ANGLE_90, FixedMul(4*FRACUNIT, mo2->scale)); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - - mo2 = P_SpawnMobj(mo->x, mo->y, - mo->z + ((mo->eflags & MFE_VERTICALFLIP)? mobjinfo[MT_BOSSSPIGOT].height-FixedMul(32*FRACUNIT,mo->scale): mo->height + FixedMul(32*FRACUNIT, mo->scale)), MT_BOSSSPIGOT); - mo2->angle = mo->angle; - mo2->destscale = mo->scale; - P_SetScale(mo2, mo2->destscale); - if (mo->eflags & MFE_VERTICALFLIP) - { - mo2->eflags |= MFE_VERTICALFLIP; - mo2->flags2 |= MF2_OBJECTFLIP; - } - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - return; - } } // Function: A_CustomPower @@ -4157,9 +4271,9 @@ void A_Invincibility(mobj_t *actor) { if (mariomode) G_GhostAddColor(GHC_INVINCIBLE); + P_PlayJingle(player, (mariomode) ? JT_MINV : JT_INV); strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14); S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]); - P_PlayJingle(player, (mariomode) ? JT_MINV : JT_INV); } } @@ -6363,6 +6477,7 @@ void A_MixUp(mobj_t *actor) INT32 starpostnum; tic_t starposttime; angle_t starpostangle; + fixed_t starpostscale; INT32 mflags2; @@ -6410,6 +6525,7 @@ void A_MixUp(mobj_t *actor) starposty = players[one].starposty; starpostz = players[one].starpostz; starpostangle = players[one].starpostangle; + starpostscale = players[one].starpostscale; starpostnum = players[one].starpostnum; starposttime = players[one].starposttime; @@ -6418,15 +6534,11 @@ void A_MixUp(mobj_t *actor) P_MixUp(players[one].mo, players[two].mo->x, players[two].mo->y, players[two].mo->z, players[two].mo->angle, players[two].starpostx, players[two].starposty, players[two].starpostz, players[two].starpostnum, players[two].starposttime, players[two].starpostangle, - players[two].mo->flags2); - - players[one].drawangle = players[two].drawangle; + players[two].starpostscale, players[two].drawangle, players[two].mo->flags2); P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz, starpostnum, starposttime, starpostangle, - mflags2); - - players[two].drawangle = drawangle; + starpostscale, drawangle, mflags2); //carry set after mixup. Stupid P_ResetPlayer() takes away some of the stuff we look for... //but not all of it! So we need to make sure they aren't set wrong or anything. @@ -6453,6 +6565,7 @@ void A_MixUp(mobj_t *actor) INT32 starpostnum[MAXPLAYERS]; tic_t starposttime[MAXPLAYERS]; angle_t starpostangle[MAXPLAYERS]; + fixed_t starpostscale[MAXPLAYERS]; INT32 flags2[MAXPLAYERS]; @@ -6490,6 +6603,7 @@ void A_MixUp(mobj_t *actor) starpostnum[counter] = players[i].starpostnum; starposttime[counter] = players[i].starposttime; starpostangle[counter] = players[i].starpostangle; + starpostscale[counter] = players[i].starpostscale; flags2[counter] = players[i].mo->flags2; @@ -6530,9 +6644,7 @@ void A_MixUp(mobj_t *actor) P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom][0], spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2], starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom], - flags2[teleportfrom]); - - players[i].drawangle = anglepos[teleportfrom][1]; + starpostscale[teleportfrom], anglepos[teleportfrom][1], flags2[teleportfrom]); //...carry after. same reasoning. players[i].powers[pw_carry] = transcarry[teleportfrom]; @@ -7978,6 +8090,57 @@ void A_Boss3Path(mobj_t *actor) } } +// Function: A_Boss3ShockThink +// +// Description: Inserts new interstitial shockwave objects when the space between others spreads too much. +// +// var1 = unused +// var2 = unused +// +void A_Boss3ShockThink(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss3ShockThink", actor)) + return; +#endif + + if (actor->momx || actor->momy) + actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy) + ANGLE_90; + + if (actor->hnext && !P_MobjWasRemoved(actor->hnext)) + { + mobj_t *snext = actor->hnext; + mobj_t *snew; + fixed_t x0, y0, x1, y1; + + // Break the link if movements are too different + if (FixedHypot(snext->momx - actor->momx, snext->momy - actor->momy) > 12*actor->scale) + { + P_SetTarget(&actor->hnext, NULL); + return; + } + + // Check distance between shockwave objects to determine whether interstitial ones should be spawned + x0 = actor->x; + y0 = actor->y; + x1 = snext->x; + y1 = snext->y; + if (FixedHypot(x1 - x0, y1 - y0) > 2*actor->radius) + { + snew = P_SpawnMobj((x0 + x1) >> 1, (y0 + y1) >> 1, (actor->z + snext->z) >> 1, actor->type); + snew->momx = (actor->momx + snext->momx) >> 1; + snew->momy = (actor->momy + snext->momy) >> 1; + snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? + snew->angle = (actor->angle + snext->angle) >> 1; + P_SetTarget(&snew->target, actor->target); + snew->fuse = actor->fuse; + + P_SetTarget(&actor->hnext, snew); + P_SetTarget(&snew->hnext, snext); + } + } +} + // Function: A_LinedefExecute // // Description: Object's location is used to set the calling sector. The tag used is var1. Optionally, if var2 is set, the actor's angle (multiplied by var2) is added to the tag number as well. @@ -8707,7 +8870,7 @@ void A_SetObjectFlags2(mobj_t *actor) // // var1: // 0 - Triple jet fume pattern -// 1 - Boss 3's propeller +// 1 - Unused (formerly Boss 3's propeller) // 2 - Metal Sonic jet fume // 3 - Boss 4 jet flame // var2 = unused @@ -8767,7 +8930,7 @@ void A_BossJetFume(mobj_t *actor) P_SetTarget(&actor->tracer, filler); } - else if (locvar1 == 1) // Boss 3 propeller + /*else if (locvar1 == 1) // Boss 3 propeller { fixed_t jetx, jety, jetz; @@ -8787,14 +8950,14 @@ void A_BossJetFume(mobj_t *actor) filler->angle = actor->angle - ANGLE_180; P_SetTarget(&actor->tracer, filler); - } + }*/ else if (locvar1 == 2) // Metal Sonic jet fumes { filler = P_SpawnMobj(actor->x, actor->y, actor->z, MT_JETFUME1); P_SetTarget(&filler->target, actor); filler->fuse = 59; P_SetTarget(&actor->tracer, filler); - filler->destscale = actor->scale/2; + filler->destscale = actor->scale/3; P_SetScale(filler, filler->destscale); if (actor->eflags & MFE_VERTICALFLIP) filler->flags2 |= MF2_OBJECTFLIP; @@ -12877,6 +13040,100 @@ void A_Boss5MakeItRain(mobj_t *actor) actor->extravalue2 = 0; } +// Function: A_Boss5MakeJunk +// +// Description: Make a mess. +// +// var1 = state # to set on MT_BROKENROBOT (if 0 do nothing, if -1 go to if colorized) +// var2 = mode (-1 = spin, 0 = make 1, & 1 make 8, & 2 alart mode) +// +void A_Boss5MakeJunk(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + mobj_t *broked; + angle_t ang; + INT32 i = ((locvar2 & 1) ? 8 : 1); +#ifdef HAVE_BLUA + if (LUA_CallAction("A_Boss5MakeJunk", actor)) + return; +#endif + + if (locvar1 < 0 && (actor->flags2 & MF2_SLIDEPUSH)) // this entire action is a hack, don't judge me + { + INT32 curextravalue2 = actor->extravalue2; + P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_PROJECTORLIGHT); + actor->z += P_MobjFlip(actor)*actor->height; + actor->flags |= MF_NOGRAVITY; + S_StartSound(actor, sfx_vwre); + actor->extravalue2 = 49; + P_SetMobjState(actor, -locvar1); + actor->extravalue2 = curextravalue2; + actor->angle -= FixedAngle((49*45)<extravalue2)/50; + if (trans > 9) + trans = 9; + if (trans < 0) + trans = 0; + if (!(actor->extravalue2 & 1)) + { + if (actor->extravalue2 > 10) + { + mobj_t *front = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_VWREF); + broked = P_SpawnMobjFromMobj(front, 0, 0, 0, MT_VWREB); + front->z = broked->z = front->z - broked->height; + P_SetObjectMomZ(front, (4<momz = front->momz; + broked->fuse = front->fuse = (actor->height+(2*front->height))/front->momz; + } + if (!(actor->colorized = !actor->colorized)) + actor->frame |= FF_FULLBRIGHT; + } + actor->angle += ANGLE_45; + actor->frame = (actor->frame & ~FF_TRANSMASK)|(trans<fuse = TICRATE; + else + broked->fuse = (((locvar2 & 1) ? 4 : 2)*TICRATE)/3; + broked->angle = ang; + P_InstaThrust(broked, ang, ((locvar2 & 2) ? 8 : 5)*actor->scale); + P_SetObjectMomZ(broked, (((locvar2) ? 4 : 0) + P_RandomRange(2, 5))< 0) + P_SetMobjState(broked, locvar1); + if (!P_MobjWasRemoved(broked)) + P_TeleportMove(broked, broked->x + broked->momx, broked->y + broked->momy, broked->z); + ang += ANGLE_45; + } + + if (locvar2 & 2) + { + broked = P_SpawnMobjFromMobj(actor, 0, 0, 64<fuse = states[S_FANG_INTRO12].tics+10; + P_SetMobjState(broked, S_ALART1); + } + else if (locvar2 & 1) + { + broked->z += broked->momz; + S_StartSound(actor, sfx_s3kccs); + actor->flags &= ~MF_NOCLIPTHING; + } + else + S_StartSound(actor, sfx_s3kd3s); +} + // Function: A_LookForBetter // // Description: A_Look, except it finds a better target in multiplayer, and doesn't lose the target in singleplayer. @@ -13003,11 +13260,14 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing) if (dustdevil->height - pos > thresh) { fixed_t dist = FixedHypot(thing->x - dustdevil->x, thing->y - dustdevil->y); - fixed_t dragamount = 6 * FRACUNIT; + fixed_t dragamount = player->speed; fixed_t x, y; if (player->powers[pw_nocontrol] == 0) + { + P_ResetPlayer(player); A_PlayActiveSound(dustdevil); + } player->powers[pw_nocontrol] = 2; player->drawangle += ANG20; P_SetPlayerMobjState(thing, S_PLAY_PAIN); diff --git a/src/p_inter.c b/src/p_inter.c index 404335657..f46d06cb3 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1438,6 +1438,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) players[i].starposty = player->mo->y>>FRACBITS; players[i].starpostz = special->z>>FRACBITS; players[i].starpostangle = special->angle; + players[i].starpostscale = player->mo->destscale; + if (special->flags2 & MF2_OBJECTFLIP) + { + players[i].starpostscale *= -1; + players[i].starpostz += special->height>>FRACBITS; + } players[i].starpostnum = special->health; if (cv_coopstarposts.value == 2 && (players[i].playerstate == PST_DEAD || players[i].spectator) && P_GetLives(&players[i])) @@ -1454,6 +1460,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->starposty = toucher->y>>FRACBITS; player->starpostz = special->z>>FRACBITS; player->starpostangle = special->angle; + player->starpostscale = player->mo->destscale; + if (special->flags2 & MF2_OBJECTFLIP) + { + player->starpostscale *= -1; + player->starpostz += special->height>>FRACBITS; + } player->starpostnum = special->health; S_StartSound(toucher, special->info->painsound); } @@ -1594,6 +1606,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Buenos Dias Mandy P_SetPlayerMobjState(toucher, S_PLAY_STUN); player->pflags &= ~PF_APPLYAUTOBRAKE; + P_ResetPlayer(player); player->drawangle = special->angle + ANGLE_180; P_InstaThrust(toucher, special->angle, FixedMul(3*special->info->speed, special->scale/2)); toucher->z += P_MobjFlip(toucher); @@ -1699,13 +1712,15 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; if (mariomode) return; + if (special->state-states != S_EXTRALARGEBUBBLE) + return; // Don't grab the bubble during its spawn animation else if (toucher->eflags & MFE_VERTICALFLIP) { - if (special->z+special->height < toucher->z + toucher->height / 3 - || special->z+special->height > toucher->z + (toucher->height*2/3)) + if (special->z+special->height < toucher->z + || special->z+special->height > toucher->z + (toucher->height*2/3)) return; // Only go in the mouth } - else if (special->z < toucher->z + toucher->height / 3 + else if (special->z < toucher->z || special->z > toucher->z + (toucher->height*2/3)) return; // Only go in the mouth @@ -2480,8 +2495,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget else if (P_IsLocalPlayer(target->player)) gameovermus = true; - if (gameovermus) - P_PlayJingle(target->player, JT_GOVER); // Yousa dead now, Okieday? Tails 03-14-2000 + if (gameovermus) // Yousa dead now, Okieday? Tails 03-14-2000 + S_ChangeMusicEx("_gover", 0, 0, 0, (2*MUSICRATE) - (MUSICRATE/25), 0); // 1.96 seconds + //P_PlayJingle(target->player, JT_GOVER); // can't be used because incompatible with track fadeout if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && numgameovers < maxgameovers) { @@ -2605,6 +2621,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget case MT_EGGMOBILE3: { + mobj_t *mo2; thinker_t *th; UINT32 i = 0; // to check how many clones we've removed @@ -2625,6 +2642,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget mo->scalespeed = (mo->scale - mo->destscale)/(2*TICRATE); mo->momz = mo->info->speed; mo->angle = FixedAngle((P_RandomKey(36)*10)<angle = mo->angle; + P_SetMobjState(mo2, S_BOSSSEBH2); + if (++i == 2) // we've already removed 2 of these, let's stop now break; else @@ -3397,7 +3419,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Spectator handling - if (netgame) + if (multiplayer) { if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator) return false; @@ -3429,7 +3451,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; // Make sure that boxes cannot be popped by enemies, red rings, etc. - if (target->flags & MF_MONITOR && ((!source || !source->player || source->player->bot) || (inflictor && !inflictor->player))) + if (target->flags & MF_MONITOR && ((!source || !source->player || source->player->bot) + || (inflictor && inflictor->type >= MT_REDRING && inflictor->type <= MT_GRENADERING))) return false; } @@ -3511,7 +3534,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return true; } - if (G_IsSpecialStage(gamemap)) + if (G_IsSpecialStage(gamemap) && !(damagetype & DMG_DEATHMASK)) { P_SpecialStageDamage(player, inflictor, source); return true; @@ -3535,10 +3558,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Instant-Death if (damagetype & DMG_DEATHMASK) - { P_KillPlayer(player, source, damage); - player->rings = player->spheres = 0; - } else if (metalrecording) { if (!inflictor) @@ -3573,7 +3593,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) return true; #endif - else if (player->powers[pw_shield] || player->bot) //If One-Hit Shield + else if (player->powers[pw_shield] || (player->bot && !ultimatemode)) //If One-Hit Shield { P_ShieldDamage(player, inflictor, source, damage, damagetype); damage = 0; diff --git a/src/p_local.h b/src/p_local.h index cad802910..02f497850 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -115,10 +115,10 @@ typedef struct camera_s extern camera_t camera, camera2; extern consvar_t cv_cam_dist, cv_cam_still, cv_cam_height; -extern consvar_t cv_cam_speed, cv_cam_rotate, cv_cam_rotspeed; +extern consvar_t cv_cam_speed, cv_cam_rotate, cv_cam_rotspeed, cv_cam_orbit, cv_cam_adjust; extern consvar_t cv_cam2_dist, cv_cam2_still, cv_cam2_height; -extern consvar_t cv_cam2_speed, cv_cam2_rotate, cv_cam2_rotspeed; +extern consvar_t cv_cam2_speed, cv_cam2_rotate, cv_cam2_rotspeed, cv_cam2_orbit, cv_cam2_adjust; extern fixed_t t_cam_dist, t_cam_height, t_cam_rotate; extern fixed_t t_cam2_dist, t_cam2_height, t_cam2_rotate; @@ -509,7 +509,7 @@ extern INT32 ceilmovesound; void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, INT16 starpostx, INT16 starposty, INT16 starpostz, INT32 starpostnum, tic_t starposttime, angle_t starpostangle, - INT32 flags2); + fixed_t starpostscale, angle_t drawangle, INT32 flags2); boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, boolean flash, boolean dontstopmove); boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state); boolean P_CheckMissileSpawn(mobj_t *th); diff --git a/src/p_map.c b/src/p_map.c index d17b5190c..a3b11e2dd 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -285,6 +285,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (spring->info->painchance != 2) { + if (object->player) + object->player->pflags &= ~PF_APPLYAUTOBRAKE; + if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA { object->momx = object->momy = 0; @@ -342,17 +345,14 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (horizspeed) { object->player->drawangle = spring->angle; - if (vertispeed || (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0)) - { - object->angle = spring->angle; + object->angle = spring->angle; - if (!demoplayback || P_AnalogMove(object->player)) - { - if (object->player == &players[consoleplayer]) - localangle = spring->angle; - else if (object->player == &players[secondarydisplayplayer]) - localangle2 = spring->angle; - } + if (!demoplayback || P_AnalogMove(object->player)) + { + if (object->player == &players[consoleplayer]) + localangle = spring->angle; + else if (object->player == &players[secondarydisplayplayer]) + localangle2 = spring->angle; } } @@ -782,7 +782,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) + if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return true; // Don't collide with your buddies while NiGHTS-flying. @@ -1122,7 +1122,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (tmthing->flags & MF_SHOOTABLE && thing->health > 0) { - UINT8 damagetype = (thing->info->mass & 0xFF); + UINT32 damagetype = (thing->info->mass & 0xFF); if (!damagetype && thing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8))) @@ -1139,7 +1139,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (thing->flags & MF_SHOOTABLE && tmthing->health > 0) { - UINT8 damagetype = (tmthing->info->mass & 0xFF); + UINT32 damagetype = (tmthing->info->mass & 0xFF); if (!damagetype && tmthing->flags & MF_FIRE) // BURN! damagetype = DMG_FIRE; if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && (damagetype = (tmthing->info->mass>>8))) @@ -2984,11 +2984,8 @@ static boolean P_ThingHeightClip(mobj_t *thing) thing->z = thing->ceilingz - thing->height; } - if (thing->z != oldz) - { - if (thing->player) - P_PlayerHitFloor(thing->player, !onfloor); - } + if (P_MobjFlip(thing)*(thing->z - oldz) > 0 && thing->player) + P_PlayerHitFloor(thing->player, !onfloor); // debug: be sure it falls to the floor thing->eflags &= ~MFE_ONGROUND; @@ -3302,7 +3299,7 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle) && glidesector->sector->ceilingpic == skyflatnum) return false; - if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < ceilingz) + if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < floorz) || (player->mo->z >= ceilingz)) floorclimb = true; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 107f9f0f7..ce65ed8df 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2942,7 +2942,7 @@ static void P_PlayerZMovement(mobj_t *mo) } // Get up if you fell. if (mo->player->panim == PA_PAIN) - P_SetPlayerMobjState(mo, S_PLAY_STND); + P_SetPlayerMobjState(mo, S_PLAY_WALK); #ifdef ESLOPE if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) { @@ -3754,7 +3754,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled if (thiscam->momx || thiscam->momy) { - if (!P_TryCameraMove(thiscam->x + thiscam->momx, thiscam->y + thiscam->momy, thiscam)) + if (!P_TryCameraMove(thiscam->x + thiscam->momx, thiscam->y + thiscam->momy, thiscam)) // Thanks for the greatly improved camera, Lach -- Sev { // Never fails for 2D mode. mobj_t dummy; dummy.thinker.function.acp1 = (actionf_p1)P_MobjThinker; @@ -3764,9 +3764,22 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled dummy.z = thiscam->z; dummy.height = thiscam->height; if (!resetcalled && !(player->pflags & PF_NOCLIP) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. + { P_ResetCamera(player, thiscam); + resetcalled = true; + } else + { + fixed_t camspeed = P_AproxDistance(thiscam->momx, thiscam->momy); + P_SlideCameraMove(thiscam); + + if (!resetcalled && P_AproxDistance(thiscam->momx, thiscam->momy) == camspeed) + { + P_ResetCamera(player, thiscam); + resetcalled = true; + } + } if (resetcalled) // Okay this means the camera is fully reset. return true; } @@ -3975,6 +3988,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) } else { +#if 0 // i don't know why this is here, it's causing a few undesired state glitches, and disabling it doesn't appear to negatively affect the game, but i don't want it gone permanently just in case some obscure bug crops up if (!(mobj->player->powers[pw_carry] == CR_NIGHTSMODE)) // used for drilling mobj->player->pflags &= ~PF_STARTJUMP; mobj->player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); @@ -3984,6 +3998,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) mobj->player->powers[pw_tailsfly] = 0; P_SetPlayerMobjState(mobj, S_PLAY_WALK); } +#endif mobj->eflags &= ~MFE_JUSTHITFLOOR; } @@ -4392,12 +4407,6 @@ static void P_Boss3Thinker(mobj_t *mobj) if (mobj->flags2 & MF2_FRET) mobj->movedir = 1; - if (!mobj->tracer) - { - var1 = 1; - A_BossJetFume(mobj); - } - if (mobj->health <= 0) return; /* @@ -4526,7 +4535,7 @@ static void P_Boss3Thinker(mobj_t *mobj) if (mobj->health <= mobj->info->damage) // pinch phase mobj->movecount--; // limited number of shots before diving again if (mobj->movecount) - P_SetMobjState(mobj, mobj->info->missilestate); + P_SetMobjState(mobj, mobj->info->missilestate+1); } } else if (mobj->threshold >= 0) // Traveling mode @@ -4609,22 +4618,46 @@ static void P_Boss3Thinker(mobj_t *mobj) if (!mobj->movefactor) // to firing mode { - UINT8 i; - angle_t ang = 0; + UINT8 i, numtospawn = 24; + angle_t ang = 0, interval = FixedAngle((360 << FRACBITS) / numtospawn); + mobj_t *shock, *sfirst, *sprev = NULL; mobj->movecount = mobj->health+1; mobj->movefactor = -512*FRACUNIT; // shock the water! - for (i = 0; i < 64; i++) + for (i = 0; i < numtospawn; i++) { - mobj_t *shock = P_SpawnMobjFromMobj(mobj, 0, 0, 4*FRACUNIT, MT_SHOCK); + shock = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SHOCKWAVE); P_SetTarget(&shock->target, mobj); - P_InstaThrust(shock, ang, shock->info->speed); - P_CheckMissileSpawn(shock); - ang += (ANGLE_MAX/64); + shock->fuse = shock->info->painchance; + + if (i % 2 == 0) + P_SetMobjState(shock, shock->state->nextstate); + + if (!sprev) + sfirst = shock; + else + { + if (i == numtospawn - 1) + P_SetTarget(&shock->hnext, sfirst); + P_SetTarget(&sprev->hnext, shock); + } + + P_Thrust(shock, ang, shock->info->speed); + ang += interval; + sprev = shock; + } + S_StartSound(mobj, shock->info->seesound); + + // look for a new target + P_BossTargetPlayer(mobj, false); + + if (mobj->target && mobj->target->player) + { + A_FaceTarget(mobj); + P_SetMobjState(mobj, mobj->info->missilestate); } - S_StartSound(mobj, sfx_fizzle); } else if (mobj->flags2 & (MF2_STRONGBOX|MF2_CLASSICPUSH)) // just hit the bottom of your tube { @@ -5058,6 +5091,24 @@ static void P_Boss5Thinker(mobj_t *mobj) { if (!mobj->health) { + if (mobj->fuse) + { + if (mobj->flags2 & MF2_SLIDEPUSH) + { + INT32 trans = 10-((10*mobj->fuse)/70); + if (trans > 9) + trans = 9; + if (trans < 0) + trans = 0; + mobj->frame = (mobj->frame & ~FF_TRANSMASK)|(trans<fuse & 1)) + { + mobj->colorized = !mobj->colorized; + mobj->frame ^= FF_FULLBRIGHT; + } + } + return; + } if (mobj->state == &states[mobj->info->xdeathstate]) mobj->momz -= (2*FRACUNIT)/3; else if (mobj->tracer && P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y) < 2*mobj->radius) @@ -5560,8 +5611,7 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); P_SetScale(mobj->tracer, mobj->tracer->destscale); } - else - mobj->tracer->frame &= ~FF_TRANSMASK; // this causes a flicker but honestly i like it this way + P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2); mobj->tracer->momx = mobj->momx; mobj->tracer->momy = mobj->momy; @@ -5678,12 +5728,12 @@ static void P_Boss9Thinker(mobj_t *mobj) if (mobj->health > mobj->info->damage) { - P_SetScale(missile, FRACUNIT/2); + P_SetScale(missile, FRACUNIT/3); missile->color = SKINCOLOR_GOLD; // sonic cd electric power } else { - P_SetScale(missile, FRACUNIT/4); + P_SetScale(missile, FRACUNIT/5); missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power } missile->destscale = missile->scale*2; @@ -5973,9 +6023,7 @@ static void P_Boss9Thinker(mobj_t *mobj) P_SetTarget(&mobj->tracer, shield); P_SetTarget(&shield->target, mobj); shield->height -= 20*FRACUNIT; // different offset... - shield->color = SKINCOLOR_MAGENTA; - shield->colorized = true; - P_SetMobjState(shield, S_FIRS1); + P_SetMobjState(shield, S_MSSHIELD_F2); //P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); -- why does this happen twice? see case 2... } mobj->fuse = 4*TICRATE; @@ -7136,9 +7184,7 @@ void P_MobjThinker(mobj_t *mobj) switch (mobj->type) { - case MT_BOSSTANK1: - case MT_BOSSTANK2: - case MT_BOSSSPIGOT: + case MT_BOSSJUNK: mobj->flags2 ^= MF2_DONTDRAW; break; case MT_MACEPOINT: @@ -7321,7 +7367,8 @@ void P_MobjThinker(mobj_t *mobj) case MT_FLAMEAURA_ORB: if (!(mobj->flags2 & MF2_SHIELD)) return; - mobj->angle = mobj->target->angle; // implicitly okay because of P_AddShield + if ((statenum_t)(mobj->state-states) < mobj->info->painstate) + mobj->angle = mobj->target->angle; // implicitly okay because of P_AddShield if (mobj->tracer /* && mobj->target -- the following is implicit by P_AddShield && mobj->target->player @@ -7659,6 +7706,17 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->movedir) mobj->angle += mobj->movedir; break; + case MT_VWREF: + case MT_VWREB: + { + INT32 strength; + ++mobj->movedir; + mobj->frame &= ~FF_TRANSMASK; + strength = min(mobj->fuse, mobj->movedir)*3; + if (strength < 10) + mobj->frame |= ((10-strength)<<(FF_TRANSSHIFT)); + } + /* FALLTHRU */ default: if (mobj->fuse) { // Scenery object fuse! Very basic! @@ -7724,12 +7782,22 @@ void P_MobjThinker(mobj_t *mobj) switch (mobj->type) { case MT_EGGMOBILE: - if (mobj->health < mobj->info->damage+1 && leveltime & 1 && mobj->health > 0) - P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMOKE); + if (mobj->health < mobj->info->damage+1 && leveltime & 2) + { + fixed_t rad = mobj->radius>>FRACBITS; + fixed_t hei = mobj->height>>FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad)<momz += mobj->momz; + } if (mobj->flags2 & MF2_SKULLFLY) #if 1 P_SpawnGhostMobj(mobj); -#else +#else // all the way back from final demo... MT_THOK isn't even the same size anymore! { mobj_t *spawnmobj; spawnmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->painchance); @@ -7740,12 +7808,48 @@ void P_MobjThinker(mobj_t *mobj) P_Boss1Thinker(mobj); break; case MT_EGGMOBILE2: + if (mobj->health < mobj->info->damage+1 && leveltime & 2) + { + fixed_t rad = mobj->radius>>FRACBITS; + fixed_t hei = mobj->height>>FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad)<momz += mobj->momz; + } P_Boss2Thinker(mobj); break; case MT_EGGMOBILE3: + if (mobj->health < mobj->info->damage+1 && leveltime & 2) + { + fixed_t rad = mobj->radius>>FRACBITS; + fixed_t hei = mobj->height>>FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad)<momz += mobj->momz; + } P_Boss3Thinker(mobj); break; case MT_EGGMOBILE4: + if (mobj->health < mobj->info->damage+1 && leveltime & 2) + { + fixed_t rad = mobj->radius>>FRACBITS; + fixed_t hei = mobj->height>>FRACBITS; + mobj_t *particle = P_SpawnMobjFromMobj(mobj, + P_RandomRange(rad, -rad)<momz += mobj->momz; + } P_Boss4Thinker(mobj); break; case MT_FANG: @@ -8361,30 +8465,6 @@ void P_MobjThinker(mobj_t *mobj) mobj->fuse++; } break; - case MT_PROPELLER: - { - fixed_t jetx, jety; - - if (!mobj->target // if you have no target - || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; - } - - jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale)); - jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale)); - - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - mobj->z = mobj->target->z + FixedMul(17*FRACUNIT, mobj->target->scale); - mobj->angle = mobj->target->angle - ANGLE_180; - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - break; case MT_JETFLAME: { if (!mobj->target // if you have no target @@ -8448,6 +8528,17 @@ void P_MobjThinker(mobj_t *mobj) } else { + + fixed_t basex = mobj->cusval, basey = mobj->cvmem; + + if (mobj->spawnpoint && mobj->spawnpoint->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) + { + angle_t sideang = mobj->movedir + ((mobj->spawnpoint->options & MTF_AMBUSH) ? ANGLE_90 : -ANGLE_90); + fixed_t oscillate = FixedMul(FINESINE(((leveltime*ANG1)>>(ANGLETOFINESHIFT+2)) & FINEMASK), 250*mobj->scale); + basex += P_ReturnThrustX(mobj, sideang, oscillate); + basey += P_ReturnThrustY(mobj, sideang, oscillate); + } + mobj->z = mobj->threshold + FixedMul(FINESINE(((leveltime + mobj->movecount)*ANG2>>(ANGLETOFINESHIFT-2)) & FINEMASK), 8*mobj->scale); if (mobj->state != &states[mobj->info->meleestate]) { @@ -8476,8 +8567,8 @@ void P_MobjThinker(mobj_t *mobj) if (players[i].mo->z + players[i].mo->height < mobj->z - 8*mobj->scale) continue; compdist = P_AproxDistance( - players[i].mo->x + players[i].mo->momx - mobj->cusval, - players[i].mo->y + players[i].mo->momy - mobj->cvmem); + players[i].mo->x + players[i].mo->momx - basex, + players[i].mo->y + players[i].mo->momy - basey); if (compdist >= dist) continue; dist = compdist; @@ -8491,14 +8582,14 @@ void P_MobjThinker(mobj_t *mobj) mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); if (P_AproxDistance( - mobj->x - mobj->cusval, - mobj->y - mobj->cvmem) + mobj->x - basex, + mobj->y - basey) < mobj->scale) S_StartSound(mobj, mobj->info->seesound); P_TeleportMove(mobj, - (15*(mobj->x>>4)) + (mobj->cusval>>4) + P_ReturnThrustX(mobj, mobj->angle, SPECTATORRADIUS>>4), - (15*(mobj->y>>4)) + (mobj->cvmem>>4) + P_ReturnThrustY(mobj, mobj->angle, SPECTATORRADIUS>>4), + (15*(mobj->x>>4)) + (basex>>4) + P_ReturnThrustX(mobj, mobj->angle, SPECTATORRADIUS>>4), + (15*(mobj->y>>4)) + (basey>>4) + P_ReturnThrustY(mobj, mobj->angle, SPECTATORRADIUS>>4), mobj->z); } else @@ -8521,18 +8612,12 @@ void P_MobjThinker(mobj_t *mobj) if (!didmove) { - if (P_AproxDistance( - mobj->x - mobj->cusval, - mobj->y - mobj->cvmem) - < mobj->scale) - P_TeleportMove(mobj, - mobj->cusval, - mobj->cvmem, - mobj->z); + if (P_AproxDistance(mobj->x - basex, mobj->y - basey) < mobj->scale) + P_TeleportMove(mobj, basex, basey, mobj->z); else P_TeleportMove(mobj, - (15*(mobj->x>>4)) + (mobj->cusval>>4), - (15*(mobj->y>>4)) + (mobj->cvmem>>4), + (15*(mobj->x>>4)) + (basex>>4), + (15*(mobj->y>>4)) + (basey>>4), mobj->z); } } @@ -9242,9 +9327,12 @@ void P_MobjThinker(mobj_t *mobj) { if (mobj->state->action.acp1 == (actionf_p1)A_Boss1Laser) { - var1 = mobj->state->var1; - var2 = mobj->state->var2; - mobj->state->action.acp1(mobj); + if (mobj->state->tics > 1) + { + var1 = mobj->state->var1; + var2 = mobj->state->var2 & 65535; + mobj->state->action.acp1(mobj); + } } else if (leveltime & 1) // Fire mode { @@ -9410,6 +9498,18 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s } P_RemoveMobj(mobj); return; + case MT_FANG: + if (mobj->flags2 & MF2_SLIDEPUSH) + { + var1 = 0; + var2 = 0; + A_BossDeath(mobj); + return; + } + P_SetMobjState(mobj, mobj->state->nextstate); + if (P_MobjWasRemoved(mobj)) + return; + break; case MT_METALSONIC_BATTLE: break; // don't remove case MT_SPIKE: @@ -10065,7 +10165,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; } - if (sc != -1) + if (sc != -1 && !(mobj->flags2 & MF2_SLIDEPUSH)) { UINT8 i; for (i = 0; i < MAXPLAYERS; i++) @@ -10077,6 +10177,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { mobj->color = SKINCOLOR_SILVER; mobj->colorized = true; + mobj->flags2 |= MF2_SLIDEPUSH; break; } } @@ -10648,7 +10749,7 @@ void P_SpawnPlayer(INT32 playernum) mobj_t *mobj; if (p->playerstate == PST_REBORN) - G_PlayerReborn(playernum); + G_PlayerReborn(playernum, false); // spawn as spectator determination if (!G_GametypeHasSpectators()) @@ -10656,9 +10757,9 @@ void P_SpawnPlayer(INT32 playernum) p->spectator = p->outofcoop = (((multiplayer || netgame) && gametype == GT_COOP) // only question status in coop && ((leveltime > 0 - && ((G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) // late join special stage + && ((G_IsSpecialStage(gamemap)) // late join special stage || (cv_coopstarposts.value == 2 && (p->jointime < 1 || p->outofcoop)))) // late join or die in new coop - || (((cv_cooplives.value == 1) || !P_GetLives(p)) && p->lives <= 0))); // game over and can't redistribute lives + || (!P_GetLives(p) && p->lives <= 0))); // game over and can't redistribute lives } else { @@ -10725,7 +10826,6 @@ void P_SpawnPlayer(INT32 playernum) P_SetupStateAnimation(mobj, mobj->state); mobj->health = 1; - p->rings = p->spheres = 0; p->playerstate = PST_LIVE; p->bonustime = false; @@ -10782,10 +10882,6 @@ void P_AfterPlayerSpawn(INT32 playernum) else p->viewz = p->mo->z + p->viewheight; - if (p->powers[pw_carry] != CR_NIGHTSMODE) - P_SetPlayerMobjState(p->mo, S_PLAY_STND); - p->pflags &= ~PF_SPINNING; - if (playernum == consoleplayer) { // wake up the status bar @@ -10870,6 +10966,8 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) mobj->eflags |= MFE_VERTICALFLIP; mobj->flags2 |= MF2_OBJECTFLIP; } + if (mthing->options & MTF_AMBUSH) + P_SetPlayerMobjState(mobj, S_PLAY_FALL); } else z = floor; @@ -10888,7 +10986,12 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) P_SetThingPosition(mobj); mobj->z = z; - if (mobj->z == mobj->floorz) + if (mobj->flags2 & MF2_OBJECTFLIP) + { + if (mobj->z + mobj->height == mobj->ceilingz) + mobj->eflags |= MFE_ONGROUND; + } + else if (mobj->z == mobj->floorz) mobj->eflags |= MFE_ONGROUND; mobj->angle = angle; @@ -10924,17 +11027,29 @@ void P_MovePlayerToStarpost(INT32 playernum) sector->ceilingheight; z = p->starpostz << FRACBITS; - if (z < floor) + + P_SetScale(mobj, (mobj->destscale = abs(p->starpostscale))); + + if (p->starpostscale < 0) + { + mobj->flags2 |= MF2_OBJECTFLIP; + if (z >= ceiling) + { + mobj->eflags |= MFE_ONGROUND; + z = ceiling; + } + z -= mobj->height; + } + else if (z <= floor) + { + mobj->eflags |= MFE_ONGROUND; z = floor; - else if (z > ceiling - mobjinfo[MT_PLAYER].height) - z = ceiling - mobjinfo[MT_PLAYER].height; + } mobj->floorz = floor; mobj->ceilingz = ceiling; mobj->z = z; - if (mobj->z == mobj->floorz) - mobj->eflags |= MFE_ONGROUND; mobj->angle = p->starpostangle; @@ -11409,6 +11524,16 @@ You should think about modifying the deathmatch starts to take full advantage of else mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS; break; + case MT_FANG: + case MT_METALSONIC_RACE: + case MT_METALSONIC_BATTLE: + if (mthing->options & MTF_EXTRA) + { + mobj->color = SKINCOLOR_SILVER; + mobj->colorized = true; + mobj->flags2 |= MF2_SLIDEPUSH; + } + break; case MT_BALLOON: if (mthing->angle > 0) mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1; @@ -12093,8 +12218,8 @@ ML_EFFECT5 : Don't stop thinking when too far away case MT_BIGFERN: { angle_t angle = FixedAngle(mthing->angle << FRACBITS); - UINT8 i; - for (i = 0; i < 8; i++) + UINT8 j; + for (j = 0; j < 8; j++) { angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; fixed_t xoffs = FINECOSINE(fa); diff --git a/src/p_saveg.c b/src/p_saveg.c index ea998b445..69c942236 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -125,6 +125,10 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].currentweapon); WRITEINT32(save_p, players[i].ringweapons); + WRITEUINT16(save_p, players[i].ammoremoval); + WRITEUINT32(save_p, players[i].ammoremovaltimer); + WRITEINT32(save_p, players[i].ammoremovaltimer); + for (j = 0; j < NUMPOWERS; j++) WRITEUINT16(save_p, players[i].powers[j]); @@ -185,6 +189,7 @@ static void P_NetArchivePlayers(void) WRITEINT16(save_p, players[i].starpostz); WRITEINT32(save_p, players[i].starpostnum); WRITEANGLE(save_p, players[i].starpostangle); + WRITEFIXED(save_p, players[i].starpostscale); WRITEANGLE(save_p, players[i].angle_pos); WRITEANGLE(save_p, players[i].old_angle_pos); @@ -329,6 +334,10 @@ static void P_NetUnArchivePlayers(void) players[i].currentweapon = READINT32(save_p); players[i].ringweapons = READINT32(save_p); + players[i].ammoremoval = READUINT16(save_p); + players[i].ammoremovaltimer = READUINT32(save_p); + players[i].ammoremovalweapon = READINT32(save_p); + for (j = 0; j < NUMPOWERS; j++) players[i].powers[j] = READUINT16(save_p); @@ -389,6 +398,7 @@ static void P_NetUnArchivePlayers(void) players[i].starpostz = READINT16(save_p); players[i].starpostnum = READINT32(save_p); players[i].starpostangle = READANGLE(save_p); + players[i].starpostscale = READFIXED(save_p); players[i].angle_pos = READANGLE(save_p); players[i].old_angle_pos = READANGLE(save_p); @@ -4109,12 +4119,54 @@ static inline boolean P_NetUnArchiveMisc(void) return true; } +static inline void P_ArchiveLuabanksAndConsistency(void) +{ + UINT8 i, banksinuse = NUM_LUABANKS; + + while (banksinuse && !luabanks[banksinuse-1]) + banksinuse--; // get the last used bank + + if (banksinuse) + { + WRITEUINT8(save_p, 0xb7); // luabanks marker + WRITEUINT8(save_p, banksinuse); + for (i = 0; i < banksinuse; i++) + WRITEINT32(save_p, luabanks[i]); + } + + WRITEUINT8(save_p, 0x1d); // consistency marker +} + +static inline boolean P_UnArchiveLuabanksAndConsistency(void) +{ + switch (READUINT8(save_p)) + { + case 0xb7: + { + UINT8 i, banksinuse = READUINT8(save_p); + if (banksinuse > NUM_LUABANKS) + return false; + for (i = 0; i < banksinuse; i++) + luabanks[i] = READINT32(save_p); + if (READUINT8(save_p) != 0x1d) + return false; + } + case 0x1d: + break; + default: + return false; + } + + return true; +} + void P_SaveGame(void) { P_ArchiveMisc(); P_ArchivePlayer(); - WRITEUINT8(save_p, 0x1d); // consistency marker + // yes, even in non HAVE_BLUA + P_ArchiveLuabanksAndConsistency(); } void P_SaveNetGame(void) @@ -4153,7 +4205,7 @@ void P_SaveNetGame(void) LUA_Archive(); #endif - WRITEUINT8(save_p, 0x1d); // consistency marker + P_ArchiveLuabanksAndConsistency(); } boolean P_LoadGame(INT16 mapoverride) @@ -4165,8 +4217,7 @@ boolean P_LoadGame(INT16 mapoverride) P_UnArchiveSPGame(mapoverride); P_UnArchivePlayer(); - // Savegame end marker - if (READUINT8(save_p) != 0x1d) + if (!P_UnArchiveLuabanksAndConsistency()) return false; // Only do this after confirming savegame is ok @@ -4207,5 +4258,5 @@ boolean P_LoadNetGame(void) // precipitation when loading a netgame save. Instead, precip has to be spawned here. // This is done in P_NetUnArchiveSpecials now. - return READUINT8(save_p) == 0x1d; + return P_UnArchiveLuabanksAndConsistency(); } diff --git a/src/p_setup.c b/src/p_setup.c index d0cd14b22..c83c8cd5c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -221,6 +221,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->muspostbosstrack = 0; mapheaderinfo[num]->muspostbosspos = 0; mapheaderinfo[num]->muspostbossfadein = 0; + mapheaderinfo[num]->musforcereset = -1; mapheaderinfo[num]->forcecharacter[0] = '\0'; mapheaderinfo[num]->weather = 0; mapheaderinfo[num]->skynum = 1; @@ -573,6 +574,11 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat) // store the flat lump number levelflat->lumpnum = R_GetFlatNumForName(flatname); + levelflat->texturenum = R_CheckTextureNumForName(flatname); + levelflat->lasttexturenum = levelflat->texturenum; + + levelflat->baselumpnum = LUMPERROR; + levelflat->basetexturenum = -1; #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); @@ -617,6 +623,11 @@ INT32 P_AddLevelFlatRuntime(const char *flatname) // store the flat lump number levelflat->lumpnum = R_GetFlatNumForName(flatname); + levelflat->texturenum = R_CheckTextureNumForName(flatname); + levelflat->lasttexturenum = levelflat->texturenum; + + levelflat->baselumpnum = LUMPERROR; + levelflat->basetexturenum = -1; #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); @@ -1480,6 +1491,7 @@ static void P_LoadRawSideDefs2(void *data) case 425: // Calls P_SetMobjState on calling mobj case 434: // Custom Power case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors + case 461: // Spawns an object on the map based on texture offsets { char process[8*3+1]; memset(process,0,8*3+1); @@ -2234,6 +2246,8 @@ static void P_LevelInitStuff(void) for (i = 0; i < MAXPLAYERS; i++) { + G_PlayerReborn(i, true); + if (canresetlives && (netgame || multiplayer) && playeringame[i] && (gametype == GT_COMPETITION || players[i].lives <= 0)) { // In Co-Op, replenish a user's lives if they are depleted. @@ -2241,41 +2255,18 @@ static void P_LevelInitStuff(void) } // obliteration station... - players[i].rings = players[i].spheres =\ - players[i].xtralife = players[i].deadtimer =\ - players[i].numboxes = players[i].totalring =\ - players[i].laps = players[i].aiming =\ - players[i].losstime = players[i].timeshit =\ - players[i].marescore = players[i].lastmarescore =\ - players[i].maxlink = players[i].startedtime =\ - players[i].finishedtime = players[i].finishedspheres =\ - players[i].finishedrings = players[i].lastmare =\ - players[i].lastmarelap = players[i].lastmarebonuslap =\ - players[i].totalmarelap = players[i].totalmarebonuslap =\ - players[i].marebegunat = players[i].textvar =\ - players[i].texttimer = players[i].linkcount =\ - players[i].linktimer = players[i].flyangle =\ - players[i].anotherflyangle = players[i].nightstime =\ - players[i].oldscale = players[i].mare = players[i].marelap =\ - players[i].marebonuslap = players[i].lapbegunat =\ - players[i].lapstartedtime = players[i].totalmarescore =\ - players[i].realtime = players[i].exiting = 0; + players[i].numboxes = players[i].totalring =\ + players[i].laps = players[i].marescore = players[i].lastmarescore =\ + players[i].mare = players[i].exiting = 0; - // i guess this could be part of the above but i feel mildly uncomfortable implicitly casting - players[i].gotcontinue = false; - - // aha, the first evidence this shouldn't be a memset! players[i].drillmeter = 40*20; - P_ResetPlayer(&players[i]); // hit these too - players[i].pflags &= ~(PF_GAMETYPEOVER|PF_TRANSFERTOCLOSEST); - - // unset ALL the pointers. P_SetTarget isn't needed here because if this - // function is being called we're just going to clobber the data anyways - players[i].mo = players[i].followmobj = players[i].awayviewmobj =\ - players[i].capsule = players[i].axis1 = players[i].axis2 = players[i].drone = NULL; + players[i].pflags &= ~(PF_GAMETYPEOVER); } + + if (botingame) + CV_SetValue(&cv_analog2, true); } // @@ -2692,7 +2683,7 @@ boolean P_SetupLevel(boolean skipprecip) S_StartSound(NULL, sfx_s3kaf); // Fade music! Time it to S3KAF: 0.25 seconds is snappy. - if (cv_resetmusic.value || + if (RESETMUSIC || strnicmp(S_MusicName(), (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7)) S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE) @@ -2725,7 +2716,7 @@ boolean P_SetupLevel(boolean skipprecip) // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!titlemapinaction && (cv_resetmusic.value || + if (!titlemapinaction && (RESETMUSIC || strnicmp(S_MusicName(), (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) S_FadeMusic(0, FixedMul( diff --git a/src/p_setup.h b/src/p_setup.h index 7e8a5d7e6..7e3a149eb 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -37,12 +37,19 @@ typedef struct { char name[9]; // resource name from wad lumpnum_t lumpnum; // lump number of the flat + INT32 texturenum, lasttexturenum; // texture number of the flat + UINT16 width, height; + fixed_t topoffset, leftoffset; // for flat animation lumpnum_t baselumpnum; + INT32 basetexturenum; INT32 animseq; // start pos. in the anim sequence INT32 numpics; INT32 speed; + + // for patchflats + UINT8 *flatpatch; } levelflat_t; extern size_t numlevelflats; diff --git a/src/p_spec.c b/src/p_spec.c index 37a1652f0..256ca3453 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -205,8 +205,8 @@ void P_InitPicAnims(void) if ((W_CheckNumForName(animdefs[i].startname)) == LUMPERROR) continue; - lastanim->picnum = R_FlatNumForName(animdefs[i].endname); - lastanim->basepic = R_FlatNumForName(animdefs[i].startname); + lastanim->picnum = R_GetFlatNumForName(animdefs[i].endname); + lastanim->basepic = R_GetFlatNumForName(animdefs[i].startname); } lastanim->istexture = animdefs[i].istexture; @@ -464,7 +464,19 @@ static inline void P_FindAnimatedFlat(INT32 animnum) for (i = 0; i < numlevelflats; i++, foundflats++) { // is that levelflat from the flat anim sequence ? - if (foundflats->lumpnum >= startflatnum && foundflats->lumpnum <= endflatnum) + if ((anims[animnum].istexture) && (foundflats->texturenum != 0 && foundflats->texturenum != -1) + && ((UINT16)foundflats->texturenum >= startflatnum && (UINT16)foundflats->texturenum <= endflatnum)) + { + foundflats->basetexturenum = startflatnum; + foundflats->animseq = foundflats->texturenum - startflatnum; + foundflats->numpics = endflatnum - startflatnum + 1; + foundflats->speed = anims[animnum].speed; + + CONS_Debug(DBG_SETUP, "animflat: #%03d name:%.8s animseq:%d numpics:%d speed:%d\n", + atoi(sizeu1(i)), foundflats->name, foundflats->animseq, + foundflats->numpics,foundflats->speed); + } + else if (foundflats->lumpnum >= startflatnum && foundflats->lumpnum <= endflatnum) { foundflats->baselumpnum = startflatnum; foundflats->animseq = foundflats->lumpnum - startflatnum; @@ -488,10 +500,7 @@ void P_SetupLevelFlatAnims(void) // the original game flat anim sequences for (i = 0; anims[i].istexture != -1; i++) - { - if (!anims[i].istexture) - P_FindAnimatedFlat(i); - } + P_FindAnimatedFlat(i); } // @@ -3953,6 +3962,39 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; + case 461: // Spawns an object on the map based on texture offsets + { + const mobjtype_t type = (mobjtype_t)(sides[line->sidenum[0]].toptexture); + mobj_t *mobj; + + fixed_t x, y, z; + x = sides[line->sidenum[0]].textureoffset; + y = sides[line->sidenum[0]].rowoffset; + z = line->frontsector->floorheight; + + if (line->flags & ML_NOCLIMB) // If noclimb is set, spawn randomly within a range + { + if (line->sidenum[1] != 0xffff) // Make sure the linedef has a back side + { + x = P_RandomRange(sides[line->sidenum[0]].textureoffset>>FRACBITS, sides[line->sidenum[1]].textureoffset>>FRACBITS)<sidenum[0]].rowoffset>>FRACBITS, sides[line->sidenum[1]].rowoffset>>FRACBITS)<frontsector->floorheight>>FRACBITS, line->frontsector->ceilingheight>>FRACBITS)<special); + break; + } + } + + mobj = P_SpawnMobj(x, y, z, type); + if (mobj) + CONS_Debug(DBG_GAMELOGIC, "Linedef Type %d - Spawn Object: %d spawned at (%d, %d, %d)\n", line->special, mobj->type, mobj->x>>FRACBITS, mobj->y>>FRACBITS, mobj->z>>FRACBITS); //TODO: Convert mobj->type to a string somehow. + else + CONS_Alert(CONS_ERROR,"Linedef Type %d - Spawn Object: Object did not spawn!\n", line->special); + } + break; + #ifdef POLYOBJECTS case 480: // Polyobj_DoorSlide case 481: // Polyobj_DoorSwing @@ -4942,7 +4984,7 @@ DoneSection2: CONS_Printf(M_GetText("%s started lap %u\n"), player_names[player-players], (UINT32)player->laps+1); // Reset starposts (checkpoints) info - player->starpostangle = player->starposttime = player->starpostnum = 0; + player->starpostscale = player->starpostangle = player->starposttime = player->starpostnum = 0; player->starpostx = player->starposty = player->starpostz = 0; P_ResetStarposts(); @@ -5636,9 +5678,12 @@ void P_UpdateSpecials(void) { if (foundflats->speed) // it is an animated flat { + // update the levelflat texture number + if (foundflats->basetexturenum != -1) + foundflats->texturenum = foundflats->basetexturenum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics); // update the levelflat lump number - foundflats->lumpnum = foundflats->baselumpnum + - ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics); + else if (foundflats->baselumpnum != LUMPERROR) + foundflats->lumpnum = foundflats->baselumpnum + ((leveltime/foundflats->speed + foundflats->animseq) % foundflats->numpics); } } } diff --git a/src/p_telept.c b/src/p_telept.c index e80dd0428..632b81e04 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -33,7 +33,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, INT16 starpostx, INT16 starposty, INT16 starpostz, INT32 starpostnum, tic_t starposttime, angle_t starpostangle, - INT32 flags2) + fixed_t starpostscale, angle_t drawangle, INT32 flags2) { const INT32 takeflags2 = MF2_TWOD|MF2_OBJECTFLIP; @@ -89,8 +89,11 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, thing->player->starpostz = starpostz; thing->player->starposttime = starposttime; thing->player->starpostangle = starpostangle; + thing->player->starpostscale = starpostscale; thing->player->starpostnum = starpostnum; + thing->player->drawangle = drawangle; + // Reset map starposts for the player's new info. P_ResetStarposts(); P_ClearStarPost(starpostnum); diff --git a/src/p_user.c b/src/p_user.c index 696bfc3b2..415bea763 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1062,6 +1062,8 @@ void P_ResetPlayer(player_t *player) // boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) { + fixed_t bottomheight, topheight; + if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing)) return false; @@ -1101,13 +1103,26 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) return true; // From the top/bottom. - if (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) + bottomheight = player->mo->z; + topheight = player->mo->z + player->mo->height; + + if (player->mo->eflags & MFE_VERTICALFLIP) { - if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) + fixed_t swap = bottomheight; + bottomheight = topheight; + topheight = swap; + } + + if (P_MobjFlip(player->mo)*(bottomheight - (thing->z + thing->height/2)) > 0) + { + if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) < 0)) + return true; + } + else if (P_MobjFlip(player->mo)*(topheight - (thing->z + thing->height/2)) < 0) + { + if (player->charability == CA_FLY && player->panim == PA_ABILITY && !(player->mo->eflags & MFE_UNDERWATER) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) > 0)) return true; } - else if (player->charability == CA_FLY && player->panim == PA_ABILITY) - return true; // Shield stomp. if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)) @@ -1427,11 +1442,11 @@ void P_PlayLivesJingle(player_t *player) S_StartSound(NULL, sfx_marioa); else { + P_PlayJingle(player, JT_1UP); if (player) player->powers[pw_extralife] = extralifetics + 1; strlcpy(S_sfx[sfx_None].caption, "One-up", 7); S_StartCaption(sfx_None, -1, extralifetics+1); - P_PlayJingle(player, JT_1UP); } } @@ -2213,148 +2228,153 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) player->pflags &= ~PF_SPINNING; } - if (player->pflags & PF_SPINNING) - { - if (player->mo->state-states != S_PLAY_ROLL && !(player->pflags & PF_STARTDASH)) - { - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_spin); - } - } - else if (player->pflags & PF_GLIDING) // ground gliding - { - if (dorollstuff) - { - player->skidtime = TICRATE; - player->mo->tics = -1; - } - else if (!player->skidtime) - player->pflags &= ~PF_GLIDING; - } - else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) - { - if (player->mo->state-states != S_PLAY_MELEE_LANDING) - { - mobjtype_t type = player->revitem; - P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); - player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; - S_StartSound(player->mo, sfx_s3k8b); - player->pflags |= PF_FULLSTASIS; - - // hearticles - if (type) - { - UINT8 i = 0; - angle_t throwang = -(2*ANG30); - fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t zo = 6*player->mo->scale; - fixed_t mu = FixedMul(player->maxdash, player->mo->scale); - fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); - fixed_t ev; - mobj_t *missile = NULL; - if (mu2 < mu) - mu2 = mu; - ev = (50*FRACUNIT - (mu/25))/50; - while (i < 5) - { - missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); - P_SetTarget(&missile->target, player->mo); - missile->angle = throwang + player->drawangle; - P_Thrust(missile, player->drawangle + ANGLE_90, - P_ReturnThrustY(missile, throwang, mu)); // side to side component - P_Thrust(missile, player->drawangle, mu2); // forward component - P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); - missile->momz += player->mo->pmomz; - missile->fuse = TICRATE/2; - missile->extravalue2 = ev; - - i++; - throwang += ANG30; - } - if (mobjinfo[type].seesound && missile) - S_StartSound(missile, missile->info->seesound); - } - } - } - else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) - ; - else if (player->panim != PA_IDLE && player->panim != PA_WALK && player->panim != PA_RUN && player->panim != PA_DASH) - { - if (player->cmomx || player->cmomy) - { - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) - P_SetPlayerMobjState(player->mo, S_PLAY_DASH); - else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) - && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) - P_SetPlayerMobjState(player->mo, S_PLAY_RUN); - else if ((player->rmomx || player->rmomy) - && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) - P_SetPlayerMobjState(player->mo, S_PLAY_WALK); - else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE) - P_SetPlayerMobjState(player->mo, S_PLAY_STND); - } - else - { - if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) - P_SetPlayerMobjState(player->mo, S_PLAY_DASH); - else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) - && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) - P_SetPlayerMobjState(player->mo, S_PLAY_RUN); - else if ((player->mo->momx || player->mo->momy) - && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) - P_SetPlayerMobjState(player->mo, S_PLAY_WALK); - else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE) - P_SetPlayerMobjState(player->mo, S_PLAY_STND); - } - } - - if (!(player->pflags & PF_GLIDING)) - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); - player->pflags &= ~(PF_STARTJUMP|PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/); - player->secondjump = 0; - player->glidetime = 0; - player->climbing = 0; - player->powers[pw_tailsfly] = 0; - - if (player->pflags & PF_SHIELDABILITY) - { - player->pflags &= ~PF_SHIELDABILITY; - - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) // Elemental shield's stomp attack. - { - if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) // play a blunt sound - S_StartSound(player->mo, sfx_s3k4c); - else // create a fire pattern on the ground - { - S_StartSound(player->mo, sfx_s3k47); - P_ElementalFire(player, true); - } - P_SetObjectMomZ(player->mo, - (player->mo->eflags & MFE_UNDERWATER) - ? 6*FRACUNIT/5 - : 5*FRACUNIT/2, - false); - P_SetPlayerMobjState(player->mo, S_PLAY_FALL); - player->mo->momx = player->mo->momy = 0; - clipmomz = false; - } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) // Bubble shield's bounce attack. - { - P_DoBubbleBounce(player); - clipmomz = false; - } - } - if (player->pflags & PF_BOUNCING) { - P_MobjCheckWater(player->mo); - player->mo->momz *= -1; - P_DoAbilityBounce(player, true); - if (player->scoreadd) - player->scoreadd--; + if (dorollstuff && player->mo->state-states != S_PLAY_BOUNCE_LANDING) + { + P_MobjCheckWater(player->mo); + player->mo->momz *= -1; + P_DoAbilityBounce(player, true); + if (player->scoreadd) + player->scoreadd--; + } clipmomz = false; } + else + { + if (player->pflags & PF_SPINNING) + { + if (player->mo->state-states != S_PLAY_ROLL && !(player->pflags & PF_STARTDASH)) + { + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_spin); + } + } + else if (player->pflags & PF_GLIDING) // ground gliding + { + if (dorollstuff) + { + player->skidtime = TICRATE; + player->mo->tics = -1; + } + else if (!player->skidtime) + player->pflags &= ~PF_GLIDING; + } + else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + { + if (player->mo->state-states != S_PLAY_MELEE_LANDING) + { + mobjtype_t type = player->revitem; + P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); + player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; + S_StartSound(player->mo, sfx_s3k8b); + player->pflags |= PF_FULLSTASIS; + + // hearticles + if (type) + { + UINT8 i = 0; + angle_t throwang = -(2*ANG30); + fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t zo = 6*player->mo->scale; + fixed_t mu = FixedMul(player->maxdash, player->mo->scale); + fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); + fixed_t ev; + mobj_t *missile = NULL; + if (mu2 < mu) + mu2 = mu; + ev = (50*FRACUNIT - (mu/25))/50; + while (i < 5) + { + missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); + P_SetTarget(&missile->target, player->mo); + missile->angle = throwang + player->drawangle; + P_Thrust(missile, player->drawangle + ANGLE_90, + P_ReturnThrustY(missile, throwang, mu)); // side to side component + P_Thrust(missile, player->drawangle, mu2); // forward component + P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); + missile->momz += player->mo->pmomz; + missile->fuse = TICRATE/2; + missile->extravalue2 = ev; + + i++; + throwang += ANG30; + } + if (mobjinfo[type].seesound && missile) + S_StartSound(missile, missile->info->seesound); + } + } + } + else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) + ; + else if (player->panim != PA_IDLE && player->panim != PA_WALK && player->panim != PA_RUN && player->panim != PA_DASH) + { + if (player->cmomx || player->cmomy) + { + if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) + && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN); + else if ((player->rmomx || player->rmomy) + && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE) + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + } + else + { + if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) + && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN); + else if ((player->mo->momx || player->mo->momy) + && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE) + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + } + } + + if (!(player->pflags & PF_GLIDING)) + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); + player->pflags &= ~(PF_STARTJUMP|PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/); + player->secondjump = 0; + player->glidetime = 0; + player->climbing = 0; + player->powers[pw_tailsfly] = 0; + + if (player->pflags & PF_SHIELDABILITY) + { + player->pflags &= ~PF_SHIELDABILITY; + + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) // Elemental shield's stomp attack. + { + if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) // play a blunt sound + S_StartSound(player->mo, sfx_s3k4c); + else // create a fire pattern on the ground + { + S_StartSound(player->mo, sfx_s3k47); + P_ElementalFire(player, true); + } + P_SetObjectMomZ(player->mo, + (player->mo->eflags & MFE_UNDERWATER) + ? 6*FRACUNIT/5 + : 5*FRACUNIT/2, + false); + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + player->mo->momx = player->mo->momy = 0; + clipmomz = false; + } + else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) // Bubble shield's bounce attack. + { + P_DoBubbleBounce(player); + clipmomz = false; + } + } + } } return clipmomz; @@ -2960,22 +2980,19 @@ static void P_DoBubbleBreath(player_t *player) P_SetScale(bubble, bubble->destscale); } - if (player->powers[pw_carry] == CR_NIGHTSMODE) // NiGHTS Super doesn't spawn flight bubbles - return; - // Tails stirs up the water while flying in it if (player->powers[pw_tailsfly] && (leveltime & 1) && player->charability != CA_SWIM) { - fixed_t radius = (3*player->mo->radius)>>1; + fixed_t radius = player->mo->radius; angle_t fa = ((leveltime%45)*FINEANGLES/8) & FINEMASK; fixed_t stirwaterx = FixedMul(FINECOSINE(fa),radius); fixed_t stirwatery = FixedMul(FINESINE(fa),radius); fixed_t stirwaterz; if (player->mo->eflags & MFE_VERTICALFLIP) - stirwaterz = player->mo->z + player->mo->height - FixedDiv(player->mo->height,3*FRACUNIT/2); + stirwaterz = player->mo->z + player->mo->height - (4<mo->z + FixedDiv(player->mo->height,3*FRACUNIT/2); + stirwaterz = player->mo->z + (4<mo->x + stirwaterx, @@ -3896,6 +3913,33 @@ static void P_SetWeaponDelay(player_t *player, INT32 delay) } } +// +// P_DrainWeaponAmmo +// +// Reduces rings and weapon ammo. Also penalizes the player +// for using weapon rings with no normal rings! >:V +// +static void P_DrainWeaponAmmo (player_t *player, INT32 power) +{ + player->powers[power]--; + + if (player->rings < 1) + { + player->ammoremovalweapon = player->currentweapon; + player->ammoremovaltimer = ammoremovaltics; + + if (player->powers[power] > 0) // can't take a ring that doesn't exist + { + player->powers[power]--; + player->ammoremoval = 2; + } + else + player->ammoremoval = 1; + } + else + player->rings--; +} + // // P_DoFiring() // @@ -3934,22 +3978,12 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) player->pflags |= PF_ATTACKDOWN; -#define TAKE_AMMO(player, power) \ - player->powers[power]--; \ - if (player->rings < 1) \ - { \ - if (player->powers[power] > 0) \ - player->powers[power]--; \ - } \ - else \ - player->rings--; - if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring. goto firenormal; //code repetition sucks. // Bounce ring else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering]) { - TAKE_AMMO(player, pw_bouncering); + P_DrainWeaponAmmo(player, pw_bouncering); P_SetWeaponDelay(player, TICRATE/4); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING); @@ -3960,7 +3994,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Rail ring else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring]) { - TAKE_AMMO(player, pw_railring); + P_DrainWeaponAmmo(player, pw_railring); P_SetWeaponDelay(player, (3*TICRATE)/2); mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW); @@ -3971,7 +4005,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Automatic else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring]) { - TAKE_AMMO(player, pw_automaticring); + P_DrainWeaponAmmo(player, pw_automaticring); player->pflags &= ~PF_ATTACKDOWN; P_SetWeaponDelay(player, 2); @@ -3980,7 +4014,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Explosion else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring]) { - TAKE_AMMO(player, pw_explosionring); + P_DrainWeaponAmmo(player, pw_explosionring); P_SetWeaponDelay(player, (3*TICRATE)/2); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION); @@ -3988,7 +4022,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // Grenade else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering]) { - TAKE_AMMO(player, pw_grenadering); + P_DrainWeaponAmmo(player, pw_grenadering); P_SetWeaponDelay(player, TICRATE/3); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION); @@ -4007,7 +4041,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) angle_t shotangle = player->mo->angle; angle_t oldaiming = player->aiming; - TAKE_AMMO(player, pw_scatterring); + P_DrainWeaponAmmo(player, pw_scatterring); P_SetWeaponDelay(player, (2*TICRATE)/3); // Center @@ -4069,8 +4103,6 @@ firenormal: } } - #undef TAKE_AMMO - if (mo) { if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING) @@ -4887,56 +4919,185 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range) // static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { - mobj_t *lockon = NULL; + mobj_t *lockonthok = NULL, *lockonshield = NULL, *visual = NULL; if (player->pflags & PF_JUMPSTASIS) return; - if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) && (lockon = P_LookForEnemies(player, true, false))) + if ((player->charability == CA_HOMINGTHOK) && !player->homing && (player->pflags & PF_JUMPED) && (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) && (lockonthok = P_LookForEnemies(player, true, false))) { if (P_IsLocalPlayer(player)) // Only display it on your own view. { - mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockon); + visual = P_SpawnMobj(lockonthok->x, lockonthok->y, lockonthok->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker + P_SetTarget(&visual->target, lockonthok); } } - if (cmd->buttons & BT_USE && !(player->pflags & PF_JUMPDOWN) && !player->exiting && !P_PlayerInPain(player)) + ////////////////// + //SHIELD ACTIVES// + //& SUPER FLOAT!// + ////////////////// + + if ((player->pflags & PF_JUMPED) && !player->exiting && !P_PlayerInPain(player)) { - if (player->mo->tracer && player->powers[pw_carry] == CR_MACESPIN) - {} - else if (onground || player->climbing || (player->mo->tracer && player->powers[pw_carry])) - {} - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND - && !(player->pflags & PF_JUMPED) - && !(player->pflags & PF_USEDOWN)) - P_DoJumpShield(player); - else if (!(player->pflags & PF_SLIDING) && ((gametype != GT_CTF) || (!player->gotflag))) + if (onground || player->climbing || player->powers[pw_carry]) + ; + else if (gametype == GT_CTF && player->gotflag) + ; + else if (player->pflags & (PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player has used an ability previously + ; + else if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_USEDOWN) + && ((!(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX)))) // thokked is optional if you're bubblewrapped { + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) + { + if ((lockonshield = P_LookForEnemies(player, false, false))) + { + if (P_IsLocalPlayer(player)) // Only display it on your own view. + { + boolean dovis = true; + if (lockonshield == lockonthok) + { + if (leveltime & 2) + dovis = false; + else if (visual) + P_RemoveMobj(visual); + } + if (dovis) + { + visual = P_SpawnMobj(lockonshield->x, lockonshield->y, lockonshield->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker + P_SetTarget(&visual->target, lockonshield); + P_SetMobjStateNF(visual, visual->info->spawnstate+1); + } + } + } + } + if (cmd->buttons & BT_USE // Spin button effects + #ifdef HAVE_BLUA + && !LUAh_ShieldSpecial(player) + #endif + ) + { + // Force stop + if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) + { + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->mo->momx = player->mo->momy = player->mo->momz = 0; + S_StartSound(player->mo, sfx_ngskid); + } + else + { + switch (player->powers[pw_shield] & SH_NOSTACK) + { + // Whirlwind jump/Thunder jump + case SH_WHIRLWIND: + case SH_THUNDERCOIN: + P_DoJumpShield(player); + break; + // Armageddon pow + case SH_ARMAGEDDON: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + P_BlackOw(player); + break; + // Attraction blast + case SH_ATTRACT: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + player->homing = 2; + P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonshield)); + if (lockonshield) + { + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonshield->x, lockonshield->y); + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_s3k40); + player->homing = 3*TICRATE; + } + else + S_StartSound(player->mo, sfx_s3ka6); + break; + // Elemental stomp/Bubble bounce + case SH_ELEMENTAL: + case SH_BUBBLEWRAP: + { + boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + if (elem) + { + player->pflags |= PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + S_StartSound(player->mo, sfx_s3k43); + } + else + { + player->pflags &= ~PF_NOJUMPDAMAGE; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_s3k44); + } + player->secondjump = 0; + player->mo->momx = player->mo->momy = 0; + P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); + break; + } + // Flame burst + case SH_FLAMEAURA: + player->pflags |= PF_THOKKED|PF_SHIELDABILITY; + P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); + player->drawangle = player->mo->angle; + S_StartSound(player->mo, sfx_s3k43); + default: + break; + } + } + } + } + else if ((cmd->buttons & BT_USE)) + { + if (!(player->pflags & PF_USEDOWN) && P_SuperReady(player)) + { + // If you can turn super and aren't already, + // and you don't have a shield, do it! + P_DoSuperTransformation(player, false); + } + else #ifdef HAVE_BLUA if (!LUAh_JumpSpinSpecial(player)) #endif switch (player->charability) { - case CA_TELEKINESIS: - if (player->pflags & PF_JUMPED) + case CA_THOK: + if (player->powers[pw_super]) // Super Sonic float { - if (!(player->pflags & PF_THOKKED) || (player->charflags & SF_MULTIABILITY)) + if ((player->speed > 5*player->mo->scale) // FixedMul(5<mo->scale), but scale is FRACUNIT-based + && (P_MobjFlip(player->mo)*player->mo->momz <= 0)) { - P_Telekinesis(player, - -FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player) - FixedMul(384*FRACUNIT, player->mo->scale)); + if (player->panim != PA_RUN && player->panim != PA_WALK) + { + if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); + else + P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); + } + + player->mo->momz = 0; + player->pflags &= ~(PF_STARTJUMP|PF_SPINNING); } } break; - case CA_AIRDRILL: - if (player->pflags & PF_JUMPED) + case CA_TELEKINESIS: + if (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || (player->charflags & SF_MULTIABILITY)) { - if (player->pflags & PF_THOKKED) // speed up falling down - { - if (player->secondjump < 42) - player->secondjump ++; - } + P_Telekinesis(player, + -FixedMul(player->actionspd, player->mo->scale), // -ve thrust (pulling towards player) + FixedMul(384*FRACUNIT, player->mo->scale)); + } + break; + case CA_TWINSPIN: + if ((player->charability2 == CA2_MELEE) && (!(player->pflags & (PF_THOKKED|PF_USEDOWN)) || player->charflags & SF_MULTIABILITY)) + { + player->pflags |= PF_THOKKED; + S_StartSound(player->mo, sfx_s3k42); + player->mo->frame = 0; + P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN); } break; default: @@ -4949,6 +5110,9 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) { if (player->pflags & PF_JUMPED) { + if (cmd->buttons & BT_USE && player->secondjump < 42) // speed up falling down + player->secondjump++; + if (player->flyangle > 0 && player->pflags & PF_THOKKED) { player->flyangle--; @@ -4967,6 +5131,11 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } } + /////////////// + // CHARACTER // + // ABILITIES!// + /////////////// + if (cmd->buttons & BT_JUMP && !player->exiting && !P_PlayerInPain(player)) { #ifdef HAVE_BLUA @@ -5036,7 +5205,6 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); - player->drawangle = player->mo->angle; if (maptol & TOL_2D) { @@ -5051,11 +5219,11 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (player->charability == CA_HOMINGTHOK) { - P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockon)); - if (lockon) + P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockonthok)); + if (lockonthok) { P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockonthok->x, lockonthok->y); player->homing = 3*TICRATE; } else @@ -5067,6 +5235,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags &= ~PF_NOJUMPDAMAGE; } + player->drawangle = player->mo->angle; + if (player->mo->info->attacksound && !player->spectator) S_StartSound(player->mo, player->mo->info->attacksound); // Play the THOK sound @@ -5213,6 +5383,60 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_DoJumpShield(player); } + // HOMING option. + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT // Sonic 3D Blast. + && player->pflags & PF_SHIELDABILITY) + { + if (player->homing && player->mo->tracer) + { + if (!P_HomingAttack(player->mo, player->mo->tracer)) + { + P_SetObjectMomZ(player->mo, 6*FRACUNIT, false); + if (player->mo->eflags & MFE_UNDERWATER) + player->mo->momz = FixedMul(player->mo->momz, FRACUNIT/3); + player->homing = 0; + } + } + + // If you're not jumping, then you obviously wouldn't be homing. + if (!(player->pflags & PF_JUMPED)) + player->homing = 0; + } + else if (player->charability == CA_HOMINGTHOK) // Sonic Adventure. + { + // If you've got a target, chase after it! + if (player->homing && player->mo->tracer) + { + P_SpawnThokMobj(player); + + // But if you don't, then stop homing. + if (!P_HomingAttack(player->mo, player->mo->tracer)) + { + if (player->mo->eflags & MFE_UNDERWATER) + P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false); + else + P_SetObjectMomZ(player->mo, 10*FRACUNIT, false); + + player->mo->momx = player->mo->momy = player->homing = 0; + + if (player->mo->tracer->flags2 & MF2_FRET) + P_InstaThrust(player->mo, player->mo->angle, -(player->speed>>3)); + + if (!(player->mo->tracer->flags & MF_BOSS)) + player->pflags &= ~PF_THOKKED; + + P_SetPlayerMobjState(player->mo, S_PLAY_SPRING); + player->pflags |= PF_NOJUMPDAMAGE; + } + } + + // If you're not jumping, then you obviously wouldn't be homing. + if (!(player->pflags & PF_JUMPED)) + player->homing = 0; + } + else + player->homing = 0; + if (cmd->buttons & BT_JUMP) { player->pflags |= PF_JUMPDOWN; @@ -5239,7 +5463,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) player->pflags &= ~PF_JUMPDOWN; // Repeat abilities, but not double jump! - if (player->secondjump == 1 && player->charability != CA_DOUBLEJUMP) + if (player->secondjump == 1 && player->charability != CA_DOUBLEJUMP && player->charability != CA_AIRDRILL) { if (player->charflags & SF_MULTIABILITY) { @@ -7895,7 +8119,7 @@ static void P_MovePlayer(player_t *player) } else if (player->pflags & PF_BOUNCING) { - if (!(player->pflags & PF_JUMPDOWN) || (onground && P_MobjFlip(player->mo)*player->mo->momz <= 0)) // If not holding the jump button OR on flat ground + if (!(player->pflags & PF_JUMPDOWN)) // If not holding the jump button { P_ResetPlayer(player); // down, stop bouncing. player->pflags |= PF_THOKKED; @@ -7998,16 +8222,22 @@ static void P_MovePlayer(player_t *player) if (P_MobjFlip(player->mo)*player->mo->momz < FixedMul(5*actionspd, player->mo->scale)) P_SetObjectMomZ(player->mo, actionspd/2, true); + P_SetPlayerMobjState(player->mo, player->mo->state->nextstate); + player->fly1--; } } // Tails Put-Put noise - if (player->charability == CA_FLY && player->bot != 1 && leveltime % 10 == 0 && !player->spectator) + if (player->charability == CA_FLY + && player->bot != 1 + && !(player->mo->eflags & MFE_UNDERWATER) + && leveltime % 10 == 0 + && !player->spectator) S_StartSound(player->mo, sfx_putput); // Descend - if (cmd->buttons & BT_USE && !(player->pflags & PF_STASIS) && !player->exiting) + if (cmd->buttons & BT_USE && !(player->pflags & PF_STASIS) && !player->exiting && !(player->mo->eflags & MFE_GOOWATER)) if (P_MobjFlip(player->mo)*player->mo->momz > -FixedMul(5*actionspd, player->mo->scale)) P_SetObjectMomZ(player->mo, -actionspd/2, true); @@ -8015,11 +8245,12 @@ static void P_MovePlayer(player_t *player) else { // Tails-gets-tired Stuff - if (player->panim == PA_ABILITY) + if (player->panim == PA_ABILITY && player->mo->state-states != S_PLAY_FLY_TIRED) P_SetPlayerMobjState(player->mo, S_PLAY_FLY_TIRED); if (player->charability == CA_FLY && (leveltime % 10 == 0) && player->mo->state-states == S_PLAY_FLY_TIRED + && !(player->mo->eflags & MFE_UNDERWATER) && !player->spectator) S_StartSound(player->mo, sfx_pudpud); } @@ -8124,178 +8355,6 @@ static void P_MovePlayer(player_t *player) localangle2 = player->mo->angle; } - ////////////////// - //SHIELD ACTIVES// - //& SUPER FLOAT!// - ////////////////// - - if (player->pflags & PF_JUMPED && !player->exiting && player->mo->health) - { - mobj_t *lockon = NULL; - if (!player->powers[pw_super] && player->powers[pw_shield] == SH_ATTRACT && !(player->pflags & PF_THOKKED)) - { - if ((lockon = P_LookForEnemies(player, false, false))) - { - if (P_IsLocalPlayer(player)) // Only display it on your own view. - { - mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker - P_SetTarget(&visual->target, lockon); - P_SetMobjStateNF(visual, visual->info->spawnstate+1); - } - } - } - if (cmd->buttons & BT_USE) // Spin button effects - { - if (player->powers[pw_super]) // Super can't use shield actives, only passives - { - if ((player->charability == CA_THOK) // Super Sonic float - && (player->speed > 5*player->mo->scale) // FixedMul(5<mo->scale), but scale is FRACUNIT-based - && (P_MobjFlip(player->mo)*player->mo->momz <= 0)) - { - if (player->panim != PA_RUN && player->panim != PA_WALK) - { - if (player->speed >= FixedMul(player->runspeed, player->mo->scale)) - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN); - else - P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT); - } - - player->mo->momz = 0; - player->pflags &= ~(PF_STARTJUMP|PF_SPINNING); - } - } - else -#ifdef HAVE_BLUA - if (!LUAh_ShieldSpecial(player)) -#endif - { - if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously - && (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super - { - // Force stop - if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) - { - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->mo->momx = player->mo->momy = player->mo->momz = 0; - S_StartSound(player->mo, sfx_ngskid); - } - else - { - switch (player->powers[pw_shield] & SH_NOSTACK) - { - // Super! - case SH_NONE: - if (P_SuperReady(player)) - P_DoSuperTransformation(player, false); - break; - // Whirlwind jump/Thunder jump - case SH_WHIRLWIND: - case SH_THUNDERCOIN: - P_DoJumpShield(player); - break; - // Armageddon pow - case SH_ARMAGEDDON: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - P_BlackOw(player); - break; - // Attraction blast - case SH_ATTRACT: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->homing = 2; - P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockon)); - if (lockon) - { - player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); - player->pflags &= ~PF_NOJUMPDAMAGE; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_s3k40); - player->homing = 3*TICRATE; - } - else - S_StartSound(player->mo, sfx_s3ka6); - break; - // Elemental stomp/Bubble bounce - case SH_ELEMENTAL: - case SH_BUBBLEWRAP: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - player->pflags &= ~PF_NOJUMPDAMAGE; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - player->secondjump = 0; - player->mo->momx = player->mo->momy = 0; - P_SetObjectMomZ(player->mo, -24*FRACUNIT, false); - S_StartSound(player->mo, - ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) - ? sfx_s3k43 - : sfx_s3k44); - break; - // Flame burst - case SH_FLAMEAURA: - player->pflags |= PF_THOKKED|PF_SHIELDABILITY; - P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); - player->drawangle = player->mo->angle; - S_StartSound(player->mo, sfx_s3k43); - default: - break; - } - } - } - } - } - } - - // HOMING option. - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT // Sonic 3D Blast. - && player->pflags & PF_SHIELDABILITY) - { - if (player->homing && player->mo->tracer) - { - if (!P_HomingAttack(player->mo, player->mo->tracer)) - { - P_SetObjectMomZ(player->mo, 6*FRACUNIT, false); - if (player->mo->eflags & MFE_UNDERWATER) - player->mo->momz = FixedMul(player->mo->momz, FRACUNIT/3); - player->homing = 0; - } - } - - // If you're not jumping, then you obviously wouldn't be homing. - if (!(player->pflags & PF_JUMPED)) - player->homing = 0; - } - else if (player->charability == CA_HOMINGTHOK) // Sonic Adventure. - { - // If you've got a target, chase after it! - if (player->homing && player->mo->tracer) - { - P_SpawnThokMobj(player); - - // But if you don't, then stop homing. - if (!P_HomingAttack(player->mo, player->mo->tracer)) - { - if (player->mo->eflags & MFE_UNDERWATER) - P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false); - else - P_SetObjectMomZ(player->mo, 10*FRACUNIT, false); - - player->mo->momx = player->mo->momy = player->homing = 0; - - if (player->mo->tracer->flags2 & MF2_FRET) - P_InstaThrust(player->mo, player->mo->angle, -(player->speed>>3)); - - if (!(player->mo->tracer->flags & MF_BOSS)) - player->pflags &= ~PF_THOKKED; - - // P_SetPlayerMobjState(player->mo, S_PLAY_SPRING); -- Speed didn't like it, RIP - } - } - - // If you're not jumping, then you obviously wouldn't be homing. - if (!(player->pflags & PF_JUMPED)) - player->homing = 0; - } - else - player->homing = 0; - if (player->climbing == 1) P_DoClimbing(player); @@ -8339,7 +8398,7 @@ static void P_MovePlayer(player_t *player) // Less height while spinning. Good for spinning under things...? if ((player->mo->state == &states[player->mo->info->painstate]) - || ((player->pflags & PF_JUMPED) && !(player->pflags & PF_NOJUMPDAMAGE && player->charflags & SF_NOJUMPSPIN)) + || ((player->pflags & PF_JUMPED) && !(player->pflags & PF_NOJUMPDAMAGE)) || (player->pflags & PF_SPINNING) || player->powers[pw_tailsfly] || player->pflags & PF_GLIDING || (player->charability == CA_FLY && player->mo->state-states == S_PLAY_FLY_TIRED)) @@ -8640,7 +8699,7 @@ static void P_DoRopeHang(player_t *player) if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope { - player->pflags |= P_GetJumpFlags(player); + player->pflags |= (P_GetJumpFlags(player)|PF_USEDOWN); P_SetPlayerMobjState(player->mo, S_PLAY_JUMP); P_SetTarget(&player->mo->tracer, NULL); @@ -8850,7 +8909,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) // Looks for something you can hit - Used for homing attack // If nonenemies is true, includes monitors and springs! // If bullet is true, you can look up and the distance is further, -// but your total angle span you can look is limited to compensate. +// but your total angle span you can look is limited to compensate. (Also, allows monitors.) // mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) { @@ -8860,6 +8919,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) const fixed_t maxdist = FixedMul((bullet ? RING_DIST*2 : RING_DIST), player->mo->scale); const angle_t span = (bullet ? ANG30 : ANGLE_90); fixed_t dist, closestdist = 0; + const mobjflag_t nonenemiesdisregard = (bullet ? 0 : MF_MONITOR)|MF_SPRING; for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next) { @@ -8867,19 +8927,23 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet) continue; mo = (mobj_t *)think; - if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag - continue; // not a valid target + + if (mo->flags & MF_NOCLIPTHING) + continue; if (mo->health <= 0) // dead continue; + if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag + continue; // not a valid target + if (mo == player->mo) continue; if (mo->flags2 & MF2_FRET) continue; - if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING)) + if (!nonenemies && mo->flags & nonenemiesdisregard) continue; if (!bullet && mo->type == MT_DETON) // Don't be STUPID, Sonic! @@ -9034,19 +9098,22 @@ boolean P_GetLives(player_t *player) INT32 i, maxlivesplayer = -1, livescheck = 1; if (!(netgame || multiplayer) || (gametype != GT_COOP) - || (cv_cooplives.value == 1) || (player->lives == INFLIVES)) return true; - if ((cv_cooplives.value == 2 || cv_cooplives.value == 0) && player->lives > 0) - return true; - if (cv_cooplives.value == 0) // infinite lives { - player->lives++; + if (player->lives < 1) + player->lives = 1; return true; } + if ((cv_cooplives.value == 2 || cv_cooplives.value == 1) && player->lives > 0) + return true; + + if (cv_cooplives.value == 1) + return false; + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -9153,7 +9220,7 @@ static void P_DeathThink(player_t *player) // continue logic if (!(netgame || multiplayer) && player->lives <= 0) { - if (player->deadtimer > TICRATE && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0) + if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0) G_UseContinue(); else if (player->deadtimer >= gameovertics) G_UseContinue(); // Even if we don't have one this handles ending the game @@ -9177,12 +9244,12 @@ static void P_DeathThink(player_t *player) // Force respawn if idle for more than 30 seconds in shooter modes. if (player->deadtimer > 30*TICRATE && !G_PlatformGametype()) player->playerstate = PST_REBORN; - else if ((player->lives > 0 || j != MAXPLAYERS) && !G_IsSpecialStage(gamemap)) // Don't allow "click to respawn" in special stages! + else if ((player->lives > 0 || j != MAXPLAYERS) && !(!(netgame || multiplayer) && G_IsSpecialStage(gamemap))) // Don't allow "click to respawn" in special stages! { if (gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2) { P_ConsiderAllGone(); - if ((player->deadtimer > 5*TICRATE) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE))) + if ((player->deadtimer > TICRATE<<1) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE))) { //player->spectator = true; player->outofcoop = true; @@ -9198,16 +9265,11 @@ static void P_DeathThink(player_t *player) player->playerstate = PST_REBORN; else switch(gametype) { case GT_COOP: - if (player->deadtimer > TICRATE) - player->playerstate = PST_REBORN; - break; case GT_COMPETITION: + case GT_RACE: if (player->deadtimer > TICRATE) player->playerstate = PST_REBORN; break; - case GT_RACE: - player->playerstate = PST_REBORN; - break; default: if (player->deadtimer > cv_respawntime.value*TICRATE) player->playerstate = PST_REBORN; @@ -9216,7 +9278,7 @@ static void P_DeathThink(player_t *player) } // Single player auto respawn - if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE) + if (!(netgame || multiplayer) && player->deadtimer > TICRATE<<1) player->playerstate = PST_REBORN; } } @@ -9316,12 +9378,16 @@ consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, consvar_t cv_cam_speed = {"cam_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_orbit = {"cam_orbit", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_adjust = {"cam_adjust", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_dist = {"cam2_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_height = {"cam2_height", "25", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_speed = {"cam2_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_orbit = {"cam2_orbit", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_adjust = {"cam2_adjust", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; fixed_t t_cam_dist = -42; fixed_t t_cam_height = -42; @@ -9375,9 +9441,9 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled) { angle_t angle = 0, focusangle = 0, focusaiming = 0; - fixed_t x, y, z, dist, checkdist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight; + fixed_t x, y, z, dist, distxy, distz, checkdist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight, slopez = 0; INT32 camrotate; - boolean camstill, cameranoclip; + boolean camstill, cameranoclip, camorbit; mobj_t *mo; subsector_t *newsubsec; fixed_t f1, f2; @@ -9458,6 +9524,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // 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; + camorbit = (!stricmp(cv_cam_orbit.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)); @@ -9466,6 +9533,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { camspeed = cv_cam_speed.value; camstill = cv_cam_still.value; + camorbit = cv_cam_orbit.value; camrotate = cv_cam_rotate.value; camdist = FixedMul(cv_cam_dist.value, mo->scale); camheight = FixedMul(cv_cam_height.value, FixedMul(player->camerascale, mo->scale)); @@ -9474,6 +9542,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { camspeed = cv_cam2_speed.value; camstill = cv_cam2_still.value; + camorbit = cv_cam2_orbit.value; camrotate = cv_cam2_rotate.value; camdist = FixedMul(cv_cam2_dist.value, mo->scale); camheight = FixedMul(cv_cam2_height.value, FixedMul(player->camerascale, mo->scale)); @@ -9583,13 +9652,50 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall dist <<= 1; } + + checkdist = (dist = FixedMul(dist, player->camerascale)); if (checkdist < 128*FRACUNIT) checkdist = 128*FRACUNIT; - x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); - y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); + if (!(twodlevel || (mo->flags2 & MF2_TWOD)) && !(player->powers[pw_carry] == CR_NIGHTSMODE)) // This block here is like 90% Lach's work, thanks bud + { + if (!resetcalled && ((thiscam == &camera && cv_cam_adjust.value) || (thiscam == &camera2 && cv_cam2_adjust.value))) + { + if (!(mo->eflags & MFE_JUSTHITFLOOR) && (P_IsObjectOnGround(mo)) // Check that player is grounded + && thiscam->ceilingz - thiscam->floorz >= P_GetPlayerHeight(player)) // Check that camera's sector is large enough for the player to fit into, at least + { + if (mo->eflags & MFE_VERTICALFLIP) // if player is upside-down + { + //z = min(z, thiscam->ceilingz); // solution 1: change new z coordinate to be at LEAST its ground height + slopez += min(thiscam->ceilingz - mo->z, 0); // solution 2: change new z coordinate by the difference between camera's ground and top of player + } + else // player is not upside-down + { + //z = max(z, thiscam->floorz); // solution 1: change new z coordinate to be at LEAST its ground height + slopez += max(thiscam->floorz - mo->z - mo->height, 0); // solution 2: change new z coordinate by the difference between camera's ground and top of player + } + } + } + } + + if (camorbit) //Sev here, I'm guessing this is where orbital cam lives + { + if (rendermode == render_opengl) + distxy = FixedMul(dist, FINECOSINE((focusaiming>>ANGLETOFINESHIFT) & FINEMASK)); + else + distxy = dist; + distz = -FixedMul(dist, FINESINE((focusaiming>>ANGLETOFINESHIFT) & FINEMASK)) + slopez; + } + else + { + distxy = dist; + distz = slopez; + } + + x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy); + y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy); #if 0 if (twodlevel || (mo->flags2 & MF2_TWOD)) @@ -9626,9 +9732,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall pviewheight = FixedMul(41*player->height/48, mo->scale); if (mo->eflags & MFE_VERTICALFLIP) - z = mo->z + mo->height - pviewheight - camheight; + z = mo->z + mo->height - pviewheight - camheight + distz; else - z = mo->z + pviewheight + camheight; + z = mo->z + pviewheight + camheight + distz; // move camera down to move under lower ceilings newsubsec = R_IsPointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1)); @@ -9941,6 +10047,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } return (x == thiscam->x && y == thiscam->y && z == thiscam->z && angle == thiscam->aiming); + } boolean P_SpectatorJoinGame(player_t *player) @@ -10592,7 +10699,8 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) angle_t horizangle = player->drawangle; fixed_t zoffs = 0; fixed_t backwards = -1*FRACUNIT; - boolean doroll = (player->panim == PA_ROLL || player->panim == PA_JUMP); + boolean doswim = (player->panim == PA_ABILITY && (player->mo->eflags & MFE_UNDERWATER)); + boolean doroll = (player->panim == PA_ROLL || (player->panim == PA_JUMP && !(player->charflags & SF_NOJUMPSPIN)) || doswim); angle_t rollangle; boolean panimchange; INT32 ticnum = 0; @@ -10619,17 +10727,25 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) if (testval < FRACUNIT) testval = FRACUNIT; } - if (smilesonground && !player->mo->reactiontime) + + if (doswim) + zdist = player->mo->momz<<1; + else if (smilesonground && !player->mo->reactiontime) zdist = (player->mo->z - tails->threshold); else zdist = player->mo->momz; + rollangle = R_PointToAngle2(0, 0, testval, -P_MobjFlip(player->mo)*zdist); - zoffs = 3*FRACUNIT + 12*FINESINE(rollangle >> ANGLETOFINESHIFT); - backwards = -12*FINECOSINE(rollangle >> ANGLETOFINESHIFT); + + if (!doswim) + { + zoffs = 3*FRACUNIT + 12*FINESINE(rollangle >> ANGLETOFINESHIFT); + backwards = -12*FINECOSINE(rollangle >> ANGLETOFINESHIFT); + } } else if (player->panim == PA_RUN) backwards = -5*FRACUNIT; - else if (player->panim == PA_SPRING) + else if (player->panim == PA_SPRING || player->panim == PA_JUMP) { zoffs += 4*FRACUNIT; backwards /= 2; @@ -10651,7 +10767,7 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) zoffs = -7*FRACUNIT; backwards = -9*FRACUNIT; } - else if (player->mo->sprite2 == SPR2_FLY || player->mo->sprite2 == SPR2_TIRE) + else if (player->panim == PA_ABILITY) backwards = -5*FRACUNIT; // sprite... @@ -10668,7 +10784,7 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) else chosenstate = S_TAILSOVERLAY_0DEGREES; } - else if (player->panim == PA_SPRING) + else if (player->panim == PA_SPRING || player->panim == PA_JUMP) chosenstate = S_TAILSOVERLAY_MINUS60DEGREES; else if (player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE) chosenstate = S_TAILSOVERLAY_PLUS60DEGREES; @@ -10691,6 +10807,8 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) } else if (player->mo->sprite2 == SPR2_FLY) chosenstate = S_TAILSOVERLAY_FLY; + else if (player->mo->sprite2 == SPR2_SWIM) + chosenstate = S_TAILSOVERLAY_FLY; else if (player->mo->sprite2 == SPR2_TIRE) chosenstate = S_TAILSOVERLAY_TIRE; else if (player->panim == PA_ABILITY2) @@ -10716,8 +10834,10 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) } } +#if 0 if (player->fly1 != 0 && player->powers[pw_tailsfly] != 0 && !smilesonground) P_SetMobjState(tails, chosenstate); +#endif // animation... if (player->panim == PA_SPRING || player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE) @@ -10732,7 +10852,7 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails) else if (player->mo->state-states == S_PLAY_GASP) tails->tics = -1; else if (player->mo->sprite2 == SPR2_TIRE) - ticnum = 4; + ticnum = (doswim ? 2 : 4); else if (player->panim != PA_IDLE) ticnum = player->mo->tics; @@ -10955,7 +11075,8 @@ void P_PlayerThink(player_t *player) if (player->exiting == 2 || countdown2 == 2) { - if (cv_playersforexit.value) // Count to be sure everyone's exited + UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); + if (numneeded) // Count to be sure everyone's exited { INT32 i, total = 0, exiting = 0; @@ -10971,7 +11092,7 @@ void P_PlayerThink(player_t *player) exiting++; } - if (!total || ((4*exiting)/total) >= cv_playersforexit.value) + if (!total || ((4*exiting)/total) >= numneeded) { if (server) SendNetXCmd(XD_EXITLEVEL, NULL, 0); @@ -11018,8 +11139,6 @@ void P_PlayerThink(player_t *player) { if (gametype != GT_COOP) player->score = 0; - player->mo->health = 1; - player->rings = player->spheres = 0; } else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP) { @@ -11266,8 +11385,8 @@ void P_PlayerThink(player_t *player) { boolean currentlyonground = P_IsObjectOnGround(player->mo); - if (!player->powers[pw_carry] - && ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) + if (!player->powers[pw_carry] && !player->powers[pw_nocontrol] + && ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE|PF_STASIS)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) && !(cmd->forwardmove || cmd->sidemove) && (player->rmomx || player->rmomy) && (!player->capsule || (player->capsule->reactiontime != (player-players)+1))) @@ -11277,6 +11396,16 @@ void P_PlayerThink(player_t *player) if (!currentlyonground) acceleration /= 2; + // fake skidding! see P_SkidStuff for reference on conditionals + else if (!player->skidtime && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID) && P_AproxDistance(player->mo->momx, player->mo->momy) >= FixedMul(player->runspeed, player->mo->scale)) // modified from player->runspeed/2 'cuz the skid was just TOO frequent ngl + { + if (player->mo->state-states != S_PLAY_SKID) + P_SetPlayerMobjState(player->mo, S_PLAY_SKID); + player->mo->tics = player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; + + if (P_IsLocalPlayer(player)) // the sound happens way more frequently now, so give co-op players' ears a brake... + S_StartSound(player->mo, sfx_skid); + } if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... acceleration = FixedMul(acceleration<mo->movefactor)>>FRACBITS; @@ -11361,6 +11490,12 @@ void P_PlayerThink(player_t *player) // Counters, time dependent power ups. // Time Bonus & Ring Bonus count settings + if (player->ammoremovaltimer) + { + if (--player->ammoremovaltimer == 0) + player->ammoremoval = 0; + } + // Strength counts up to diminish fade. if (player->powers[pw_sneakers] && player->powers[pw_sneakers] < UINT16_MAX) player->powers[pw_sneakers]--; @@ -11780,7 +11915,7 @@ void P_PlayerAfterThink(player_t *player) { if ((tails->z + tails->height + player->mo->height + FixedMul(FRACUNIT, player->mo->scale)) <= tails->ceilingz && (tails->eflags & MFE_VERTICALFLIP)) // Reverse gravity check for the carrier - Flame - player->mo->z = tails->z + tails->height + FixedMul(FRACUNIT, player->mo->scale); + player->mo->z = tails->z + tails->height + 12*player->mo->scale; else player->powers[pw_carry] = CR_NONE; } @@ -11788,7 +11923,7 @@ void P_PlayerAfterThink(player_t *player) { if ((tails->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale)) >= tails->floorz && !(tails->eflags & MFE_VERTICALFLIP)) // Correct gravity check for the carrier - Flame - player->mo->z = tails->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale); + player->mo->z = tails->z - player->mo->height - 12*player->mo->scale; else player->powers[pw_carry] = CR_NONE; } @@ -11797,7 +11932,7 @@ void P_PlayerAfterThink(player_t *player) player->powers[pw_carry] = CR_NONE; else { - P_TryMove(player->mo, tails->x, tails->y, true); + P_TryMove(player->mo, tails->x + P_ReturnThrustX(tails, tails->player->drawangle, 4*FRACUNIT), tails->y + P_ReturnThrustY(tails, tails->player->drawangle, 4*FRACUNIT), true); player->mo->momx = tails->momx; player->mo->momy = tails->momy; player->mo->momz = tails->momz; @@ -11823,6 +11958,8 @@ void P_PlayerAfterThink(player_t *player) { if (player->mo->state-states != S_PLAY_RIDE) P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); + if ((tails->skin && ((skin_t *)(tails->skin))->sprites[SPR2_SWIM].numframes) && (tails->eflags & MFE_UNDERWATER)) + tails->player->powers[pw_tailsfly] = 0; } else P_SetTarget(&player->mo->tracer, NULL); diff --git a/src/r_bsp.c b/src/r_bsp.c index d521d9f4d..23e751420 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -1088,9 +1088,9 @@ static void R_Subsector(size_t num) { light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); ffloor[numffloors].plane = R_FindPlane(polysec->floorheight, polysec->floorpic, - polysec->lightlevel, polysec->floor_xoffs, polysec->floor_yoffs, + (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->floor_xoffs, polysec->floor_yoffs, polysec->floorpic_angle-po->angle, - NULL, NULL, po + (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po #ifdef ESLOPE , NULL // will ffloors be slopable eventually? #endif @@ -1115,10 +1115,10 @@ static void R_Subsector(size_t num) && polysec->ceilingheight <= ceilingcenterz && (viewz > polysec->ceilingheight)) { - light = R_GetPlaneLight(frontsector, polysec->ceilingheight, viewz < polysec->ceilingheight); + light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, - polysec->lightlevel, polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle, - NULL, NULL, po + (light == -1 ? frontsector->lightlevel : *frontsector->lightlist[light].lightlevel), polysec->ceiling_xoffs, polysec->ceiling_yoffs, polysec->ceilingpic_angle-po->angle, + (light == -1 ? frontsector->extra_colormap : *frontsector->lightlist[light].extra_colormap), NULL, po #ifdef ESLOPE , NULL // will ffloors be slopable eventually? #endif diff --git a/src/r_data.c b/src/r_data.c index 6889bddde..b8b363021 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -23,6 +23,7 @@ #include "z_zone.h" #include "p_setup.h" // levelflats #include "v_video.h" // pMasterPalette +#include "byteptr.h" #include "dehacked.h" #ifdef _WIN32 @@ -40,6 +41,28 @@ #include #endif +#ifdef HAVE_PNG + +#ifndef _MSC_VER +#ifndef _LARGEFILE64_SOURCE +#define _LARGEFILE64_SOURCE +#endif +#endif + +#ifndef _LFS64_LARGEFILE +#define _LFS64_LARGEFILE +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 0 +#endif + +#include "png.h" +#ifndef PNG_READ_SUPPORTED +#undef HAVE_PNG +#endif +#endif + // // Texture definition. // Each texture is composed of one or more patches, @@ -98,12 +121,11 @@ INT32 numtextures = 0; // total number of textures found, // size of following tables texture_t **textures = NULL; +textureflat_t *texflats = NULL; static UINT32 **texturecolumnofs; // column offset lookup table for each texture static UINT8 **texturecache; // graphics data for each generated full-size texture -// texture width is a power of 2, so it can easily repeat along sidedefs using a simple mask -INT32 *texturewidthmask; - +INT32 *texturewidth; fixed_t *textureheight; // needed for texture pegging INT32 *texturetranslation; @@ -220,15 +242,121 @@ static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, tex } } +UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) +{ + RGBA_t output; + if (style == AST_TRANSLUCENT) + { + if (alpha == 0) + output.rgba = background.rgba; + else if (alpha == 0xFF) + output.rgba = foreground.rgba; + else if (alpha < 0xFF) + { + UINT8 beta = (0xFF - alpha); + output.s.red = ((background.s.red * beta) + (foreground.s.red * alpha)) / 0xFF; + output.s.green = ((background.s.green * beta) + (foreground.s.green * alpha)) / 0xFF; + output.s.blue = ((background.s.blue * beta) + (foreground.s.blue * alpha)) / 0xFF; + } + // write foreground pixel alpha + // if there's no pixel in here + if (!background.rgba) + output.s.alpha = foreground.s.alpha; + else + output.s.alpha = 0xFF; + return output.rgba; + } +#define clamp(c) max(min(c, 0xFF), 0x00); + else + { + float falpha = ((float)alpha / 256.0f); + float fr = ((float)foreground.s.red * falpha); + float fg = ((float)foreground.s.green * falpha); + float fb = ((float)foreground.s.blue * falpha); + if (style == AST_ADD) + { + output.s.red = clamp((int)(background.s.red + fr)); + output.s.green = clamp((int)(background.s.green + fg)); + output.s.blue = clamp((int)(background.s.blue + fb)); + } + else if (style == AST_SUBTRACT) + { + output.s.red = clamp((int)(background.s.red - fr)); + output.s.green = clamp((int)(background.s.green - fg)); + output.s.blue = clamp((int)(background.s.blue - fb)); + } + else if (style == AST_REVERSESUBTRACT) + { + output.s.red = clamp((int)((-background.s.red) + fr)); + output.s.green = clamp((int)((-background.s.green) + fg)); + output.s.blue = clamp((int)((-background.s.blue) + fb)); + } + else if (style == AST_MODULATE) + { + fr = ((float)foreground.s.red / 256.0f); + fg = ((float)foreground.s.green / 256.0f); + fb = ((float)foreground.s.blue / 256.0f); + output.s.red = clamp((int)(background.s.red * fr)); + output.s.green = clamp((int)(background.s.green * fg)); + output.s.blue = clamp((int)(background.s.blue * fb)); + } + // just copy the pixel + else if (style == AST_COPY) + output.rgba = foreground.rgba; + + output.s.alpha = 0xFF; + return output.rgba; + } +#undef clamp + return 0; +} + +UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha) +{ + // Alpha style set to translucent? + if (style == AST_TRANSLUCENT) + { + // Is the alpha small enough for translucency? + if (alpha <= (10*255/11)) + { + UINT8 *mytransmap; + // Is the patch way too translucent? Don't blend then. + if (alpha < 255/11) + return background; + // The equation's not exact but it works as intended. I'll call it a day for now. + mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); + if (background != 0xFF) + return *(mytransmap + (background<<8) + foreground); + } + else // just copy the pixel + return foreground; + } + // just copy the pixel + else if (style == AST_COPY) + return foreground; + // use ASTBlendPixel for all other blend modes + // and find the nearest colour in the palette + else if (style != AST_TRANSLUCENT) + { + RGBA_t texel; + RGBA_t bg = V_GetColor(background); + RGBA_t fg = V_GetColor(foreground); + texel.rgba = ASTBlendPixel(bg, fg, style, alpha); + return NearestColor(texel.s.red, texel.s.green, texel.s.blue); + } + // fallback if all above fails, somehow + // return the background pixel + return background; +} + // -// R_DrawTransColumnInCache +// R_DrawBlendColumnInCache // Draws a translucent column into the cache, applying a half-cooked equation to get a proper translucency value (Needs code in R_GenerateTexture()). // -static inline void R_DrawTransColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) +static inline void R_DrawBlendColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) { INT32 count, position; UINT8 *source, *dest; - UINT8 *mytransmap = transtables + ((8*(originPatch->alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); // The equation's not exact but it works as intended. I'll call it a day for now. INT32 topdelta, prevdelta = -1; INT32 originy = originPatch->originy; @@ -258,7 +386,8 @@ static inline void R_DrawTransColumnInCache(column_t *patch, UINT8 *cache, texpa if (count > 0) { for (; dest < cache + position + count; source++, dest++) - if (*dest != 0xFF) *dest = *(mytransmap + ((*dest)<<8) + (*source)); + if (*source != 0xFF) + *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); } patch = (column_t *)((UINT8 *)patch + patch->length + 4); @@ -266,14 +395,13 @@ static inline void R_DrawTransColumnInCache(column_t *patch, UINT8 *cache, texpa } // -// R_DrawTransColumnInCache +// R_DrawBlendFlippedColumnInCache // Similar to the one above except that the column is inverted. // -static inline void R_DrawTransFlippedColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) +static inline void R_DrawBlendFlippedColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) { INT32 count, position; UINT8 *source, *dest; - UINT8 *mytransmap = transtables + ((8*(originPatch->alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); // The equation's not exact but it works as intended. I'll call it a day for now. INT32 topdelta, prevdelta = -1; INT32 originy = originPatch->originy; @@ -302,7 +430,8 @@ static inline void R_DrawTransFlippedColumnInCache(column_t *patch, UINT8 *cache if (count > 0) { for (; dest < cache + position + count; --source, dest++) - if (*dest != 0xFF) *dest = *(mytransmap + ((*dest)<<8) + (*source)); + if (*source != 0xFF) + *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); } patch = (column_t *)((UINT8 *)patch + patch->length + 4); @@ -315,7 +444,7 @@ static inline void R_DrawTransFlippedColumnInCache(column_t *patch, UINT8 *cache // Allocate space for full size texture, either single patch or 'composite' // Build the full textures from patches. // The texture caching system is a little more hungry of memory, but has -// been simplified for the sake of highcolor, dynamic ligthing, & speed. +// been simplified for the sake of highcolor (lol), dynamic ligthing, & speed. // // This is not optimised, but it's supposed to be executed only once // per level, when enough memory is available. @@ -332,6 +461,10 @@ static UINT8 *R_GenerateTexture(size_t texnum) column_t *patchcol; UINT32 *colofs; + UINT16 wadnum; + lumpnum_t lumpnum; + size_t lumplength; + I_Assert(texnum <= (size_t)numtextures); texture = textures[texnum]; I_Assert(texture != NULL); @@ -346,7 +479,19 @@ static UINT8 *R_GenerateTexture(size_t texnum) { boolean holey = false; patch = texture->patches; - realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); + + wadnum = patch->wad; + lumpnum = patch->lump; + lumplength = W_LumpLengthPwad(wadnum, lumpnum); + realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + +#ifndef NO_PNG_LUMPS + if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) + { + realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); + goto multipatch; + } +#endif // Check the patch for holes. if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height)) @@ -376,7 +521,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) { texture->holes = true; texture->flip = patch->flip; - blocksize = W_LumpLengthPwad(patch->wad, patch->lump); + blocksize = lumplength; block = Z_Calloc(blocksize, PU_STATIC, // will change tag at end of this function &texturecache[texnum]); M_Memcpy(block, realpatch, blocksize); @@ -403,6 +548,9 @@ static UINT8 *R_GenerateTexture(size_t texnum) } // multi-patch textures (or 'composite') +#ifndef NO_PNG_LUMPS + multipatch: +#endif texture->holes = false; texture->flip = 0; blocksize = (texture->width * 4) + (texture->width * texture->height); @@ -422,18 +570,20 @@ static UINT8 *R_GenerateTexture(size_t texnum) for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { static void (*ColumnDrawerPointer)(column_t *, UINT8 *, texpatch_t *, INT32, INT32); // Column drawing function pointer. - if ((patch->style == AST_TRANSLUCENT) && (patch->alpha <= (10*255/11))) // Alpha style set to translucent? Is the alpha small enough for translucency? - { - if (patch->alpha < 255/11) // Is the patch way too translucent? Don't render then. - continue; - ColumnDrawerPointer = (patch->flip & 2) ? R_DrawTransFlippedColumnInCache : R_DrawTransColumnInCache; - } + if (patch->style != AST_COPY) + ColumnDrawerPointer = (patch->flip & 2) ? R_DrawBlendFlippedColumnInCache : R_DrawBlendColumnInCache; else - { ColumnDrawerPointer = (patch->flip & 2) ? R_DrawFlippedColumnInCache : R_DrawColumnInCache; - } - realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); + wadnum = patch->wad; + lumpnum = patch->lump; + lumplength = W_LumpLengthPwad(wadnum, lumpnum); + realpatch = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); +#ifndef NO_PNG_LUMPS + if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) + realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); +#endif + x1 = patch->originx; width = SHORT(realpatch->width); height = SHORT(realpatch->height); @@ -509,10 +659,14 @@ void R_CheckTextureCache(INT32 tex) UINT8 *R_GetColumn(fixed_t tex, INT32 col) { UINT8 *data; + INT32 width = texturewidth[tex]; + + if (width & (width - 1)) + col = (UINT32)col % width; + else + col &= (width - 1); - col &= texturewidthmask[tex]; data = texturecache[tex]; - if (!data) data = R_GenerateTexture(tex); @@ -550,7 +704,7 @@ void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *index); #define TX_END "TX_END" void R_LoadTextures(void) { - INT32 i, k, w; + INT32 i, w; UINT16 j; UINT16 texstart, texend, texturesLumpPos; patch_t *patchlump; @@ -567,6 +721,7 @@ void R_LoadTextures(void) } Z_Free(texturetranslation); Z_Free(textures); + Z_Free(texflats); } // Load patches and textures. @@ -627,15 +782,16 @@ void R_LoadTextures(void) // Allocate memory and initialize to 0 for all the textures we are initialising. // There are actually 5 buffers allocated in one for convenience. textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); + texflats = Z_Calloc((numtextures * sizeof(*texflats)), PU_STATIC, NULL); // Allocate texture column offset table. texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *))); // Allocate texture referencing cache. - texturecache = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 2)); - // Allocate texture width mask table. - texturewidthmask = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 3)); - // Allocate texture height mask table. - textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4)); + texturecache = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 2)); + // Allocate texture width table. + texturewidth = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 3)); + // Allocate texture height table. + textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4)); // Create translation table for global animation. texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, NULL); @@ -673,20 +829,39 @@ void R_LoadTextures(void) // Work through each lump between the markers in the WAD. for (j = 0; j < (texend - texstart); j++) { + UINT16 wadnum = (UINT16)w; + lumpnum_t lumpnum = texstart + j; + size_t lumplength; + if (wadfiles[w]->type == RET_PK3) { - if (W_IsLumpFolder((UINT16)w, texstart + j)) // Check if lump is a folder + if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder continue; // If it is then SKIP IT } - patchlump = W_CacheLumpNumPwad((UINT16)w, texstart + j, PU_CACHE); + + lumplength = W_LumpLengthPwad(wadnum, lumpnum); + patchlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height); texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); // Set texture properties. - M_Memcpy(texture->name, W_CheckNameForNumPwad((UINT16)w, texstart + j), sizeof(texture->name)); - texture->width = SHORT(patchlump->width); - texture->height = SHORT(patchlump->height); + M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); + +#ifndef NO_PNG_LUMPS + if (R_IsLumpPNG((UINT8 *)patchlump, lumplength)) + { + INT16 width, height; + R_PNGDimensions((UINT8 *)patchlump, &width, &height, lumplength); + texture->width = width; + texture->height = height; + } + else +#endif + { + texture->width = SHORT(patchlump->width); + texture->height = SHORT(patchlump->height); + } texture->patchcount = 1; texture->holes = false; texture->flip = 0; @@ -701,11 +876,7 @@ void R_LoadTextures(void) Z_Unlock(patchlump); - k = 1; - while (k << 1 <= texture->width) - k <<= 1; - - texturewidthmask[i] = k - 1; + texturewidth[i] = texture->width; textureheight[i] = texture->height << FRACBITS; i++; } @@ -848,8 +1019,16 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) { Z_Free(texturesToken); texturesToken = M_GetToken(NULL); - if(stricmp(texturesToken, "TRANSLUCENT")==0) + if (stricmp(texturesToken, "TRANSLUCENT")==0) style = AST_TRANSLUCENT; + else if (stricmp(texturesToken, "ADD")==0) + style = AST_ADD; + else if (stricmp(texturesToken, "SUBTRACT")==0) + style = AST_SUBTRACT; + else if (stricmp(texturesToken, "REVERSESUBTRACT")==0) + style = AST_REVERSESUBTRACT; + else if (stricmp(texturesToken, "MODULATE")==0) + style = AST_MODULATE; } else if (stricmp(texturesToken, "FLIPX")==0) flip |= 1; @@ -1097,7 +1276,7 @@ int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum) texturesToken = M_GetToken(texturesText); while (texturesToken != NULL) { - if (stricmp(texturesToken, "WALLTEXTURE")==0) + if (stricmp(texturesToken, "WALLTEXTURE") == 0 || stricmp(texturesToken, "TEXTURE") == 0) { numTexturesInLump++; Z_Free(texturesToken); @@ -1105,7 +1284,7 @@ int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum) } else { - I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\", got \"%s\"",texturesToken); + I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\" or \"TEXTURE\", got \"%s\"",texturesToken); } texturesToken = M_GetToken(NULL); } @@ -1146,21 +1325,21 @@ void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *texindex) texturesToken = M_GetToken(texturesText); while (texturesToken != NULL) { - if (stricmp(texturesToken, "WALLTEXTURE")==0) + if (stricmp(texturesToken, "WALLTEXTURE") == 0 || stricmp(texturesToken, "TEXTURE") == 0) { Z_Free(texturesToken); // Get the new texture newTexture = R_ParseTexture(true); // Store the new texture textures[*texindex] = newTexture; - texturewidthmask[*texindex] = newTexture->width - 1; + texturewidth[*texindex] = newTexture->width; textureheight[*texindex] = newTexture->height << FRACBITS; // Increment i back in R_LoadTextures() (*texindex)++; } else { - I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\", got \"%s\"",texturesToken); + I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\" or \"TEXTURE\", got \"%s\"",texturesToken); } texturesToken = M_GetToken(NULL); } @@ -1267,6 +1446,41 @@ lumpnum_t R_GetFlatNumForName(const char *name) lump = LUMPERROR; } + // Detect textures + if (lump == LUMPERROR) + { + // Scan wad files backwards so patched textures take preference. + for (i = numwadfiles - 1; i >= 0; i--) + { + switch (wadfiles[i]->type) + { + case RET_WAD: + if ((start = W_CheckNumForNamePwad("TX_START", (UINT16)i, 0)) == INT16_MAX) + continue; + if ((end = W_CheckNumForNamePwad("TX_END", (UINT16)i, start)) == INT16_MAX) + continue; + break; + case RET_PK3: + if ((start = W_CheckNumForFolderStartPK3("Textures/", i, 0)) == INT16_MAX) + continue; + if ((end = W_CheckNumForFolderEndPK3("Textures/", i, start)) == INT16_MAX) + continue; + break; + default: + continue; + } + + // Now find lump with specified name in that range. + lump = W_CheckNumForNamePwad(name, (UINT16)i, start); + if (lump < end) + { + lump += (i<<16); // found it, in our constraints + break; + } + lump = LUMPERROR; + } + } + if (lump == LUMPERROR) { if (strcmp(name, SKYFLATNAME)) @@ -1615,7 +1829,6 @@ extracolormap_t *R_ColormapForName(char *name) // static double deltas[256][3], map[256][3]; -static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); static int RoundUp(double number); lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap) @@ -2027,7 +2240,7 @@ extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *ex // Thanks to quake2 source! // utils3/qdata/images.c -static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b) +UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b) { int dr, dg, db; int distortion, bestdistortion = 256 * 256 * 4, bestcolor = 0, i; @@ -2306,3 +2519,535 @@ void R_PrecacheLevel(void) "texturememory: %s k\n" "spritememory: %s k\n", sizeu1(flatmemory>>10), sizeu2(texturememory>>10), sizeu3(spritememory>>10)); } + +// https://github.com/coelckers/prboom-plus/blob/master/prboom2/src/r_patch.c#L350 +boolean R_CheckIfPatch(lumpnum_t lump) +{ + size_t size; + INT16 width, height; + patch_t *patch; + boolean result; + + size = W_LumpLength(lump); + + // minimum length of a valid Doom patch + if (size < 13) + return false; + + patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC); + + width = SHORT(patch->width); + height = SHORT(patch->height); + + result = (height > 0 && height <= 16384 && width > 0 && width <= 16384 && width < (INT16)(size / 4)); + + if (result) + { + // The dimensions seem like they might be valid for a patch, so + // check the column directory for extra security. All columns + // must begin after the column directory, and none of them must + // point past the end of the patch. + INT16 x; + + for (x = 0; x < width; x++) + { + UINT32 ofs = LONG(patch->columnofs[x]); + + // Need one byte for an empty column (but there's patches that don't know that!) + if (ofs < (UINT32)width * 4 + 8 || ofs >= (UINT32)size) + { + result = false; + break; + } + } + } + + return result; +} + +void R_PatchToFlat(patch_t *patch, UINT8 *flat) +{ + fixed_t col, ofs; + column_t *column; + UINT8 *desttop, *dest, *deststop; + UINT8 *source; + + desttop = flat; + deststop = desttop + (SHORT(patch->width) * SHORT(patch->height)); + + for (col = 0; col < SHORT(patch->width); col++, desttop++) + { + INT32 topdelta, prevdelta = -1; + column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[col])); + + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + + dest = desttop + (topdelta * SHORT(patch->width)); + source = (UINT8 *)(column) + 3; + for (ofs = 0; dest < deststop && ofs < column->length; ofs++) + { + *dest = source[ofs]; + dest += SHORT(patch->width); + } + column = (column_t *)((UINT8 *)column + column->length + 4); + } + } +} + +#ifndef NO_PNG_LUMPS +boolean R_IsLumpPNG(const UINT8 *d, size_t s) +{ + if (s < 67) // http://garethrees.org/2007/11/14/pngcrush/ + return false; + // Check for PNG file signature using memcmp + // As it may be faster on CPUs with slow unaligned memory access + // Ref: http://www.libpng.org/pub/png/spec/1.2/PNG-Rationale.html#R.PNG-file-signature + return (memcmp(&d[0], "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) == 0); +} + +#ifdef HAVE_PNG + +#if PNG_LIBPNG_VER_DLLNUM < 14 +typedef PNG_CONST png_byte *png_const_bytep; +#endif +typedef struct { + png_const_bytep buffer; + png_uint_32 bufsize; + png_uint_32 current_pos; +} png_io_t; + +static void PNG_IOReader(png_structp png_ptr, png_bytep data, png_size_t length) +{ + png_io_t *f = png_get_io_ptr(png_ptr); + if (length > (f->bufsize - f->current_pos)) + png_error(png_ptr, "PNG_IOReader: buffer overrun"); + memcpy(data, f->buffer + f->current_pos, length); + f->current_pos += length; +} + +typedef struct +{ + char name[4]; + void *data; + size_t size; +} png_chunk_t; + +static png_byte *chunkname = NULL; +static png_chunk_t chunk; + +static int PNG_ChunkReader(png_structp png_ptr, png_unknown_chunkp chonk) +{ + (void)png_ptr; + if (!memcmp(chonk->name, chunkname, 4)) + { + memcpy(chunk.name, chonk->name, 4); + chunk.size = chonk->size; + chunk.data = Z_Malloc(chunk.size, PU_STATIC, NULL); + memcpy(chunk.data, chonk->data, chunk.size); + return 1; + } + return 0; +} + +static void PNG_error(png_structp PNG, png_const_charp pngtext) +{ + CONS_Debug(DBG_RENDER, "libpng error at %p: %s", PNG, pngtext); + //I_Error("libpng error at %p: %s", PNG, pngtext); +} + +static void PNG_warn(png_structp PNG, png_const_charp pngtext) +{ + CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); +} + +static png_bytep *PNG_Read(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) +{ + png_structp png_ptr; + png_infop png_info_ptr; + png_uint_32 width, height; + int bit_depth, color_type; + png_uint_32 y; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + + png_io_t png_io; + png_bytep *row_pointers; + + png_byte grAb_chunk[5] = {'g', 'r', 'A', 'b', (png_byte)'\0'}; + png_voidp *user_chunk_ptr; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); + if (!png_ptr) + { + CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); + return NULL; + } + + png_info_ptr = png_create_info_struct(png_ptr); + if (!png_info_ptr) + { + CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return NULL; + } + +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(png_ptr))) +#endif + { + //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); + png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); + return NULL; + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); +#endif + + // set our own read_function + png_io.buffer = (png_const_bytep)png; + png_io.bufsize = size; + png_io.current_pos = 0; + png_set_read_fn(png_ptr, &png_io, PNG_IOReader); + + memset(&chunk, 0x00, sizeof(png_chunk_t)); + chunkname = grAb_chunk; // I want to read a grAb chunk + + user_chunk_ptr = png_get_user_chunk_ptr(png_ptr); + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, PNG_ChunkReader); + png_set_keep_unknown_chunks(png_ptr, 2, chunkname, 1); + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_set_user_limits(png_ptr, 2048, 2048); +#endif + + png_read_info(png_ptr, png_info_ptr); + png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + else if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + else if (color_type != PNG_COLOR_TYPE_RGB_ALPHA && color_type != PNG_COLOR_TYPE_GRAY_ALPHA) + { +#if PNG_LIBPNG_VER < 10207 + png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); +#else + png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER); +#endif + } + + png_read_update_info(png_ptr, png_info_ptr); + + // Read the image + row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height); + for (y = 0; y < height; y++) + row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, png_info_ptr)); + png_read_image(png_ptr, row_pointers); + + // Read grAB chunk + if ((topoffset || leftoffset) && (chunk.data != NULL)) + { + INT32 *offsets = (INT32 *)chunk.data; + // read left offset + if (leftoffset != NULL) + *leftoffset = (INT16)BIGENDIAN_LONG(*offsets); + offsets++; + // read top offset + if (topoffset != NULL) + *topoffset = (INT16)BIGENDIAN_LONG(*offsets); + } + + // bye + png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); + if (chunk.data) + Z_Free(chunk.data); + + *w = (INT32)width; + *h = (INT32)height; + return row_pointers; +} + +// Convert a PNG to a raw image. +static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) +{ + UINT8 *flat; + png_uint_32 x, y; + png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, size); + png_uint_32 width = *w, height = *h; + + if (!row_pointers) + I_Error("PNG_RawConvert: conversion failed"); + + // Convert the image to 8bpp + flat = Z_Malloc(width * height, PU_LEVEL, NULL); + memset(flat, TRANSPARENTPIXEL, width * height); + for (y = 0; y < height; y++) + { + png_bytep row = row_pointers[y]; + for (x = 0; x < width; x++) + { + png_bytep px = &(row[x * 4]); + if ((UINT8)px[3]) + flat[((y * width) + x)] = NearestColor((UINT8)px[0], (UINT8)px[1], (UINT8)px[2]); + } + } + free(row_pointers); + + return flat; +} + +// Convert a PNG to a flat. +UINT8 *R_PNGToFlat(levelflat_t *levelflat, UINT8 *png, size_t size) +{ + return PNG_RawConvert(png, &levelflat->width, &levelflat->height, NULL, NULL, size); +} + +// Convert a PNG to a patch. +static unsigned char imgbuf[1<<26]; +patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency) +{ + UINT16 width, height; + INT16 topoffset = 0, leftoffset = 0; + UINT8 *raw = PNG_RawConvert(png, &width, &height, &topoffset, &leftoffset, size); + + UINT32 x, y; + UINT8 *img; + UINT8 *imgptr = imgbuf; + UINT8 *colpointers, *startofspan; + + if (!raw) + I_Error("R_PNGToPatch: conversion failed"); + + // Write image size and offset + WRITEINT16(imgptr, width); + WRITEINT16(imgptr, height); + WRITEINT16(imgptr, leftoffset); + WRITEINT16(imgptr, topoffset); + + // Leave placeholder to column pointers + colpointers = imgptr; + imgptr += width*4; + + // Write columns + for (x = 0; x < width; x++) + { + int lastStartY = 0; + int spanSize = 0; + startofspan = NULL; + + //printf("%d ", x); + // Write column pointer (@TODO may be wrong) + WRITEINT32(colpointers, imgptr - imgbuf); + + // Write pixels + for (y = 0; y < height; y++) + { + UINT8 paletteIndex = raw[((y * width) + x)]; + boolean opaque = transparency ? (paletteIndex != TRANSPARENTPIXEL) : true; + + // End span if we have a transparent pixel + if (!opaque) + { + if (startofspan) + WRITEUINT8(imgptr, 0); + startofspan = NULL; + continue; + } + + // Start new column if we need to + if (!startofspan || spanSize == 255) + { + int writeY = y; + + // If we reached the span size limit, finish the previous span + if (startofspan) + WRITEUINT8(imgptr, 0); + + if (y > 254) + { + // Make sure we're aligned to 254 + if (lastStartY < 254) + { + WRITEUINT8(imgptr, 254); + WRITEUINT8(imgptr, 0); + imgptr += 2; + lastStartY = 254; + } + + // Write stopgap empty spans if needed + writeY = y - lastStartY; + + while (writeY > 254) + { + WRITEUINT8(imgptr, 254); + WRITEUINT8(imgptr, 0); + imgptr += 2; + writeY -= 254; + } + } + + startofspan = imgptr; + WRITEUINT8(imgptr, writeY);///@TODO calculate starting y pos + imgptr += 2; + spanSize = 0; + + lastStartY = y; + } + + // Write the pixel + WRITEUINT8(imgptr, paletteIndex); + spanSize++; + startofspan[1] = spanSize; + } + + if (startofspan) + WRITEUINT8(imgptr, 0); + + WRITEUINT8(imgptr, 0xFF); + } + + size = imgptr-imgbuf; + img = Z_Malloc(size, PU_STATIC, NULL); + memcpy(img, imgbuf, size); + + Z_Free(raw); + + if (destsize != NULL) + *destsize = size; + return (patch_t *)img; +} + +boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size) +{ + png_structp png_ptr; + png_infop png_info_ptr; + png_uint_32 w, h; + int bit_depth, color_type; +#ifdef PNG_SETJMP_SUPPORTED +#ifdef USE_FAR_KEYWORD + jmp_buf jmpbuf; +#endif +#endif + + png_io_t png_io; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, + PNG_error, PNG_warn); + if (!png_ptr) + { + CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); + return false; + } + + png_info_ptr = png_create_info_struct(png_ptr); + if (!png_info_ptr) + { + CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); + png_destroy_read_struct(&png_ptr, NULL, NULL); + return false; + } + +#ifdef USE_FAR_KEYWORD + if (setjmp(jmpbuf)) +#else + if (setjmp(png_jmpbuf(png_ptr))) +#endif + { + //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); + png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); + return false; + } +#ifdef USE_FAR_KEYWORD + png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); +#endif + + // set our own read_function + png_io.buffer = (png_bytep)png; + png_io.bufsize = size; + png_io.current_pos = 0; + png_set_read_fn(png_ptr, &png_io, PNG_IOReader); + +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + png_set_user_limits(png_ptr, 2048, 2048); +#endif + + png_read_info(png_ptr, png_info_ptr); + + png_get_IHDR(png_ptr, png_info_ptr, &w, &h, &bit_depth, &color_type, + NULL, NULL, NULL); + + // okay done. stop. + png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); + + *width = (INT32)w; + *height = (INT32)h; + return true; +} +#endif +#endif + +void R_TextureToFlat(size_t tex, UINT8 *flat) +{ + texture_t *texture = textures[tex]; + + fixed_t col, ofs; + column_t *column; + UINT8 *desttop, *dest, *deststop; + UINT8 *source; + + desttop = flat; + deststop = desttop + (texture->width * texture->height); + + for (col = 0; col < texture->width; col++, desttop++) + { + column = (column_t *)R_GetColumn(tex, col); + if (!texture->holes) + { + dest = desttop; + source = (UINT8 *)(column); + for (ofs = 0; dest < deststop && ofs < texture->height; ofs++) + { + if (source[ofs] != TRANSPARENTPIXEL) + *dest = source[ofs]; + dest += texture->width; + } + } + else + { + INT32 topdelta, prevdelta = -1; + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + + dest = desttop + (topdelta * texture->width); + source = (UINT8 *)(column) + 3; + for (ofs = 0; dest < deststop && ofs < column->length; ofs++) + { + if (source[ofs] != TRANSPARENTPIXEL) + *dest = source[ofs]; + dest += texture->width; + } + column = (column_t *)((UINT8 *)column + column->length + 4); + } + } + } +} diff --git a/src/r_data.h b/src/r_data.h index b6b0a16a1..c2fd284ff 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -16,13 +16,19 @@ #include "r_defs.h" #include "r_state.h" +#include "p_setup.h" // levelflats #ifdef __GNUG__ #pragma interface #endif // Possible alpha types for a patch. -enum patchalphastyle {AST_COPY, AST_TRANSLUCENT}; // , AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; +enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; + +UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); +UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha); + +UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); // moved here for r_sky.c (texpatch_t is used) @@ -55,12 +61,17 @@ typedef struct texpatch_t patches[0]; } texture_t; +typedef struct +{ + UINT8 *flat; + INT16 width, height; +} textureflat_t; + // all loaded and prepared textures from the start of the game extern texture_t **textures; +extern textureflat_t *texflats; -// texture width is a power of 2, so it can easily repeat along sidedefs using a simple mask -extern INT32 *texturewidthmask; - +extern INT32 *texturewidth; extern fixed_t *textureheight; // needed for texture pegging extern INT16 color8to16[256]; // remap color index to highcolor @@ -88,7 +99,6 @@ void R_PrecacheLevel(void); // Floor/ceiling opaque texture tiles, // lookup by name. For animation? lumpnum_t R_GetFlatNumForName(const char *name); -#define R_FlatNumForName(x) R_GetFlatNumForName(x) // Called by P_Ticker for switches and animations, // returns the texture number for the texture name. @@ -148,6 +158,20 @@ const char *R_NameForColormap(extracolormap_t *extra_colormap); #define R_PutRgbaRGB(r, g, b) (R_PutRgbaR(r) + R_PutRgbaG(g) + R_PutRgbaB(b)) #define R_PutRgbaRGBA(r, g, b, a) (R_PutRgbaRGB(r, g, b) + R_PutRgbaA(a)) +boolean R_CheckIfPatch(lumpnum_t lump); +UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); + +void R_PatchToFlat(patch_t *patch, UINT8 *flat); +void R_TextureToFlat(size_t tex, UINT8 *flat); + +#ifndef NO_PNG_LUMPS +boolean R_IsLumpPNG(const UINT8 *d, size_t s); + +UINT8 *R_PNGToFlat(levelflat_t *levelflat, UINT8 *png, size_t size); +patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency); +boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size); +#endif + extern INT32 numtextures; #endif diff --git a/src/r_draw.c b/src/r_draw.c index d8b720caf..1754403c4 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -99,6 +99,8 @@ INT32 dc_numlights = 0, dc_maxlights, dc_texheight; INT32 ds_y, ds_x1, ds_x2; lighttable_t *ds_colormap; fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; +UINT16 ds_flatwidth, ds_flatheight; +boolean ds_powersoftwo; UINT8 *ds_source; // start of a 64*64 tile image UINT8 *ds_transmap; // one of the translucency tables @@ -557,9 +559,16 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U // White! if (skinnum == TC_BOSS) - dest_colormap[31] = 0; + { + for (i = 0; i < 16; i++) + dest_colormap[31-i] = i; + } else if (skinnum == TC_METALSONIC) - dest_colormap[159] = 0; + { + for (i = 0; i < 6; i++) + dest_colormap[Color_Index[SKINCOLOR_BLUE-1][12-i]] = Color_Index[SKINCOLOR_BLUE-1][i]; + dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0; + } return; } else if (color == SKINCOLOR_NONE) diff --git a/src/r_draw.h b/src/r_draw.h index 82498eb11..3c1429722 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -57,7 +57,9 @@ extern INT32 dc_texheight; extern INT32 ds_y, ds_x1, ds_x2; extern lighttable_t *ds_colormap; extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; -extern UINT8 *ds_source; // start of a 64*64 tile image +extern UINT16 ds_flatwidth, ds_flatheight; +extern boolean ds_powersoftwo; +extern UINT8 *ds_source; extern UINT8 *ds_transmap; #ifdef ESLOPE @@ -128,6 +130,8 @@ void R_FillBackScreen(void); void R_DrawViewBorder(void); #endif +#define TRANSPARENTPIXEL 255 + // ----------------- // 8bpp DRAWING CODE // ----------------- @@ -169,6 +173,13 @@ void R_DrawFogSpan_8(void); void R_DrawFogColumn_8(void); void R_DrawColumnShadowed_8(void); +#ifndef NOWATER +void R_DrawTranslucentWaterSpan_8(void); + +extern INT32 ds_bgofs; +extern INT32 ds_waterofs; +#endif + // ------------------ // 16bpp DRAWING CODE // ------------------ diff --git a/src/r_draw8.c b/src/r_draw8.c index 8a2d37fb3..77406f83c 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -105,8 +105,6 @@ void R_DrawColumn_8(void) } } -#define TRANSPARENTPIXEL 255 - void R_Draw2sMultiPatchColumn_8(void) { INT32 count; @@ -543,16 +541,19 @@ void R_DrawTranslatedColumn_8(void) */ void R_DrawSpan_8 (void) { - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; UINT8 *source; UINT8 *colormap; UINT8 *dest; const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; - size_t count; + size_t count = (ds_x2 - ds_x1 + 1); + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest // can be used for the fraction part. This allows calculation of the memory address in the @@ -561,62 +562,88 @@ void R_DrawSpan_8 (void) // bit per power of two (obviously) // Ok, because I was able to eliminate the variable spot below, this function is now FASTER // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = ds_yfrac << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; + if (ds_powersoftwo) + { + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + } source = ds_source; colormap = ds_colormap; dest = ylookup[ds_y] + columnofs[ds_x1]; - count = ds_x2 - ds_x1 + 1; if (dest+8 > deststop) return; - while (count >= 8) + if (!ds_powersoftwo) { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - dest[0] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; + while (count-- && dest <= deststop) + { + fixed_t x = (xposition >> FRACBITS); + fixed_t y = (yposition >> FRACBITS); - dest[1] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - dest[2] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; + x %= ds_flatwidth; + y %= ds_flatheight; - dest[3] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; - - dest[4] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; - - dest[5] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; - - dest[6] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; - - dest[7] = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; - - dest += 8; - count -= 8; + *dest++ = colormap[source[((y * ds_flatwidth) + x)]]; + xposition += xstep; + yposition += ystep; + } } - while (count-- && dest <= deststop) + else { - *dest++ = colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]]; - xposition += xstep; - yposition += ystep; + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + dest[0] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest[1] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest[2] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest[3] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest[4] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest[5] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest[6] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest[7] = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + *dest++ = colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]]; + xposition += xstep; + yposition += ystep; + } } } @@ -697,7 +724,24 @@ void R_DrawTiltedSpan_8(void) colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = colormap[source[((y * ds_flatwidth) + x)]]; + } + else + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; dest++; iz += ds_sz.x; uz += ds_su.x; @@ -734,7 +778,24 @@ void R_DrawTiltedSpan_8(void) for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = colormap[source[((y * ds_flatwidth) + x)]]; + } + else + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; dest++; u += stepu; v += stepv; @@ -750,7 +811,24 @@ void R_DrawTiltedSpan_8(void) u = (INT64)(startu); v = (INT64)(startv); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = colormap[source[((y * ds_flatwidth) + x)]]; + } + else + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; } else { @@ -771,7 +849,24 @@ void R_DrawTiltedSpan_8(void) for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = colormap[source[((y * ds_flatwidth) + x)]]; + } + else + *dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]]; dest++; u += stepu; v += stepv; @@ -832,7 +927,24 @@ void R_DrawTiltedTranslucentSpan_8(void) v = (INT64)(vz*z) + viewy; colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); + } + else + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); dest++; iz += ds_sz.x; uz += ds_su.x; @@ -869,7 +981,24 @@ void R_DrawTiltedTranslucentSpan_8(void) for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); + } + else + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); dest++; u += stepu; v += stepv; @@ -885,7 +1014,24 @@ void R_DrawTiltedTranslucentSpan_8(void) u = (INT64)(startu); v = (INT64)(startv); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); + } + else + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); } else { @@ -906,7 +1052,24 @@ void R_DrawTiltedTranslucentSpan_8(void) for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); + } + else + *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); dest++; u += stepu; v += stepv; @@ -967,9 +1130,28 @@ void R_DrawTiltedSplat_8(void) colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + } + else + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) *dest = colormap[val]; + dest++; iz += ds_sz.x; uz += ds_su.x; @@ -1006,7 +1188,24 @@ void R_DrawTiltedSplat_8(void) for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + } + else + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; if (val != TRANSPARENTPIXEL) *dest = colormap[val]; dest++; @@ -1024,7 +1223,24 @@ void R_DrawTiltedSplat_8(void) u = (INT64)(startu); v = (INT64)(startv); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + } + else + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; if (val != TRANSPARENTPIXEL) *dest = colormap[val]; } @@ -1048,6 +1264,24 @@ void R_DrawTiltedSplat_8(void) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (!ds_powersoftwo) + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + } + else + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; if (val != TRANSPARENTPIXEL) *dest = colormap[val]; dest++; @@ -1065,17 +1299,21 @@ void R_DrawTiltedSplat_8(void) */ void R_DrawSplat_8 (void) { - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; UINT8 *source; UINT8 *colormap; UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; - size_t count; + size_t count = (ds_x2 - ds_x1 + 1); UINT32 val; + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest // can be used for the fraction part. This allows calculation of the memory address in the // texture with two shifts, an OR and one AND. (see below) @@ -1083,99 +1321,125 @@ void R_DrawSplat_8 (void) // bit per power of two (obviously) // Ok, because I was able to eliminate the variable spot below, this function is now FASTER // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = ds_yfrac << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; + if (ds_powersoftwo) + { + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + } source = ds_source; colormap = ds_colormap; dest = ylookup[ds_y] + columnofs[ds_x1]; - count = ds_x2 - ds_x1 + 1; - while (count >= 8) + if (!ds_powersoftwo) { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - // - // 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[0] = colormap[val]; - xposition += xstep; - yposition += ystep; + while (count-- && dest <= deststop) + { + fixed_t x = (xposition >> FRACBITS); + fixed_t y = (yposition >> FRACBITS); - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[1] = colormap[val]; - xposition += xstep; - yposition += ystep; + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[2] = colormap[val]; - xposition += xstep; - yposition += ystep; + x %= ds_flatwidth; + y %= ds_flatheight; - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[3] = colormap[val]; - xposition += xstep; - yposition += ystep; - - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[4] = colormap[val]; - xposition += xstep; - yposition += ystep; - - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[5] = colormap[val]; - xposition += xstep; - yposition += ystep; - - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[6] = colormap[val]; - xposition += xstep; - yposition += ystep; - - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - dest[7] = colormap[val]; - xposition += xstep; - yposition += ystep; - - dest += 8; - count -= 8; + val = source[((y * ds_flatwidth) + x)]; + if (val != TRANSPARENTPIXEL) + *dest = colormap[val]; + dest++; + xposition += xstep; + yposition += ystep; + } } - while (count--) + else { - val = ((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift); - val &= 4194303; - val = source[val]; - if (val != TRANSPARENTPIXEL) - *dest = colormap[val]; + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + // + // 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[0] = colormap[val]; + xposition += xstep; + yposition += ystep; - dest++; - xposition += xstep; - yposition += ystep; + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[1] = colormap[val]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[2] = colormap[val]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[3] = colormap[val]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[4] = colormap[val]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[5] = colormap[val]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[6] = colormap[val]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val != TRANSPARENTPIXEL) + dest[7] = colormap[val]; + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + *dest = colormap[val]; + dest++; + xposition += xstep; + yposition += ystep; + } } } @@ -1184,16 +1448,20 @@ void R_DrawSplat_8 (void) */ void R_DrawTranslucentSplat_8 (void) { - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; UINT8 *source; UINT8 *colormap; UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; - size_t count; - UINT8 val; + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest // can be used for the fraction part. This allows calculation of the memory address in the @@ -1202,79 +1470,107 @@ void R_DrawTranslucentSplat_8 (void) // bit per power of two (obviously) // Ok, because I was able to eliminate the variable spot below, this function is now FASTER // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = ds_yfrac << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; + if (ds_powersoftwo) + { + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + } source = ds_source; colormap = ds_colormap; dest = ylookup[ds_y] + columnofs[ds_x1]; - count = ds_x2 - ds_x1 + 1; - while (count >= 8) + if (!ds_powersoftwo) { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[0] = *(ds_transmap + (colormap[val] << 8) + dest[0]); - xposition += xstep; - yposition += ystep; + while (count-- && dest <= deststop) + { + fixed_t x = (xposition >> FRACBITS); + fixed_t y = (yposition >> FRACBITS); - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[1] = *(ds_transmap + (colormap[val] << 8) + dest[1]); - xposition += xstep; - yposition += ystep; + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[2] = *(ds_transmap + (colormap[val] << 8) + dest[2]); - xposition += xstep; - yposition += ystep; + x %= ds_flatwidth; + y %= ds_flatheight; - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[3] = *(ds_transmap + (colormap[val] << 8) + dest[3]); - xposition += xstep; - yposition += ystep; - - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[4] = *(ds_transmap + (colormap[val] << 8) + dest[4]); - xposition += xstep; - yposition += ystep; - - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[5] = *(ds_transmap + (colormap[val] << 8) + dest[5]); - xposition += xstep; - yposition += ystep; - - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[6] = *(ds_transmap + (colormap[val] << 8) + dest[6]); - xposition += xstep; - yposition += ystep; - - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - dest[7] = *(ds_transmap + (colormap[val] << 8) + dest[7]); - xposition += xstep; - yposition += ystep; - - dest += 8; - count -= 8; + val = source[((y * ds_flatwidth) + x)]; + if (val != TRANSPARENTPIXEL) + *dest = *(ds_transmap + (colormap[val] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } } - while (count--) + else { - val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]; - if (val != TRANSPARENTPIXEL) - *dest = *(ds_transmap + (colormap[val] << 8) + *dest); + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[0] = *(ds_transmap + (colormap[val] << 8) + dest[0]); + xposition += xstep; + yposition += ystep; - dest++; - xposition += xstep; - yposition += ystep; + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[1] = *(ds_transmap + (colormap[val] << 8) + dest[1]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[2] = *(ds_transmap + (colormap[val] << 8) + dest[2]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[3] = *(ds_transmap + (colormap[val] << 8) + dest[3]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[4] = *(ds_transmap + (colormap[val] << 8) + dest[4]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[5] = *(ds_transmap + (colormap[val] << 8) + dest[5]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[6] = *(ds_transmap + (colormap[val] << 8) + dest[6]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + dest[7] = *(ds_transmap + (colormap[val] << 8) + dest[7]); + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val != TRANSPARENTPIXEL) + *dest = *(ds_transmap + (colormap[val] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } } } @@ -1283,15 +1579,20 @@ void R_DrawTranslucentSplat_8 (void) */ void R_DrawTranslucentSpan_8 (void) { - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; UINT8 *source; UINT8 *colormap; UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; - size_t count; + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest // can be used for the fraction part. This allows calculation of the memory address in the @@ -1300,63 +1601,161 @@ void R_DrawTranslucentSpan_8 (void) // bit per power of two (obviously) // Ok, because I was able to eliminate the variable spot below, this function is now FASTER // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = ds_yfrac << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; + if (ds_powersoftwo) + { + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + } source = ds_source; colormap = ds_colormap; dest = ylookup[ds_y] + columnofs[ds_x1]; - count = ds_x2 - ds_x1 + 1; - while (count >= 8) + if (!ds_powersoftwo) { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - dest[0] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[0]); - xposition += xstep; - yposition += ystep; + while (count-- && dest <= deststop) + { + fixed_t x = (xposition >> FRACBITS); + fixed_t y = (yposition >> FRACBITS); - dest[1] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[1]); - xposition += xstep; - yposition += ystep; + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - dest[2] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[2]); - xposition += xstep; - yposition += ystep; + x %= ds_flatwidth; + y %= ds_flatheight; - dest[3] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[3]); - xposition += xstep; - yposition += ystep; - - dest[4] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[4]); - xposition += xstep; - yposition += ystep; - - dest[5] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[5]); - xposition += xstep; - yposition += ystep; - - dest[6] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[6]); - xposition += xstep; - yposition += ystep; - - dest[7] = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + dest[7]); - xposition += xstep; - yposition += ystep; - - dest += 8; - count -= 8; + val = ((y * ds_flatwidth) + x); + *dest = *(ds_transmap + (colormap[source[val]] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } } - while (count--) + else { - *dest = *(ds_transmap + (colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]] << 8) + *dest); - dest++; - xposition += xstep; - yposition += ystep; + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + dest[0] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[0]); + xposition += xstep; + yposition += ystep; + + dest[1] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[1]); + xposition += xstep; + yposition += ystep; + + dest[2] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[2]); + xposition += xstep; + yposition += ystep; + + dest[3] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[3]); + xposition += xstep; + yposition += ystep; + + dest[4] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[4]); + xposition += xstep; + yposition += ystep; + + dest[5] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[5]); + xposition += xstep; + yposition += ystep; + + dest[6] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[6]); + xposition += xstep; + yposition += ystep; + + dest[7] = *(ds_transmap + (colormap[source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]] << 8) + dest[7]); + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + *dest = *(ds_transmap + (colormap[source[val]] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } } } +#ifndef NOWATER +void R_DrawTranslucentWaterSpan_8(void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + + UINT8 *source; + UINT8 *colormap; + UINT8 *dest; + UINT8 *dsrc; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + + xposition = ds_xfrac; yposition = (ds_yfrac + ds_waterofs); + xstep = ds_xstep; ystep = ds_ystep; + + // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest + // can be used for the fraction part. This allows calculation of the memory address in the + // texture with two shifts, an OR and one AND. (see below) + // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one + // bit per power of two (obviously) + // Ok, because I was able to eliminate the variable spot below, this function is now FASTER + // than the original span renderer. Whodathunkit? + if (ds_powersoftwo) + { + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + } + + source = ds_source; + colormap = ds_colormap; + dest = ylookup[ds_y] + columnofs[ds_x1]; + dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1; + + if (!ds_powersoftwo) + { + while (count-- && dest <= deststop) + { + fixed_t x = (xposition >> FRACBITS); + fixed_t y = (yposition >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + *dest++ = colormap[*(ds_transmap + (source[((y * ds_flatwidth) + x)] << 8) + *dsrc++)]; + xposition += xstep; + yposition += ystep; + } + } + else + { + while (count-- && dest <= deststop) + { + *dest++ = colormap[*(ds_transmap + (source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)] << 8) + *dsrc++)]; + xposition += xstep; + yposition += ystep; + } + } +} +#endif + /** \brief The R_DrawFogSpan_8 function Draws the actual span with fogging. */ diff --git a/src/r_main.c b/src/r_main.c index db351e991..9cce41288 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1182,6 +1182,8 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_cam_speed); CV_RegisterVar(&cv_cam_rotate); CV_RegisterVar(&cv_cam_rotspeed); + CV_RegisterVar(&cv_cam_orbit); + CV_RegisterVar(&cv_cam_adjust); CV_RegisterVar(&cv_cam2_dist); CV_RegisterVar(&cv_cam2_still); @@ -1189,6 +1191,8 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_cam2_speed); CV_RegisterVar(&cv_cam2_rotate); CV_RegisterVar(&cv_cam2_rotspeed); + CV_RegisterVar(&cv_cam2_orbit); + CV_RegisterVar(&cv_cam2_adjust); CV_RegisterVar(&cv_showhud); CV_RegisterVar(&cv_translucenthud); diff --git a/src/r_plane.c b/src/r_plane.c index 2f6f97240..db5fb0f24 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -127,91 +127,13 @@ void R_InitPlanes(void) // viewheight #ifndef NOWATER -static INT32 bgofs; +INT32 ds_bgofs; +INT32 ds_waterofs; + static INT32 wtofs=0; -static INT32 waterofs; static boolean itswater; #endif -#ifndef NOWATER -static void R_DrawTranslucentWaterSpan_8(void) -{ - UINT32 xposition; - UINT32 yposition; - UINT32 xstep, ystep; - - UINT8 *source; - UINT8 *colormap; - UINT8 *dest; - UINT8 *dsrc; - - size_t count; - - // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest - // can be used for the fraction part. This allows calculation of the memory address in the - // texture with two shifts, an OR and one AND. (see below) - // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one - // bit per power of two (obviously) - // Ok, because I was able to eliminate the variable spot below, this function is now FASTER - // than the original span renderer. Whodathunkit? - xposition = ds_xfrac << nflatshiftup; yposition = (ds_yfrac + waterofs) << nflatshiftup; - xstep = ds_xstep << nflatshiftup; ystep = ds_ystep << nflatshiftup; - - source = ds_source; - colormap = ds_colormap; - dest = ylookup[ds_y] + columnofs[ds_x1]; - dsrc = screens[1] + (ds_y+bgofs)*vid.width + ds_x1; - count = ds_x2 - ds_x1 + 1; - - while (count >= 8) - { - // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't - // have the uber complicated math to calculate it now, so that was a memory write we didn't - // need! - dest[0] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest[1] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest[2] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest[3] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest[4] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest[5] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest[6] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest[7] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - - dest += 8; - count -= 8; - } - while (count--) - { - *dest++ = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dsrc++)]; - xposition += xstep; - yposition += ystep; - } -} -#endif - void R_MapPlane(INT32 y, INT32 x1, INT32 x2) { angle_t angle, planecos, planesin; @@ -258,17 +180,17 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) { const INT32 yay = (wtofs + (distance>>9) ) & 8191; // ripples da water texture - bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS; + ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS; angle = (currentplane->viewangle + currentplane->plangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; angle = (angle + 2048) & 8191; // 90 degrees - ds_xfrac += FixedMul(FINECOSINE(angle), (bgofs<=viewheight) - bgofs = viewheight-y-1; - if (y+bgofs<0) - bgofs = -y; + if (y+ds_bgofs>=viewheight) + ds_bgofs = viewheight-y-1; + if (y+ds_bgofs<0) + ds_bgofs = -y; } #endif @@ -680,7 +602,7 @@ void R_DrawPlanes(void) } } #ifndef NOWATER - waterofs = (leveltime & 1)*16384; + ds_waterofs = (leveltime & 1)*16384; wtofs = leveltime * 140; #endif } @@ -728,13 +650,169 @@ static void R_DrawSkyPlane(visplane_t *pl) } } +boolean R_CheckPowersOfTwo(void) +{ + boolean wpow2 = (!(ds_flatwidth & (ds_flatwidth - 1))); + boolean hpow2 = (!(ds_flatheight & (ds_flatheight - 1))); + + // Initially, the flat isn't powers-of-two-sized. + ds_powersoftwo = false; + + // But if the width and height are powers of two, + // and are EQUAL, then it's okay :] + if ((ds_flatwidth == ds_flatheight) && (wpow2 && hpow2)) + ds_powersoftwo = true; + + // Just return ds_powersoftwo. + return ds_powersoftwo; +} + +void R_CheckFlatLength(size_t size) +{ + switch (size) + { + case 4194304: // 2048x2048 lump + nflatmask = 0x3FF800; + nflatxshift = 21; + nflatyshift = 10; + nflatshiftup = 5; + ds_flatwidth = ds_flatheight = 2048; + break; + case 1048576: // 1024x1024 lump + nflatmask = 0xFFC00; + nflatxshift = 22; + nflatyshift = 12; + nflatshiftup = 6; + ds_flatwidth = ds_flatheight = 1024; + break; + case 262144:// 512x512 lump + nflatmask = 0x3FE00; + nflatxshift = 23; + nflatyshift = 14; + nflatshiftup = 7; + ds_flatwidth = ds_flatheight = 512; + break; + case 65536: // 256x256 lump + nflatmask = 0xFF00; + nflatxshift = 24; + nflatyshift = 16; + nflatshiftup = 8; + ds_flatwidth = ds_flatheight = 256; + break; + case 16384: // 128x128 lump + nflatmask = 0x3F80; + nflatxshift = 25; + nflatyshift = 18; + nflatshiftup = 9; + ds_flatwidth = ds_flatheight = 128; + break; + case 1024: // 32x32 lump + nflatmask = 0x3E0; + nflatxshift = 27; + nflatyshift = 22; + nflatshiftup = 11; + ds_flatwidth = ds_flatheight = 32; + break; + default: // 64x64 lump + nflatmask = 0xFC0; + nflatxshift = 26; + nflatyshift = 20; + nflatshiftup = 10; + ds_flatwidth = ds_flatheight = 64; + break; + } +} + +static UINT8 *R_GetPatchFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng) +{ + UINT8 *flat; + textureflat_t *texflat = &texflats[levelflat->texturenum]; + patch_t *patch = NULL; + boolean texturechanged = (leveltexture ? (levelflat->texturenum != levelflat->lasttexturenum) : false); + + // Check if the texture changed. + if (leveltexture && (!texturechanged)) + { + if (texflat != NULL && texflat->flat) + { + flat = texflat->flat; + ds_flatwidth = texflat->width; + ds_flatheight = texflat->height; + texturechanged = false; + } + else + texturechanged = true; + } + + // If the texture changed, or the patch doesn't exist, convert either of them to a flat. + if (levelflat->flatpatch == NULL || texturechanged) + { + if (leveltexture) + { + texture_t *texture = textures[levelflat->texturenum]; + texflat->width = ds_flatwidth = texture->width; + texflat->height = ds_flatheight = texture->height; + + texflat->flat = Z_Malloc(ds_flatwidth * ds_flatheight, PU_LEVEL, NULL); + memset(texflat->flat, TRANSPARENTPIXEL, ds_flatwidth * ds_flatheight); + R_TextureToFlat(levelflat->texturenum, texflat->flat); + flat = texflat->flat; + + levelflat->flatpatch = flat; + levelflat->width = ds_flatwidth; + levelflat->height = ds_flatheight; + } + else + { + patch = (patch_t *)ds_source; +#ifndef NO_PNG_LUMPS + if (ispng) + { + levelflat->flatpatch = R_PNGToFlat(levelflat, ds_source, W_LumpLength(levelflat->lumpnum)); + levelflat->topoffset = levelflat->leftoffset = 0; + ds_flatwidth = levelflat->width; + ds_flatheight = levelflat->height; + } + else +#endif + { + levelflat->width = ds_flatwidth = SHORT(patch->width); + levelflat->height = ds_flatheight = SHORT(patch->height); + + levelflat->topoffset = patch->topoffset * FRACUNIT; + levelflat->leftoffset = patch->leftoffset * FRACUNIT; + + levelflat->flatpatch = Z_Malloc(ds_flatwidth * ds_flatheight, PU_LEVEL, NULL); + memset(levelflat->flatpatch, TRANSPARENTPIXEL, ds_flatwidth * ds_flatheight); + R_PatchToFlat(patch, levelflat->flatpatch); + } + flat = levelflat->flatpatch; + } + } + else + { + flat = levelflat->flatpatch; + ds_flatwidth = levelflat->width; + ds_flatheight = levelflat->height; + + xoffs += levelflat->leftoffset; + yoffs += levelflat->topoffset; + } + + levelflat->lasttexturenum = levelflat->texturenum; + return flat; +} + void R_DrawSinglePlane(visplane_t *pl) { + UINT8 *flat; INT32 light = 0; INT32 x; INT32 stop, angle; size_t size; ffloor_t *rover; + levelflat_t *levelflat; + boolean rawflat = false; if (!(pl->minx <= pl->maxx)) return; @@ -874,64 +952,51 @@ void R_DrawSinglePlane(visplane_t *pl) viewangle = pl->viewangle+pl->plangle; } - currentplane = pl; - - ds_source = (UINT8 *) - W_CacheLumpNum(levelflats[pl->picnum].lumpnum, - PU_STATIC); // Stay here until Z_ChangeTag - - size = W_LumpLength(levelflats[pl->picnum].lumpnum); - - switch (size) - { - case 4194304: // 2048x2048 lump - nflatmask = 0x3FF800; - nflatxshift = 21; - nflatyshift = 10; - nflatshiftup = 5; - break; - case 1048576: // 1024x1024 lump - nflatmask = 0xFFC00; - nflatxshift = 22; - nflatyshift = 12; - nflatshiftup = 6; - break; - case 262144:// 512x512 lump' - nflatmask = 0x3FE00; - nflatxshift = 23; - nflatyshift = 14; - nflatshiftup = 7; - break; - case 65536: // 256x256 lump - nflatmask = 0xFF00; - nflatxshift = 24; - nflatyshift = 16; - nflatshiftup = 8; - break; - case 16384: // 128x128 lump - nflatmask = 0x3F80; - nflatxshift = 25; - nflatyshift = 18; - nflatshiftup = 9; - break; - case 1024: // 32x32 lump - nflatmask = 0x3E0; - nflatxshift = 27; - nflatyshift = 22; - nflatshiftup = 11; - break; - default: // 64x64 lump - nflatmask = 0xFC0; - nflatxshift = 26; - nflatyshift = 20; - nflatshiftup = 10; - break; - } - xoffs = pl->xoffs; yoffs = pl->yoffs; planeheight = abs(pl->height - pl->viewz); + currentplane = pl; + levelflat = &levelflats[pl->picnum]; + size = W_LumpLength(levelflat->lumpnum); + ds_source = (UINT8 *)W_CacheLumpNum(levelflat->lumpnum, PU_STATIC); // Stay here until Z_ChangeTag + + // Check if the flat is actually a wall texture. + if (levelflat->texturenum != 0 && levelflat->texturenum != -1) + flat = R_GetPatchFlat(levelflat, true, false); +#ifndef NO_PNG_LUMPS + // Maybe it's a PNG?! + else if (R_IsLumpPNG(ds_source, size)) + flat = R_GetPatchFlat(levelflat, false, true); +#endif + // Maybe it's just a patch, then? + else if (R_CheckIfPatch(levelflat->lumpnum)) + flat = R_GetPatchFlat(levelflat, false, false); + // It's a raw flat. + else + { + rawflat = true; + R_CheckFlatLength(size); + flat = ds_source; + } + + Z_ChangeTag(ds_source, PU_CACHE); + ds_source = flat; + + if (ds_source == NULL) + return; + + // Raw flats always have dimensions that are powers-of-two numbers. + if (rawflat) + ds_powersoftwo = true; + // Otherwise, check if this texture or patch has such dimensions. + else if (R_CheckPowersOfTwo()) + { + R_CheckFlatLength(ds_flatwidth * ds_flatheight); + if (spanfunc == basespanfunc) + spanfunc = mmxspanfunc; + } + if (light >= LIGHTLEVELS) light = LIGHTLEVELS-1; @@ -945,60 +1010,63 @@ void R_DrawSinglePlane(visplane_t *pl) floatv3_t p, m, n; float ang; float vx, vy, vz; + float fudge = 0; // compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly // use this as a temp var to store P_GetZAt's return value each time fixed_t temp; - // Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -Red - const float fudge = ((1<plangle & (ANGLE_90-1)); yoffs *= 1; - if (hack) + if (ds_powersoftwo) { - /* - Essentially: We can't & the components along the regular axes when the plane is rotated. - This is because the distance on each regular axis in order to loop is different. - We rotate them, & the components, add them together, & them again, and then rotate them back. - These three seperate & operations are done per axis in order to prevent overflows. - toast 10/04/17 - */ - const fixed_t cosinecomponent = FINECOSINE(hack>>ANGLETOFINESHIFT); - const fixed_t sinecomponent = FINESINE(hack>>ANGLETOFINESHIFT); + // Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -Red + fudge = ((1<>ANGLETOFINESHIFT); + const fixed_t sinecomponent = FINESINE(hack>>ANGLETOFINESHIFT); - const fixed_t modmask = ((1 << (32-nflatshiftup)) - 1); + const fixed_t modmask = ((1 << (32-nflatshiftup)) - 1); - fixed_t ox = (FixedMul(pl->slope->o.x,cosinecomponent) & modmask) - (FixedMul(pl->slope->o.y,sinecomponent) & modmask); - fixed_t oy = (-FixedMul(pl->slope->o.x,sinecomponent) & modmask) - (FixedMul(pl->slope->o.y,cosinecomponent) & modmask); + fixed_t ox = (FixedMul(pl->slope->o.x,cosinecomponent) & modmask) - (FixedMul(pl->slope->o.y,sinecomponent) & modmask); + fixed_t oy = (-FixedMul(pl->slope->o.x,sinecomponent) & modmask) - (FixedMul(pl->slope->o.y,cosinecomponent) & modmask); - temp = ox & modmask; - oy &= modmask; - ox = FixedMul(temp,cosinecomponent)+FixedMul(oy,-sinecomponent); // negative sine for opposite direction - oy = -FixedMul(temp,-sinecomponent)+FixedMul(oy,cosinecomponent); + temp = ox & modmask; + oy &= modmask; + ox = FixedMul(temp,cosinecomponent)+FixedMul(oy,-sinecomponent); // negative sine for opposite direction + oy = -FixedMul(temp,-sinecomponent)+FixedMul(oy,cosinecomponent); - temp = xoffs; - xoffs = (FixedMul(temp,cosinecomponent) & modmask) + (FixedMul(yoffs,sinecomponent) & modmask); - yoffs = (-FixedMul(temp,sinecomponent) & modmask) + (FixedMul(yoffs,cosinecomponent) & modmask); + temp = xoffs; + xoffs = (FixedMul(temp,cosinecomponent) & modmask) + (FixedMul(yoffs,sinecomponent) & modmask); + yoffs = (-FixedMul(temp,sinecomponent) & modmask) + (FixedMul(yoffs,cosinecomponent) & modmask); - temp = xoffs & modmask; - yoffs &= modmask; - xoffs = FixedMul(temp,cosinecomponent)+FixedMul(yoffs,-sinecomponent); // ditto - yoffs = -FixedMul(temp,-sinecomponent)+FixedMul(yoffs,cosinecomponent); + temp = xoffs & modmask; + yoffs &= modmask; + xoffs = FixedMul(temp,cosinecomponent)+FixedMul(yoffs,-sinecomponent); // ditto + yoffs = -FixedMul(temp,-sinecomponent)+FixedMul(yoffs,cosinecomponent); - xoffs -= (pl->slope->o.x - ox); - yoffs += (pl->slope->o.y + oy); + xoffs -= (pl->slope->o.x - ox); + yoffs += (pl->slope->o.y + oy); + } + else + { + xoffs &= ((1 << (32-nflatshiftup))-1); + yoffs &= ((1 << (32-nflatshiftup))-1); + xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); + yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); + } + xoffs = (fixed_t)(xoffs*fudge); + yoffs = (fixed_t)(yoffs/fudge); } - else - { - xoffs &= ((1 << (32-nflatshiftup))-1); - yoffs &= ((1 << (32-nflatshiftup))-1); - xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); - yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); - } - - xoffs = (fixed_t)(xoffs*fudge); - yoffs = (fixed_t)(yoffs/fudge); vx = FIXED_TO_FLOAT(pl->viewx+xoffs); vy = FIXED_TO_FLOAT(pl->viewy-yoffs); @@ -1033,13 +1101,16 @@ void R_DrawSinglePlane(visplane_t *pl) temp = P_GetZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(cos(ang)), pl->viewy - FLOAT_TO_FIXED(sin(ang))); n.y = FIXED_TO_FLOAT(temp) - zeroheight; - m.x /= fudge; - m.y /= fudge; - m.z /= fudge; + if (ds_powersoftwo) + { + m.x /= fudge; + m.y /= fudge; + m.z /= fudge; - n.x *= fudge; - n.y *= fudge; - n.z *= fudge; + n.x *= fudge; + n.y *= fudge; + n.z *= fudge; + } // Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using. #define CROSS(d, v1, v2) \ @@ -1056,13 +1127,26 @@ void R_DrawSinglePlane(visplane_t *pl) ds_sz.z *= focallengthf; // Premultiply the texture vectors with the scale factors -#define SFMULT 65536.f*(1<patch, PU_CACHE); + patch_t *patch = W_CachePatchNum(vis->patch, PU_CACHE); fixed_t this_scale = vis->mobj->scale; INT32 x1, x2; INT64 overflow_test; @@ -870,7 +883,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) INT64 overflow_test; //Fab : R_InitSprites now sets a wad lump number - patch = W_CacheLumpNum(vis->patch, PU_CACHE); + patch = W_CachePatchNum(vis->patch, PU_CACHE); if (!patch) return; @@ -2511,7 +2524,7 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) if (!skin) return 0; - if ((unsigned)(spr2 & ~FF_SPR2SUPER) >= free_spr2) + if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2) return 0; while (!(skin->sprites[spr2].numframes) @@ -2603,6 +2616,8 @@ static void Sk_SetDefaultValue(skin_t *skin) skin->followitem = 0; skin->highresscale = FRACUNIT; + skin->contspeed = 17; + skin->contangle = 0; skin->availability = 0; @@ -2869,6 +2884,8 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski for (sprite2 = 0; sprite2 < free_spr2; sprite2++) R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[sprite2], wadnum, *lump, *lastlump); + if (skin->sprites[0].numframes == 0) + I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]); } // returns whether found appropriate property @@ -2907,6 +2924,8 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) GETINT(thrustfactor) GETINT(accelstart) GETINT(acceleration) + GETINT(contspeed) + GETINT(contangle) #undef GETINT #define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value); diff --git a/src/r_things.h b/src/r_things.h index 9c3d16ab0..0fa9c4b94 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -122,6 +122,8 @@ typedef struct UINT8 prefoppositecolor; // if 0 use tables instead fixed_t highresscale; // scale of highres, default is 0.5 + UINT8 contspeed; // continue screen animation speed + UINT8 contangle; // initial angle on continue screen // specific sounds per skin sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table diff --git a/src/s_sound.c b/src/s_sound.c index 1c6cd5ef1..299e4b889 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -108,7 +108,9 @@ 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}; static consvar_t surround = {"surround", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_resetmusic = {"resetmusic", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_resetmusic = {"resetmusic", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_resetmusicbyheader = {"resetmusicbyheader", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; // Sound system toggles, saved into the config consvar_t cv_gamedigimusic = {"digimusic", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, GameDigiMusic_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -275,6 +277,7 @@ void S_RegisterSoundStuff(void) CV_RegisterVar(&surround); CV_RegisterVar(&cv_samplerate); CV_RegisterVar(&cv_resetmusic); + CV_RegisterVar(&cv_resetmusicbyheader); CV_RegisterVar(&cv_gamesounds); CV_RegisterVar(&cv_gamedigimusic); CV_RegisterVar(&cv_gamemidimusic); @@ -1783,12 +1786,12 @@ static lumpnum_t S_GetMusicLumpNum(const char *mname) return W_GetNumForName(va("d_%s", mname)); else if (S_DigMusicDisabled() && S_DigExists(mname)) { - CONS_Alert(CONS_NOTICE, "Digital music is disabled!\n"); + //CONS_Alert(CONS_NOTICE, "Digital music is disabled!\n"); return LUMPERROR; } else if (S_MIDIMusicDisabled() && S_MIDIExists(mname)) { - CONS_Alert(CONS_NOTICE, "MIDI music is disabled!\n"); + //CONS_Alert(CONS_NOTICE, "MIDI music is disabled!\n"); return LUMPERROR; } else @@ -2096,7 +2099,7 @@ void S_StartEx(boolean reset) mapmusposition = mapheaderinfo[gamemap-1]->muspos; } - if (cv_resetmusic.value || reset) + if (RESETMUSIC || reset) S_StopMusic(); S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); diff --git a/src/s_sound.h b/src/s_sound.h index e0737eff7..48128527c 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -31,7 +31,16 @@ openmpt_module *openmpt_mhandle; extern consvar_t stereoreverse; extern consvar_t cv_soundvolume, cv_closedcaptioning, cv_digmusicvolume, cv_midimusicvolume; extern consvar_t cv_numChannels; + extern consvar_t cv_resetmusic; +extern consvar_t cv_resetmusicbyheader; + +#define RESETMUSIC (!modeattacking && \ + (cv_resetmusicbyheader.value ? \ + (mapheaderinfo[gamemap-1]->musforcereset != -1 ? mapheaderinfo[gamemap-1]->musforcereset : cv_resetmusic.value) \ + : cv_resetmusic.value) \ + ) + extern consvar_t cv_gamedigimusic; extern consvar_t cv_gamemidimusic; extern consvar_t cv_gamesounds; diff --git a/src/screen.c b/src/screen.c index fc3f5b8e8..547036a60 100644 --- a/src/screen.c +++ b/src/screen.c @@ -49,6 +49,7 @@ void (*fuzzcolfunc)(void); // standard fuzzy effect column drawer void (*transcolfunc)(void); // translation column drawer void (*shadecolfunc)(void); // smokie test.. void (*spanfunc)(void); // span drawer, use a 64x64 tile +void (*mmxspanfunc)(void); // span drawer in MMX assembly void (*splatfunc)(void); // span drawer w/ transparency void (*basespanfunc)(void); // default span func for color mode void (*transtransfunc)(void); // translucent translated column drawer @@ -112,7 +113,7 @@ void SCR_SetMode(void) // if (true)//vid.bpp == 1) //Always run in 8bpp. todo: remove all 16bpp code? { - spanfunc = basespanfunc = R_DrawSpan_8; + spanfunc = basespanfunc = mmxspanfunc = R_DrawSpan_8; splatfunc = R_DrawSplat_8; transcolfunc = R_DrawTranslatedColumn_8; transtransfunc = R_DrawTranslatedTranslucentColumn_8; @@ -133,7 +134,7 @@ void SCR_SetMode(void) //fuzzcolfunc = R_DrawTranslucentColumn_8_ASM; walldrawerfunc = R_DrawWallColumn_8_MMX; twosmultipatchfunc = R_Draw2sMultiPatchColumn_8_MMX; - spanfunc = basespanfunc = R_DrawSpan_8_MMX; + mmxspanfunc = R_DrawSpan_8_MMX; } else { diff --git a/src/screen.h b/src/screen.h index 7aa6fdb63..3554b5520 100644 --- a/src/screen.h +++ b/src/screen.h @@ -123,6 +123,7 @@ extern void (*transcolfunc)(void); extern void (*shadecolfunc)(void); extern void (*spanfunc)(void); extern void (*basespanfunc)(void); +extern void (*mmxspanfunc)(void); extern void (*splatfunc)(void); extern void (*transtransfunc)(void); extern void (*twosmultipatchfunc)(void); diff --git a/src/sdl/IMG_xpm.c b/src/sdl/IMG_xpm.c index af76ec1dd..43fb4ded2 100644 --- a/src/sdl/IMG_xpm.c +++ b/src/sdl/IMG_xpm.c @@ -1,6 +1,6 @@ /* SDL_image: An example image loading library for use with SDL - Copyright (C) 1997-2018 Sam Lantinga + Copyright (C) 1997-2019 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -34,7 +34,7 @@ * * Besides the standard API, also provides * - * SDL_Surface *IMG_ReadXPMFromArray(char **xpm) + * SDL_Surface *IMG_ReadXPMFromArray(const char **xpm) * * that reads the image data from an XPM file included in the C source. * @@ -88,8 +88,8 @@ struct color_hash { struct hash_entry **table; struct hash_entry *entries; /* array of all entries */ struct hash_entry *next_free; - int size; - int maxnum; + size_t size; + size_t maxnum; }; static int hash_key(const char *key, int cpp, int size) @@ -103,14 +103,14 @@ static int hash_key(const char *key, int cpp, int size) return hash & (size - 1); } -static struct color_hash *create_colorhash(int maxnum) +static struct color_hash *create_colorhash(size_t maxnum) { - int bytes, s; + size_t bytes, s; struct color_hash *hash; /* we know how many entries we need, so we can allocate everything here */ - hash = (struct color_hash *)SDL_malloc(sizeof *hash); + hash = (struct color_hash *)SDL_calloc(1, sizeof(*hash)); if (!hash) return NULL; @@ -119,15 +119,29 @@ static struct color_hash *create_colorhash(int maxnum) ; hash->size = s; hash->maxnum = maxnum; + bytes = hash->size * sizeof(struct hash_entry **); - hash->entries = NULL; /* in case malloc fails */ - hash->table = (struct hash_entry **)SDL_malloc(bytes); + /* Check for overflow */ + if ((bytes / sizeof(struct hash_entry **)) != hash->size) { + IMG_SetError("memory allocation overflow"); + SDL_free(hash); + return NULL; + } + hash->table = (struct hash_entry **)SDL_calloc(1, bytes); if (!hash->table) { SDL_free(hash); return NULL; } - SDL_memset(hash->table, 0, bytes); - hash->entries = (struct hash_entry *)SDL_malloc(maxnum * sizeof(struct hash_entry)); + + bytes = maxnum * sizeof(struct hash_entry); + /* Check for overflow */ + if ((bytes / sizeof(struct hash_entry)) != maxnum) { + IMG_SetError("memory allocation overflow"); + SDL_free(hash->table); + SDL_free(hash); + return NULL; + } + hash->entries = (struct hash_entry *)SDL_calloc(1, bytes); if (!hash->entries) { SDL_free(hash->table); SDL_free(hash); @@ -138,7 +152,7 @@ static struct color_hash *create_colorhash(int maxnum) } static int add_colorhash(struct color_hash *hash, - char *key, int cpp, Uint32 color) + const char *key, int cpp, Uint32 color) { int index = hash_key(key, cpp, hash->size); struct hash_entry *e = hash->next_free++; @@ -995,10 +1009,11 @@ static SDL_Surface *load_xpm(const char **xpm, SDL_RWops *src) { Sint64 start = 0; SDL_Surface *image = NULL; - int index; + size_t index; int x, y; - int w, h, ncolors, cpp; - int indexed; + int w, h, cpp; + size_t ncolors; + size_t indexed; Uint8 *dst; struct color_hash *colors = NULL; SDL_Color *im_colors = NULL; @@ -1029,12 +1044,17 @@ static SDL_Surface *load_xpm(const char **xpm, SDL_RWops *src) * Right now we don't use the hotspots but it should be handled * one day. */ - if (SDL_sscanf(line, "%d %d %d %d", &w, &h, &ncolors, &cpp) != 4 + if (SDL_sscanf(line, "%d %d %lu %d", &w, &h, &ncolors, &cpp) != 4 || w <= 0 || h <= 0 || ncolors <= 0 || cpp <= 0) { error = "Invalid format description"; goto done; } + /* Check for allocation overflow */ + if ((size_t)(ncolors * cpp)/cpp != ncolors) { + error = "Invalid color specification"; + goto done; + } keystrings = (char *)SDL_malloc(ncolors * cpp); if (!keystrings) { error = "Out of memory"; @@ -1102,8 +1122,9 @@ static SDL_Surface *load_xpm(const char **xpm, SDL_RWops *src) c->g = (Uint8)(rgb >> 8); c->b = (Uint8)(rgb); pixel = index; - } else + } else { pixel = rgb; + } add_colorhash(colors, nextkey, cpp, pixel); nextkey += cpp; if (rgb == 0xffffffff) @@ -1192,7 +1213,7 @@ SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src) return(NULL); } -SDL_Surface *IMG_ReadXPMFromArray(char **xpm) +SDL_Surface *IMG_ReadXPMFromArray(const char **xpm) { return NULL; } diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm index 1d0f9d314..2180d782c 100644 --- a/src/sdl/SDL_icon.xpm +++ b/src/sdl/SDL_icon.xpm @@ -1,163 +1,99 @@ /* XPM */ -const char * SDL_icon_xpm[] = { -"96 96 64 1", +static const char *SDL_icon_xpm[] = { +"64 64 32 1", " c None", -". c #040656", -"+ c #0100B2", -"@ c #04056E", -"# c #0000BD", -"$ c #0B0C09", -"% c #0B0D26", -"& c #090C42", -"* c #060AA7", -"= c #1604DA", -"- c #020CD5", -"; c #100F8D", -"> c #040DE4", -", c #11129B", -"' c #1D1A83", -") c #2A10FD", -"! c #1318FA", -"~ c #25225B", -"{ c #252271", -"] c #312E2B", -"^ c #33334D", -"/ c #363775", -"( c #3D3B69", -"_ c #3A3B8B", -": c #373AFF", -"< c #4142AA", -"[ c #4B4864", -"} c #4D4B4A", -"| c #60492F", -"1 c #4F4C57", -"2 c #4A4A9E", -"3 c #4F4E85", -"4 c #474ADE", -"5 c #4E4FFE", -"6 c #5D5CB3", -"7 c #686663", -"8 c #666682", -"9 c #676875", -"0 c #66659E", -"a c #8B6538", -"b c #6465D5", -"c c #7F694F", -"d c #6767FF", -"e c #7272FF", -"f c #91795C", -"g c #7677FD", -"h c #828396", -"i c #A78153", -"j c #888989", -"k c #8D897E", -"l c #9190FD", -"m c #CA9048", -"n c #C09968", -"o c #A9A8A1", -"p c #A6A8B0", -"q c #B0B1FB", -"r c #EEAC61", -"s c #E3B478", -"t c #C3C4BE", -"u c #FFC68C", -"v c #FCCD90", -"w c #D4D7D3", -"x c #E3E5E0", -"y c #FCFFFB", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ttj7777777joot ", -" 9hh8830000088hh9 ", -" 9888(//__-*{^kt ", -" &,5b60^ (02*{} ", -" tp,-)!5egb3} ~_<4dgggeeeeeeeeeeeeeegb6/_2[amusf'#!<_'>))))))))))))!)>+{~ ", -" p;-))!5gb2^^'#5eggeeeeeeeeeeeeeeegg6/_23amrusi{#!+;;>))))))))))))))!!-'8p ", -" tp'#!)):d6(@*>5egeeeeeeeeeeeeeeeegg6_/<(amrrvvn{+)-,;>))))))!!!!!!)))!!>,~j ", -" p;#!))-'{'+-5eggeeeeeeeeeeeeeeeegb222(cmrruvvn{+)>,@>!)!!)!!>>>>======>-,/8 ", -" ;#)!-*.;-!5eggeeeeeeeeeeeeeeeegb2_<6|mrrsvvvn{+)!,.-!!!!>>=--######+++-#@(k ", -" h@-)+@.*>!5egeeeeeeeeeeeeeeeeeegb_>--###++++++###+;@{(9j ", -" kh,#+@@,>!:dggeeeeeeeeeeeeeeeeeeebbb_]mrruuvvsf'#)!*.+-###+++++++##+*;'3(&^9 ", -" 8*,@@*)):dggeeeeeeeeeeeeeeeeeeeeggg<(|iruvvvsc,=!!*.;*++++++++###+,@&1o ", -" 8@@@-!)!5eeeeeeeeeeeeeeeeeeeeeeeeeggb2[csvvvn^#)!!+@;*#+++++###*@~[ ", -" 9&@*!)):5geeeeeeeeeeeeeeeeeeeeeeeeegge637nsvf{>))!+;;*-######*;{.^ ", -" 9%;!!)):dgeeeeeeeeeeeeeeeeeeeeeeeeeeeggb_1ir7;>))!+;;,++++++*'(} ", -" 9{+!))!5egeeeeeeeeeeeeeeeeeddddeeeeeeeege2}|~#!))!#;@...@@@.^hp ", -" 8,=!))):dggeeeeeeeeeeeeeeeeggggeeeeeeeeggb_~,>!))!+@@@;;;;@&^o ", -" }(-)))))!:eegeeeeeeeeeeeeeegllllgeeeeeeeegd5+=))))!+;,#>--#,'/hj ", -" o8.>))))))!:dgggeeeeeeeeeeellqqqqlgeeeeggg5:!!!)))))-*+>)!:55db631 ", -" p8<*!)))))))!:5deggggggeeeegqqqqqqqqlggged5:!))))))))>->!!:5ddeegb3/ ", -" oh'#!))))))))))!:ddeeeeeeeeglqqqqqqqqlgedd:!)))))))))))))!:dggggeggg239 ", -" ^*>!))!)))))))))!::55dddeegglll600333_4:!!)))))))))))))):dggeeeeeeggb6(9o ", -" ~+=-+#>))))))))))!!!:::::5554<3889988[/,=)))))))))))))):5gggeeeeeeeggb6087 ", -" ~**@~'+>!))))))))))))))))!!>*{1kkooook7(,-!)))))))))))!:5deeeeeeeeeeeggb289 ", -" ~,'1o7(*>!))))))))))))))))=,[jtttwxxxwto^;>!))))))))))!!!::5deggeeeeeeegbb3] ", -" ~@/oxt7'#))))))))))))))))=,3ktwxxyyyyyyxk/+!))))))))))))))!:::5degggeeegggb3^ ", -" ^&8xyyt^,)))))))))))))))>,3otwxyyyyyyyyyxh'>)))))))))))))))))):5ddeeeeeeeggb3^ ", -" 771pyyyx7'=!)))))))))))!!#(jtxxyyyyyyyyyyyt3-)))))))))))))))))))!!::degggeeegb2[o ", -" 77tyyyxk/+!!)))))))))))-;9owxyyyyyyyyyyyywh*>)))))))))))))))))))))!::5ddgggggb68j ", -" owyyyyt8;>))))))))))))*(otwyyyyyyyyyyyyyxp'-)))))))))))))))))))))))!!:5deeeggg_8j ", -" jtxyyyyxh'>)))))))))!!#_ktxyyyyyyyyyyyyyyyt_+))))))))))))))))))))))))))!!:5deggg63j ", -" 7jwyyyyyyp/=))))))))))>,3owxyyyyyyyyyyyyyyyw/+))))))))))))))))))))))))))))!::5degb689 ", -" 7xyyyyyyo[#))))))))))-/jtwyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))!:5dgg_/ ", -" }xyyyyyyt9*=))))))))=*9owyyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))))!!:5d3} ", -" }xyyyyyywj'#!))))))!#@7oxyyyyyyyyyyyyyyyyyw/*)))))))))))))))))))))))))))))))))))!!:4/7 ", -" 7xyyyyyyxj&,!!))))!!,%}oyyyyyyyyyyyyyyyyyyw/*))))))))))))))))))))))))))))))))))))))>487 ", -" 7xyyyyyywk$@!!)))!!-.$]oyyyyyyyyyyyyyyyyyyw/+))))))))))))))))))))))))))))))!!!!))))!>' ", -" }xyyyyyywj$&+!!)!)>;%$]jyyyyyyyyyyyyyyyyyyt{#)))))))))))))))))))))!!!!!!))!)!!!!!!))!#' ", -" 7xyyyyyyt7$%@-!)!>*[]$$jyyyyyyyyyyyyyyyyyxp;-))))))))))))))))))!!!!!!!!!!!!>>>>>>>>>>!,^ ", -" 7xyyyyyyt}$][;-)=,(o7$$7yyyyyyyyyyyyyyyyyxp,-)))))))))))!!!!)!!!!>>>>=-----########--=+'9 ", -" jwyyyyyyo}$}o(';@~7wj$$7yyyyyyyyyyyyyyyyywh*>)))))))))))!>>>=>=---#####+########+++***;@17 ", -" otxyyyyyt}$7t7}1}7kw7$$7yyyyyyyyyyyyyyyyyt0-)))))))))!!!>--####+++++++++++++##+***,;''.&] ", -" ooowyyyyyt}$}j7owwojo}$$jyyyyyyyyyyyyyyyyyp2>)))))))!!!=##++++++++++++++###+*;@.~[8[9hph ", -" ojtyyyyywj$$}jwyyxo}$$]jyyyyyyyyyyyyyyyyyp'>))))))!>>-#++++++++++++####+,;'_3/&^}77kot ", -" 7tyyyyyxo]$$oxyyyt]$$}tyyyyyyyyyyyyyyyyx0*!)))!!!>-#++++++++++++#+##+*;.&1ko ", -" 7tyyyyyyx7]}xyyyyxj}]oxyyyyyyyyyyyyyyyyp<=)!!!!>-#++++++++++++####*;.(8h ", -" owxyxxyytooywptwwtppxyyyyyyyyyyyyyyyxp3,-=!)!>-#++++++++++###+*,'_{&1k ", -" jtwwttwtwwtj7kjowxyyyyyyyyyyyyyyyyxt7~'',+>=#+++++++++++###*;@&^j ", -" ]joojj7}]}]|innfc7jtwyyyyyyyyyyyxtjcfnnnf[@*#+++++++++###+@.&%% ", -" ]$}77}}$$$$]fsssnnifkkotwwwwwwwtpjkfinvvvsi}@*#++++++###*;@.@@&[ ", -" o7$]]]]]$$]|isvvvvvusifckopppopok7cisvvvvvvvn(,#++++++#+*@.&@*#;3o ", -" }}$]|||fnnsvvvuvvvuuvvsniffffffnnsvvvvuuuvvvc{*+#++##*@&.@*+#--<7 ", -" }]cninsuvvvvuuuuuuvvvvusnnnnnssuvvvvvuuuuvvc~*+#+++*@.@;*##=>>,^ ", -" 7fvvvvvvuuuuuuuuuuuuvvvvvvvvvvvuuuuuuuuuvvc~*+#+#+,.@*###->!!*~ ", -" pkivvvvuuuuuuuuuuuuuuuvvvvvvvvuuuvsnsuuuvvf~*+#++++*+++->!!)!#. ", -" kfsuvvuuuuuuuuuuuuuuuuuuuuuuuuuvvnfsuvuvvc{++#++++###->!!))!-;h ", -" kisvvvuuuuuuuuuuuuuuuuuuuuuuuvvvicsvvvvs1@##+++++++#>!!))))=,ho ", -" 7imuvvvuuuuuuuuuuuuuuuuuuuuvusfcivvuvvn~;##+++++++#>!!))))!#8k ", -" cimruuuuuvuuuuuuuuuuuuuuuuvsnfisuvvvsc@*#+++++++++#>!!))))-3} ", -" 7amrruuuuuuuuuuuuuuuuuuuuvsnnsvvuvvi^,##++++++++++#>!!)))>/^ ", -" kfamrruuuuvvvuuuuuuuuuuuuuvvvvvvvn1@+#++++++++++++#>!)))>{~ ", -" 7|iimrrruuuuuuuuuuuuuuuuvvvvuusn1'+#########++++++->!))>; ", -" 7cammrrrrruuuuuuvvvvvuuuuurrm|.*-#+#######+###+++->!!!*' ", -" ookcaimmrrrrrruuuuurrrrrmi|]%.@@@@@;,*,*+########->!!*6o ", -" p7}|ainiimmmmmmmmmmminnia|$%.....{3322_{''',,**+#=!!#6k ", -" j7||aaiiiiiaa||7j ookok711^&.';,*+=!>> c #2325EC", +", c #3C3883", +"' c #3D3A9E", +") c #5B5170", +"! c #4B4CFF", +"~ c #795339", +"{ c #5E5B5C", +"] c #5F5ED3", +"^ c #5E5EFB", +"/ c #7271FF", +"( c #B37F5D", +"_ c #8F8883", +": c #8887FF", +"< c #D59E76", +"[ c #ABABA9", +"} c #A9AAFF", +"| c #C1C3C1", +"1 c #FAC296", +"2 c #D4D6D3", +"3 c #F9FCF8", +" ", +" ", +" #***,,,**** ", +" *,,]]]]]]]]]]]]]',,** ", +" *,']//////////////////]]',* ", +" *,']/////////////////////////]'% ", +" *,]////////////////////^^!!>>>>>>>$+ ", +" *,]////////////////////!>---------->=@% ", +" * ,]///////////////////]^>------->==@@@$.# ", +" +', *']//////////////////],,,=---->=@@@@@$.% ", +" #.=^'* ,]//////////////////],']^]$--=@@@@@@@$+# ", +" %$=-^'* ,]/////////////////],]/!>-^'=@@@@@@@$.% ", +" +$=->/,*,//////////////////]'/^!,$-!,$@@@@@@$+* ", +" +@=--!''/////////////////]']^!,(()->%$@@@@@$+# ", +" +@=--='/////////////////]']^${(<<)->,$@@@@$% ", +" +@=->']/////////:::////]]/^'(<111)->,$@@@$% ", +" #+@@>$]////////::}}}://///!,(<1111)--%$@@.% ", +" #+@@$$^////////:}}}}}://^>$(<<1111)--+$@.% ", +" +@$.>^///////:}}}}}}:/^>->,(<111<'--+$$*# ", +" +$.=-!///////:}}}}}:^!-----@(111<@--+$,'],,* ", +" %+%=->^///////:}}}:!--------@(11(=--$=^////],* ", +" ,]]'>->^//////^^!!-----------'<1_>--@-!//////]'* ", +" '!->@--->>>>>>--->===>--------)<,-->@->^///////]', ", +" *$--->----------='){__{'>------>'=--=@-->!^///////],* ", +" %$.=---------->$)[22332[)=----------=>----->^^//////], ", +" %$_,--------->'_|3333333['----------=--------->!^////],# ", +" *'[{=--------'_2333333333_=---------------------->!^///,* ", +" #)[_@-------@_|33333333332,------------------------->!^/'* ", +" #)2[$------=)|333332|23333{>--------------------------->^'* ", +" {2|,------$[233333___3333_=----------------------------->$ ", +" ;22)=---->)|333332{2_2333[@-------------------------------$ ", +" &22{@----$_233333|{2||333|'--------------------------------$ ", +" &|3_.----,|333333[;2|[333|'--------------------------------=+ ", +" [3_%=--={2333333[&___333|'-------------------->>>====>>----@ ", +" _3[#$=@.[2333333[&&&_333[$------------->>==@@@@@@@@@@@@@@@==+", +" {3|;+$$)|3333333[&&&[333_=-------->==@@@@@@@@@@@@@@@$$$$.+++%", +" {23{*$${23333333|;&&|332)>----->=@@@@@@@@@@@@@@$$$.++%** ", +";{{;[3{&*)[333333333{&&|332,=---==@@@@@@@@@@@@$$.++%* ", +"{22_{|[;_|2333333333_&;233_$@@@@@@@@@@@@@@@@$$+%* ", +"&_|2{;{{[233333333332_[33[,$@@@@@@@@@@@@@$$+%# ", +" &;{&&&;~(_|3333333333332)$@@@@@@@@@@@@$.+%# ", +" &&&&&;(11([33333333332{$@@@@@@@@@@@$...$@$* ", +" &~((1111<[333333332{%.$@@@@@@@@@$$$$@=--$ ", +" ~<<11111<[33333|[_(<~,$@@@@@@@@@@@@@>-->. ", +" ;(<111111<(____(11111(+@@@@@@@@@@@@=----=% ", +" ~(<11111111<11111<(<<;$@@$$@@@@@@@=-----. ", +" ~(<1111111111111(~<1{$$$.$@@@@@@@=-----= ", +" ~(<1111111<<(((<11<*$+.$@@@@@@@@@>---->+ ", +" ;(<1111111<<1111<~%+$@@@@@@@@@@@=-----$ ", +" ~(<<111111111(~&*+$$$@@@@@@@@@@=----=% ", +" ;~((<<<<(~~; *%+$$@@@@@@@@@>----+ ", +" ;;; #%+$$@@@@@@@----. ", +" *+$$@@@@@=---@ ", +" *+$@@@@@>--= ", +" *.$@@@@-->% ", +" #%.$@@=->+ ", +" *+$@@>-$ ", +" %$@=-$ ", +" %.@>@ ", +" +=@ ", +" .. ", +" * ", +" ", +" "}; diff --git a/src/sdl/Srb2SDL.ico b/src/sdl/Srb2SDL.ico index 700276fd4..3b37433db 100644 Binary files a/src/sdl/Srb2SDL.ico and b/src/sdl/Srb2SDL.ico differ diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index f54f0d7c5..029febc05 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -26,6 +26,8 @@ #include #endif +#include "time.h" // For log timestamps + #ifdef HAVE_SDL #ifdef HAVE_TTF @@ -114,6 +116,7 @@ int main(int argc, char **argv) #endif { const char *logdir = NULL; + char logfile[MAX_WADPATH]; myargc = argc; myargv = argv; /// \todo pull out path to exe from this string @@ -125,15 +128,36 @@ int main(int argc, char **argv) #endif #endif - logdir = D_Home(); - #ifdef LOGMESSAGES + if (!M_CheckParm("-nolog")) + { + time_t my_time; + struct tm * timeinfo; + char buf[26]; + + logdir = D_Home(); + + my_time = time(NULL); + timeinfo = localtime(&my_time); + + strftime(buf, 26, "%Y-%m-%d %H-%M-%S", timeinfo); + strcpy(logfile, va("log-%s.txt", buf)); + #ifdef DEFAULTDIR - if (logdir) - logstream = fopen(va("%s/"DEFAULTDIR"/log.txt",logdir), "wt"); - else + if (logdir) + { + // Create dirs here because D_SRB2Main() is too late. + I_mkdir(va("%s%s"DEFAULTDIR, logdir, PATHSEP), 0755); + I_mkdir(va("%s%s"DEFAULTDIR"%slogs",logdir, PATHSEP, PATHSEP), 0755); + logstream = fopen(va("%s%s"DEFAULTDIR"%slogs%s%s",logdir, PATHSEP, PATHSEP, PATHSEP, logfile), "wt"); + } + else #endif - logstream = fopen("./log.txt", "wt"); + { + I_mkdir("."PATHSEP"logs"PATHSEP, 0755); + logstream = fopen(va("."PATHSEP"logs"PATHSEP"%s", logfile), "wt"); + } + } #endif //I_OutputMsg("I_StartupSystem() ...\n"); @@ -160,6 +184,10 @@ int main(int argc, char **argv) // startup SRB2 CONS_Printf("Setting up SRB2...\n"); D_SRB2Main(); +#ifdef LOGMESSAGES + if (!M_CheckParm("-nolog")) + CONS_Printf("Logfile: %s\n", logfile); +#endif CONS_Printf("Entering main game loop...\n"); // never return D_SRB2Loop(); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 98166a1ce..d7926e5b2 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -530,7 +530,7 @@ static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co) break; case VK_RETURN: entering_con_command = false; - // Fall through. + /* FALLTHRU */ default: event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char } @@ -827,6 +827,23 @@ void I_JoyScale2(void) JoyInfo2.scale = Joystick2.bGamepadStyle?1:cv_joyscale2.value; } +// Cheat to get the device index for a joystick handle +INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev) +{ + INT32 i, count = SDL_NumJoysticks(); + + for (i = 0; dev && i < count; i++) + { + SDL_Joystick *test = SDL_JoystickOpen(i); + if (test && test == dev) + return i; + else if (JoyInfo.dev != test && JoyInfo2.dev != test) + SDL_JoystickClose(test); + } + + return -1; +} + /** \brief Joystick 1 buttons states */ static UINT64 lastjoybuttons = 0; @@ -842,7 +859,7 @@ static UINT64 lastjoyhats = 0; */ -static void I_ShutdownJoystick(void) +void I_ShutdownJoystick(void) { INT32 i; event_t event; @@ -876,14 +893,8 @@ static void I_ShutdownJoystick(void) joystick_started = 0; JoyReset(&JoyInfo); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) - { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - if (cv_usejoystick.value == 0) - { - I_OutputMsg("I_Joystick: SDL's Joystick system has been shutdown\n"); - } - } + + // don't shut down the subsystem here, because hotplugging } void I_GetJoystickEvents(void) @@ -1024,74 +1035,66 @@ void I_GetJoystickEvents(void) */ -static int joy_open(const char *fname) +static int joy_open(int joyindex) { - int joyindex = atoi(fname); + SDL_Joystick *newdev = NULL; int num_joy = 0; - int i; - if (joystick_started == 0 && joystick2_started == 0) + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) - { - CONS_Printf(M_GetText("Couldn't initialize gamepad: %s\n"), SDL_GetError()); - return -1; - } - else - { - num_joy = SDL_NumJoysticks(); - } + CONS_Printf(M_GetText("Joystick subsystem not started\n")); + return -1; + } - if (num_joy < joyindex) - { - CONS_Printf("Cannot use gamepad #%d/(%s), it doesn't exist\n",joyindex,fname); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - I_ShutdownJoystick(); - return -1; - } - } - else - { - JoyReset(&JoyInfo); - //I_ShutdownJoystick(); - //joy_open(fname); - } + if (joyindex <= 0) + return -1; num_joy = SDL_NumJoysticks(); - if (joyindex <= 0 || num_joy == 0 || JoyInfo.oldjoy == joyindex) + if (num_joy == 0) { -// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); - if (num_joy != 0) - { - CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - } - else - CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); - if (joyindex <= 0 || num_joy == 0) return 0; + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + return -1; } - JoyInfo.dev = SDL_JoystickOpen(joyindex-1); + newdev = SDL_JoystickOpen(joyindex-1); + + // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging + // This indexing is SDL's responsibility and there's not much we can do about it. + // + // Example: + // 1. Plug Controller A -> Index 0 opened + // 2. Plug Controller B -> Index 1 opened + // 3. Unplug Controller A -> Index 0 closed, Index 1 active + // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed + // 5. Plug Controller B -> Index 0 opened + // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B + if (JoyInfo.dev) + { + if (JoyInfo.dev == newdev // same device, nothing to do + || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo.dev))) // we failed, but already have a working device + return JoyInfo.axises; + // Else, we're changing devices, so send neutral joy events + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device is changing; resetting events...\n"); + I_ShutdownJoystick(); + } + + JoyInfo.dev = newdev; if (JoyInfo.dev == NULL) { - CONS_Printf(M_GetText("Couldn't open joystick: %s\n"), SDL_GetError()); - I_ShutdownJoystick(); + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: Couldn't open device - %s\n"), SDL_GetError()); return -1; } else { - CONS_Printf(M_GetText("Joystick: %s\n"), SDL_JoystickName(JoyInfo.dev)); + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: %s\n"), SDL_JoystickName(JoyInfo.dev)); JoyInfo.axises = SDL_JoystickNumAxes(JoyInfo.dev); if (JoyInfo.axises > JOYAXISSET*2) JoyInfo.axises = JOYAXISSET*2; -/* if (joyaxes<2) + /* if (joyaxes<2) { I_OutputMsg("Not enought axes?\n"); - I_ShutdownJoystick(); return 0; }*/ @@ -1126,7 +1129,7 @@ static UINT64 lastjoy2hats = 0; \return void */ -static void I_ShutdownJoystick2(void) +void I_ShutdownJoystick2(void) { INT32 i; event_t event; @@ -1160,14 +1163,8 @@ static void I_ShutdownJoystick2(void) joystick2_started = 0; JoyReset(&JoyInfo2); - if (!joystick_started && !joystick2_started && SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) - { - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - if (cv_usejoystick2.value == 0) - { - DEBFILE("I_Joystick2: SDL's Joystick system has been shutdown\n"); - } - } + + // don't shut down the subsystem here, because hotplugging } void I_GetJoystick2Events(void) @@ -1310,72 +1307,66 @@ void I_GetJoystick2Events(void) */ -static int joy_open2(const char *fname) +static int joy_open2(int joyindex) { - int joyindex = atoi(fname); + SDL_Joystick *newdev = NULL; int num_joy = 0; - int i; - if (joystick_started == 0 && joystick2_started == 0) + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) - { - CONS_Printf(M_GetText("Couldn't initialize gamepad: %s\n"), SDL_GetError()); - return -1; - } - else - num_joy = SDL_NumJoysticks(); + CONS_Printf(M_GetText("Joystick subsystem not started\n")); + return -1; + } - if (num_joy < joyindex) - { - CONS_Printf("Cannot use gamepad #%d/(%s), it doesn't exist\n",joyindex,fname); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - I_ShutdownJoystick2(); - return -1; - } - } - else - { - JoyReset(&JoyInfo2); - //I_ShutdownJoystick(); - //joy_open(fname); - } + if (joyindex <= 0) + return -1; num_joy = SDL_NumJoysticks(); - if (joyindex <= 0 || num_joy == 0 || JoyInfo2.oldjoy == joyindex) + if (num_joy == 0) { -// I_OutputMsg("Unable to use that joystick #(%s), non-number\n",fname); - if (num_joy != 0) - { - CONS_Printf(M_GetText("Found %d joysticks on this system\n"), num_joy); - for (i = 0; i < num_joy; i++) - CONS_Printf("#%d/(%s)\n", i+1, SDL_JoystickNameForIndex(i)); - } - else - CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); - if (joyindex <= 0 || num_joy == 0) return 0; + CONS_Printf("%s", M_GetText("Found no joysticks on this system\n")); + return -1; } - JoyInfo2.dev = SDL_JoystickOpen(joyindex-1); + newdev = SDL_JoystickOpen(joyindex-1); - if (!JoyInfo2.dev) + // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging + // This indexing is SDL's responsibility and there's not much we can do about it. + // + // Example: + // 1. Plug Controller A -> Index 0 opened + // 2. Plug Controller B -> Index 1 opened + // 3. Unplug Controller A -> Index 0 closed, Index 1 active + // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed + // 5. Plug Controller B -> Index 0 opened + // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B + if (JoyInfo2.dev) { - CONS_Printf(M_GetText("Couldn't open joystick2: %s\n"), SDL_GetError()); + if (JoyInfo2.dev == newdev // same device, nothing to do + || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo2.dev))) // we failed, but already have a working device + return JoyInfo.axises; + // Else, we're changing devices, so send neutral joy events + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device is changing; resetting events...\n"); I_ShutdownJoystick2(); + } + + JoyInfo2.dev = newdev; + + if (JoyInfo2.dev == NULL) + { + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: couldn't open device - %s\n"), SDL_GetError()); return -1; } else { - CONS_Printf(M_GetText("Joystick2: %s\n"), SDL_JoystickName(JoyInfo2.dev)); + CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: %s\n"), SDL_JoystickName(JoyInfo2.dev)); JoyInfo2.axises = SDL_JoystickNumAxes(JoyInfo2.dev); if (JoyInfo2.axises > JOYAXISSET*2) JoyInfo2.axises = JOYAXISSET*2; -/* if (joyaxes < 2) +/* if (joyaxes<2) { I_OutputMsg("Not enought axes?\n"); - I_ShutdownJoystick2(); return 0; }*/ @@ -1400,7 +1391,11 @@ static int joy_open2(const char *fname) // void I_InitJoystick(void) { - I_ShutdownJoystick(); + SDL_Joystick *newjoy = NULL; + + //I_ShutdownJoystick(); + if (M_CheckParm("-nojoy")) + return; if (M_CheckParm("-noxinput")) SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); @@ -1408,21 +1403,48 @@ void I_InitJoystick(void) if (M_CheckParm("-nohidapi")) SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE); - if (!strcmp(cv_usejoystick.string, "0") || M_CheckParm("-nojoy")) - return; - if (joy_open(cv_usejoystick.string) != -1) - JoyInfo.oldjoy = atoi(cv_usejoystick.string); + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf("I_InitJoystick()...\n"); + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return; + } + } + + if (cv_usejoystick.value) + newjoy = SDL_JoystickOpen(cv_usejoystick.value-1); + + if (newjoy && JoyInfo2.dev == newjoy) // don't override an active device + cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (newjoy && joy_open(cv_usejoystick.value) != -1) + { + // SDL's device indexes are unstable, so cv_usejoystick may not match + // the actual device index. So let's cheat a bit and find the device's current index. + JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + joystick_started = 1; + } else { + if (JoyInfo.oldjoy) + I_ShutdownJoystick(); cv_usejoystick.value = 0; - return; + joystick_started = 0; } - joystick_started = 1; + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); } void I_InitJoystick2(void) { - I_ShutdownJoystick2(); + SDL_Joystick *newjoy = NULL; + + //I_ShutdownJoystick2(); + if (M_CheckParm("-nojoy")) + return; if (M_CheckParm("-noxinput")) SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE); @@ -1430,64 +1452,77 @@ void I_InitJoystick2(void) if (M_CheckParm("-nohidapi")) SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE); - if (!strcmp(cv_usejoystick2.string, "0") || M_CheckParm("-nojoy")) - return; - if (joy_open2(cv_usejoystick2.string) != -1) - JoyInfo2.oldjoy = atoi(cv_usejoystick2.string); + if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) + { + CONS_Printf("I_InitJoystick2()...\n"); + + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) + { + CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError()); + return; + } + } + + if (cv_usejoystick2.value) + newjoy = SDL_JoystickOpen(cv_usejoystick2.value-1); + + if (newjoy && JoyInfo.dev == newjoy) // don't override an active device + cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (newjoy && joy_open2(cv_usejoystick2.value) != -1) + { + // SDL's device indexes are unstable, so cv_usejoystick may not match + // the actual device index. So let's cheat a bit and find the device's current index. + JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + joystick2_started = 1; + } else { + if (JoyInfo2.oldjoy) + I_ShutdownJoystick2(); cv_usejoystick2.value = 0; - return; + joystick2_started = 0; } - joystick2_started = 1; + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); } static void I_ShutdownInput(void) { + // Yes, the name is misleading: these send neutral events to + // clean up the unplugged joystick's input + // Note these methods are internal to this file, not called elsewhere. + I_ShutdownJoystick(); + I_ShutdownJoystick2(); + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { - JoyReset(&JoyInfo); - JoyReset(&JoyInfo2); + CONS_Printf("Shutting down joy system\n"); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + I_OutputMsg("I_Joystick: SDL's Joystick system has been shutdown\n"); } - } INT32 I_NumJoys(void) { INT32 numjoy = 0; - if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) - { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1) - numjoy = SDL_NumJoysticks(); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - } - else + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) numjoy = SDL_NumJoysticks(); return numjoy; } -static char joyname[255]; // MAX_PATH; joystick name is straight from the driver +static char joyname[255]; // joystick name is straight from the driver const char *I_GetJoyName(INT32 joyindex) { const char *tempname = NULL; + joyname[0] = 0; joyindex--; //SDL's Joystick System starts at 0, not 1 - if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) - { - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1) - { - tempname = SDL_JoystickNameForIndex(joyindex); - if (tempname) - strncpy(joyname, tempname, 254); - } - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - } - else + if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK) { tempname = SDL_JoystickNameForIndex(joyindex); if (tempname) - strncpy(joyname, tempname, 254); + strncpy(joyname, tempname, 255); } return joyname; } diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 5a4fd7a02..46c05aea9 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -41,7 +41,7 @@ #ifdef HAVE_IMAGE #include "SDL_image.h" -#elif 1 +#elif defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) // Windows doesn't need this, as SDL will do it for us. #define LOAD_XPM //I want XPM! #include "IMG_xpm.c" //Alam: I don't want to add SDL_Image.dll/so #define HAVE_IMAGE //I have SDL_Image, sortof @@ -886,6 +886,136 @@ void I_GetEvent(void) case SDL_JOYBUTTONDOWN: Impl_HandleJoystickButtonEvent(evt.jbutton, evt.type); break; + case SDL_JOYDEVICEADDED: + { + SDL_Joystick *newjoy = SDL_JoystickOpen(evt.jdevice.which); + + CONS_Debug(DBG_GAMELOGIC, "Joystick device index %d added\n", evt.jdevice.which + 1); + + // Because SDL's device index is unstable, we're going to cheat here a bit: + // For the first joystick setting that is NOT active: + // 1. Set cv_usejoystickX.value to the new device index (this does not change what is written to config.cfg) + // 2. Set OTHERS' cv_usejoystickX.value to THEIR new device index, because it likely changed + // * If device doesn't exist, switch cv_usejoystick back to default value (.string) + // * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value! + if (newjoy && (!JoyInfo.dev || !SDL_JoystickGetAttached(JoyInfo.dev)) + && JoyInfo2.dev != newjoy) // don't override a currently active device + { + cv_usejoystick.value = evt.jdevice.which + 1; + + if (JoyInfo2.dev) + cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy + && atoi(cv_usejoystick2.string) != cv_usejoystick.value) + cv_usejoystick2.value = atoi(cv_usejoystick2.string); + else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy + && atoi(cv_usejoystick.string) != cv_usejoystick.value) + cv_usejoystick2.value = atoi(cv_usejoystick.string); + else // we tried... + cv_usejoystick2.value = 0; + } + else if (newjoy && (!JoyInfo2.dev || !SDL_JoystickGetAttached(JoyInfo2.dev)) + && JoyInfo.dev != newjoy) // don't override a currently active device + { + cv_usejoystick2.value = evt.jdevice.which + 1; + + if (JoyInfo.dev) + cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy + && atoi(cv_usejoystick.string) != cv_usejoystick2.value) + cv_usejoystick.value = atoi(cv_usejoystick.string); + else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy + && atoi(cv_usejoystick2.string) != cv_usejoystick2.value) + cv_usejoystick.value = atoi(cv_usejoystick2.string); + else // we tried... + cv_usejoystick.value = 0; + } + + // Was cv_usejoystick disabled in settings? + if (!strcmp(cv_usejoystick.string, "0") || !cv_usejoystick.value) + cv_usejoystick.value = 0; + else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + if (!strcmp(cv_usejoystick2.string, "0") || !cv_usejoystick2.value) + cv_usejoystick2.value = 0; + else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick2.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + // Update all joysticks' init states + // This is a little wasteful since cv_usejoystick already calls this, but + // we need to do this in case CV_SetValue did nothing because the string was already same. + // if the device is already active, this should do nothing, effectively. + I_InitJoystick(); + I_InitJoystick2(); + + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy); + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy); + + // update the menu + if (currentMenu == &OP_JoystickSetDef) + M_SetupJoystickMenu(0); + + if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy) + SDL_JoystickClose(newjoy); + } + break; + case SDL_JOYDEVICEREMOVED: + if (JoyInfo.dev && !SDL_JoystickGetAttached(JoyInfo.dev)) + { + CONS_Debug(DBG_GAMELOGIC, "Joystick1 removed, device index: %d\n", JoyInfo.oldjoy); + I_ShutdownJoystick(); + } + + if (JoyInfo2.dev && !SDL_JoystickGetAttached(JoyInfo2.dev)) + { + CONS_Debug(DBG_GAMELOGIC, "Joystick2 removed, device index: %d\n", JoyInfo2.oldjoy); + I_ShutdownJoystick2(); + } + + // Update the device indexes, because they likely changed + // * If device doesn't exist, switch cv_usejoystick back to default value (.string) + // * BUT: If that default index is being occupied, use ANOTHER cv_usejoystick's default value! + if (JoyInfo.dev) + cv_usejoystick.value = JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1; + else if (atoi(cv_usejoystick.string) != JoyInfo2.oldjoy) + cv_usejoystick.value = atoi(cv_usejoystick.string); + else if (atoi(cv_usejoystick2.string) != JoyInfo2.oldjoy) + cv_usejoystick.value = atoi(cv_usejoystick2.string); + else // we tried... + cv_usejoystick.value = 0; + + if (JoyInfo2.dev) + cv_usejoystick2.value = JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1; + else if (atoi(cv_usejoystick2.string) != JoyInfo.oldjoy) + cv_usejoystick2.value = atoi(cv_usejoystick2.string); + else if (atoi(cv_usejoystick.string) != JoyInfo.oldjoy) + cv_usejoystick2.value = atoi(cv_usejoystick.string); + else // we tried... + cv_usejoystick2.value = 0; + + // Was cv_usejoystick disabled in settings? + if (!strcmp(cv_usejoystick.string, "0")) + cv_usejoystick.value = 0; + else if (atoi(cv_usejoystick.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick, cv_usejoystick.value); + + if (!strcmp(cv_usejoystick2.string, "0")) + cv_usejoystick2.value = 0; + else if (atoi(cv_usejoystick2.string) <= I_NumJoys() // don't mess if we intentionally set higher than NumJoys + && cv_usejoystick2.value) // update the cvar ONLY if a device exists + CV_SetValue(&cv_usejoystick2, cv_usejoystick2.value); + + CONS_Debug(DBG_GAMELOGIC, "Joystick1 device index: %d\n", JoyInfo.oldjoy); + CONS_Debug(DBG_GAMELOGIC, "Joystick2 device index: %d\n", JoyInfo2.oldjoy); + + // update the menu + if (currentMenu == &OP_JoystickSetDef) + M_SetupJoystickMenu(0); + break; case SDL_QUIT: I_Quit(); M_QuitResponse('y'); diff --git a/src/sdl/macosx/Srb2mac.icns b/src/sdl/macosx/Srb2mac.icns index 96cb8a36d..a3e37aab3 100644 Binary files a/src/sdl/macosx/Srb2mac.icns and b/src/sdl/macosx/Srb2mac.icns differ diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index d12daaa8a..810c7dce1 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -31,6 +31,9 @@ extern SDL_bool framebuffer; #define SDL2STUB() CONS_Printf("SDL2: stubbed: %s:%d\n", __func__, __LINE__) #endif +// So m_menu knows whether to store cv_usejoystick value or string +#define JOYSTICK_HOTPLUG + /** \brief The JoyInfo_s struct info about joystick @@ -67,6 +70,13 @@ extern SDLJoyInfo_t JoyInfo; */ extern SDLJoyInfo_t JoyInfo2; +// So we can call this from i_video event loop +void I_ShutdownJoystick(void); +void I_ShutdownJoystick2(void); + +// Cheat to get the device index for a joystick handle +INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev); + void I_GetConsoleEvents(void); void SDLforceUngrabMouse(void); diff --git a/src/sdl/srb2icon.png b/src/sdl/srb2icon.png deleted file mode 100644 index cdee18a84..000000000 Binary files a/src/sdl/srb2icon.png and /dev/null differ diff --git a/src/sounds.c b/src/sounds.c index c2b9a09d7..67cf81b53 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -35,6 +35,23 @@ sfxinfo_t S_sfx[NUMSFX] = // name, singularity, priority, pitch, volume, data, length, skinsound, usefulness, lumpnum, caption {"none" , false, 0, 0, -1, NULL, 0, -1, -1, LUMPERROR, "///////////////////////////////"}, // maximum length + // A HUMBLE REQUEST FROM YOUR FRIENDLY NEIGHBORHOOD toaster! + // + // If you see a caption that's just "" (shows the lumpname in-game), + // and you intend to use the sound associated with it in a mod, + // PLEASE give it a caption through SOC or Lua. + // + // If the first character of the caption is '/', no caption will be + // produced; only do this for "unimportant" sounds that aren't used + // to indicate gameplay. + // + // (to whomstever updates the sounds list wiki page for 2.2, please + // either copy this comment across, or make sure its desire is + // codified in the initial paragraph of the page.) + // + // Closed Captioning may be a niche feature, but it's an important one. + // Thank you! ^u^ + // Skin Sounds {"altdi1", false, 192, 16, -1, NULL, 0, SKSPLDET1, -1, LUMPERROR, "Dying"}, {"altdi2", false, 192, 16, -1, NULL, 0, SKSPLDET2, -1, LUMPERROR, "Dying"}, @@ -195,6 +212,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"boingf", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bouncing"}, {"corkp", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork fired"}, {"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"}, + {"alart", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Caught red handed!"}, + {"vwre", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Clone fighter!"}, {"bowl", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bowling"}, {"chuchu", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Train horn"}, {"bsnipe", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Home-run smash"}, @@ -292,6 +311,139 @@ sfxinfo_t S_sfx[NUMSFX] = {"brakrl", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Rocket launch"}, {"brakrx", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Rocket explosion"}, + // Sonic 1 sounds + {"s1a0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1a9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1aa", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ab", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ac", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ad", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ae", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1af", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1b9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ba", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bd", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1be", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1bf", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1c9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ca", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cc", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cd", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1ce", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s1cf", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + + // Sonic 2 sounds + {"s220", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s221", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s222", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s223", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s224", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s225", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s226", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s227", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s228", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s229", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s22f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s230", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s231", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s232", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s233", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s234", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s235", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s236", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s237", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s238", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s239", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s23f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s240", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s241", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s242", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s243", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s244", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s245", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s246", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s247", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s248", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s249", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s24f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s250", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s251", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s252", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s253", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s254", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s255", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s256", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s257", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s258", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s259", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s25f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s260", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s261", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s262", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s263", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s264", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s265", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s266", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s267", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s268", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s269", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s26a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s26b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s26c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s26d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s26e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s26f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"s270", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // S3&K sounds {"s3k33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, // stereo in original game, identical to latter {"s3k34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, // mono in original game, identical to previous @@ -336,7 +488,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k5b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Menu beep"}, {"s3k5c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Electric spark"}, {"s3k5d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"}, - {"s3k5e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"}, + {"s3k5e", false, 127, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Releasing charge"}, {"s3k5f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crusher stomp"}, {"s3k60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accelerating"}, {"s3k61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drilling"}, @@ -461,8 +613,8 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kcal", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Energy"}, // ditto {"s3kcbs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, {"s3kcbl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, // ditto - {"s3kccs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"}, - {"s3kccl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Collapsing"}, // ditto + {"s3kccs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bursting"}, + {"s3kccl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bursting"}, // ditto {"s3kcds", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, {"s3kcdl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ominous rumbling"}, // ditto {"s3kces", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Wind tunnel"}, @@ -494,6 +646,174 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kdbs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running on water"}, {"s3kdbl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Running on water"}, // ditto + // 3D Blast sounds (the "missing" ones are direct copies of S3K's, no minor differences what-so-ever) + {"3db06", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Collection"}, + {"3db09", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Peep"}, + {"3db14", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Chirp"}, + {"3db16", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + + // Sonic CD sounds + {"cdfm00", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Skid"}, + {"cdfm01", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm02", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"}, + {"cdfm03", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dying"}, + {"cdfm04", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ring loss"}, + {"cdfm05", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Sparkle"}, + {"cdfm06", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Pop"}, + {"cdfm07", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Shield"}, + {"cdfm08", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spring"}, + {"cdfm09", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm10", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm11", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm12", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm13", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm14", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm15", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm16", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm17", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm18", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm19", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm20", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm21", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm22", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm23", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm24", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm25", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm26", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm27", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm28", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm29", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble gasp"}, + {"cdfm30", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"}, + {"cdfm31", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Warp"}, + {"cdfm32", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm35", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm36", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm37", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm38", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drowning"}, + {"cdfm39", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Extra time"}, + {"cdfm45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aquaphobia"}, + {"cdfm50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm54", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Warp"}, + {"cdfm57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm59", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm64", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm65", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm70", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm71", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm72", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm73", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm74", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm75", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm76", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm77", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm78", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm79", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdpcm0", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Future."}, + {"cdpcm1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Past."}, + {"cdpcm2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "All right!"}, + {"cdpcm3", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "I'm outta here..."}, + {"cdpcm4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Yes!"}, + {"cdpcm5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Yeah!"}, + {"cdpcm6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Giggles"}, + {"cdpcm7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Eep!"}, + {"cdpcm8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdpcm9", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Bumper"}, + + // Knuckles Chaotix sounds + {"kc2a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2e", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc2f", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc30", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc31", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc32", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc35", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc36", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc37", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc38", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc39", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Confirm"}, + {"kc43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc46", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc48", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Select"}, + {"kc49", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc51", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc54", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc57", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Sheer terror"}, + {"kc58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc59", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Shrink"}, + {"kc5a", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Grow"}, + {"kc5b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc5f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc64", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Terrifying rumble"}, + {"kc65", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc6b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ascending"}, + {"kc6c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc6d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc6e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // skin sounds free slots to add sounds at run time (Boris HACK!!!) // initialized to NULL }; diff --git a/src/sounds.h b/src/sounds.h index be6969e56..9f6e0bab6 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -261,6 +261,8 @@ typedef enum sfx_boingf, sfx_corkp, sfx_corkh, + sfx_alart, + sfx_vwre, sfx_bowl, sfx_chuchu, sfx_bsnipe, @@ -358,6 +360,139 @@ typedef enum sfx_brakrl, // Rocket launcher sfx_brakrx, // Rocket explodes + // S1 sounds + sfx_s1a0, + sfx_s1a1, + sfx_s1a2, + sfx_s1a3, + sfx_s1a4, + sfx_s1a5, + sfx_s1a6, + sfx_s1a7, + sfx_s1a8, + sfx_s1a9, + sfx_s1aa, + sfx_s1ab, + sfx_s1ac, + sfx_s1ad, + sfx_s1ae, + sfx_s1af, + sfx_s1b0, + sfx_s1b1, + sfx_s1b2, + sfx_s1b3, + sfx_s1b4, + sfx_s1b5, + sfx_s1b6, + sfx_s1b7, + sfx_s1b8, + sfx_s1b9, + sfx_s1ba, + sfx_s1bb, + sfx_s1bc, + sfx_s1bd, + sfx_s1be, + sfx_s1bf, + sfx_s1c0, + sfx_s1c1, + sfx_s1c2, + sfx_s1c3, + sfx_s1c4, + sfx_s1c5, + sfx_s1c6, + sfx_s1c7, + sfx_s1c8, + sfx_s1c9, + sfx_s1ca, + sfx_s1cb, + sfx_s1cc, + sfx_s1cd, + sfx_s1ce, + sfx_s1cf, + + // S2 sounds + sfx_s220, + sfx_s221, + sfx_s222, + sfx_s223, + sfx_s224, + sfx_s225, + sfx_s226, + sfx_s227, + sfx_s228, + sfx_s229, + sfx_s22a, + sfx_s22b, + sfx_s22c, + sfx_s22d, + sfx_s22e, + sfx_s22f, + sfx_s230, + sfx_s231, + sfx_s232, + sfx_s233, + sfx_s234, + sfx_s235, + sfx_s236, + sfx_s237, + sfx_s238, + sfx_s239, + sfx_s23a, + sfx_s23b, + sfx_s23c, + sfx_s23d, + sfx_s23e, + sfx_s23f, + sfx_s240, + sfx_s241, + sfx_s242, + sfx_s243, + sfx_s244, + sfx_s245, + sfx_s246, + sfx_s247, + sfx_s248, + sfx_s249, + sfx_s24a, + sfx_s24b, + sfx_s24c, + sfx_s24d, + sfx_s24e, + sfx_s24f, + sfx_s250, + sfx_s251, + sfx_s252, + sfx_s253, + sfx_s254, + sfx_s255, + sfx_s256, + sfx_s257, + sfx_s258, + sfx_s259, + sfx_s25a, + sfx_s25b, + sfx_s25c, + sfx_s25d, + sfx_s25e, + sfx_s25f, + sfx_s260, + sfx_s261, + sfx_s262, + sfx_s263, + sfx_s264, + sfx_s265, + sfx_s266, + sfx_s267, + sfx_s268, + sfx_s269, + sfx_s26a, + sfx_s26b, + sfx_s26c, + sfx_s26d, + sfx_s26e, + sfx_s26f, + sfx_s270, + // S3&K sounds sfx_s3k33, sfx_s3k34, @@ -560,6 +695,174 @@ typedef enum sfx_s3kdbs, sfx_s3kdbl, + // 3DB sounds + sfx_3db06, + sfx_3db09, + sfx_3db14, + sfx_3db16, + + // SCD sounds + sfx_cdfm00, + sfx_cdfm01, + sfx_cdfm02, + sfx_cdfm03, + sfx_cdfm04, + sfx_cdfm05, + sfx_cdfm06, + sfx_cdfm07, + sfx_cdfm08, + sfx_cdfm09, + sfx_cdfm10, + sfx_cdfm11, + sfx_cdfm12, + sfx_cdfm13, + sfx_cdfm14, + sfx_cdfm15, + sfx_cdfm16, + sfx_cdfm17, + sfx_cdfm18, + sfx_cdfm19, + sfx_cdfm20, + sfx_cdfm21, + sfx_cdfm22, + sfx_cdfm23, + sfx_cdfm24, + sfx_cdfm25, + sfx_cdfm26, + sfx_cdfm27, + sfx_cdfm28, + sfx_cdfm29, + sfx_cdfm30, + sfx_cdfm31, + sfx_cdfm32, + sfx_cdfm33, + sfx_cdfm34, + sfx_cdfm35, + sfx_cdfm36, + sfx_cdfm37, + sfx_cdfm38, + sfx_cdfm39, + sfx_cdfm40, + sfx_cdfm41, + sfx_cdfm42, + sfx_cdfm43, + sfx_cdfm44, + sfx_cdfm45, + sfx_cdfm46, + sfx_cdfm47, + sfx_cdfm48, + sfx_cdfm49, + sfx_cdfm50, + sfx_cdfm51, + sfx_cdfm52, + sfx_cdfm53, + sfx_cdfm54, + sfx_cdfm55, + sfx_cdfm56, + sfx_cdfm57, + sfx_cdfm58, + sfx_cdfm59, + sfx_cdfm60, + sfx_cdfm61, + sfx_cdfm62, + sfx_cdfm63, + sfx_cdfm64, + sfx_cdfm65, + sfx_cdfm66, + sfx_cdfm67, + sfx_cdfm68, + sfx_cdfm69, + sfx_cdfm70, + sfx_cdfm71, + sfx_cdfm72, + sfx_cdfm73, + sfx_cdfm74, + sfx_cdfm75, + sfx_cdfm76, + sfx_cdfm77, + sfx_cdfm78, + sfx_cdfm79, + sfx_cdpcm0, + sfx_cdpcm1, + sfx_cdpcm2, + sfx_cdpcm3, + sfx_cdpcm4, + sfx_cdpcm5, + sfx_cdpcm6, + sfx_cdpcm7, + sfx_cdpcm8, + sfx_cdpcm9, + + // KC sounds + sfx_kc2a, + sfx_kc2b, + sfx_kc2c, + sfx_kc2d, + sfx_kc2e, + sfx_kc2f, + sfx_kc30, + sfx_kc31, + sfx_kc32, + sfx_kc33, + sfx_kc34, + sfx_kc35, + sfx_kc36, + sfx_kc37, + sfx_kc38, + sfx_kc39, + sfx_kc3a, + sfx_kc3b, + sfx_kc3c, + sfx_kc3d, + sfx_kc3e, + sfx_kc3f, + sfx_kc40, + sfx_kc41, + sfx_kc42, + sfx_kc43, + sfx_kc44, + sfx_kc45, + sfx_kc46, + sfx_kc47, + sfx_kc48, + sfx_kc49, + sfx_kc4a, + sfx_kc4b, + sfx_kc4c, + sfx_kc4d, + sfx_kc4e, + sfx_kc4f, + sfx_kc50, + sfx_kc51, + sfx_kc52, + sfx_kc53, + sfx_kc54, + sfx_kc55, + sfx_kc56, + sfx_kc57, + sfx_kc58, + sfx_kc59, + sfx_kc5a, + sfx_kc5b, + sfx_kc5c, + sfx_kc5d, + sfx_kc5e, + sfx_kc5f, + sfx_kc60, + sfx_kc61, + sfx_kc62, + sfx_kc63, + sfx_kc64, + sfx_kc65, + sfx_kc66, + sfx_kc67, + sfx_kc68, + sfx_kc69, + sfx_kc6b, + sfx_kc6c, + sfx_kc6d, + sfx_kc6e, + // free slots for S_AddSoundFx() at run-time -------------------- sfx_freeslot0, // diff --git a/src/st_stuff.c b/src/st_stuff.c index aefb4c53c..20a132b3a 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -64,11 +64,12 @@ patch_t *sbotime; // Time logo patch_t *sbocolon; // Colon for time patch_t *sboperiod; // Period for time centiseconds patch_t *livesback; // Lives icon background +patch_t *stlivex; static patch_t *nrec_timer; // Timer for NiGHTS records static patch_t *sborings; -static patch_t *sboover; -static patch_t *timeover; -static patch_t *stlivex; +static patch_t *slidgame; +static patch_t *slidtime; +static patch_t *slidover; static patch_t *sboredrings; static patch_t *sboredtime; static patch_t *getall; // Special Stage HUD @@ -253,8 +254,10 @@ void ST_LoadGraphics(void) sbocolon = W_CachePatchName("STTCOLON", PU_HUDGFX); // Colon for time sboperiod = W_CachePatchName("STTPERIO", PU_HUDGFX); // Period for time centiseconds - sboover = W_CachePatchName("SBOOVER", PU_HUDGFX); - timeover = W_CachePatchName("TIMEOVER", PU_HUDGFX); + slidgame = W_CachePatchName("SLIDGAME", PU_HUDGFX); + slidtime = W_CachePatchName("SLIDTIME", PU_HUDGFX); + slidover = W_CachePatchName("SLIDOVER", PU_HUDGFX); + stlivex = W_CachePatchName("STLIVEX", PU_HUDGFX); livesback = W_CachePatchName("STLIVEBK", PU_HUDGFX); nrec_timer = W_CachePatchName("NGRTIMER", PU_HUDGFX); // Timer for NiGHTS @@ -768,7 +771,12 @@ static inline void ST_drawRings(void) ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); - ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0)); + if (objectplacing) + ringnum = op_currentdoomednum; + else if (stplyr->rings < 0 || stplyr->spectator || stplyr->playerstate == PST_REBORN) + ringnum = 0; + else + ringnum = stplyr->rings; if (cv_timetic.value == 2) // Yes, even in modeattacking ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS)); @@ -877,6 +885,8 @@ static void ST_drawLivesArea(void) '\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false); else { + if (stplyr->playerstate == PST_DEAD && !(stplyr->spectator) && (livescount || stplyr->deadtimer < (TICRATE<<1))) + livescount++; if (livescount > 99) livescount = 99; V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8, @@ -1960,6 +1970,7 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I static void ST_drawMatchHUD(void) { + char penaltystr[7]; const INT32 y = 176; // HUD_LIVES INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; @@ -1986,18 +1997,20 @@ static void ST_drawMatchHUD(void) ST_drawWeaponSelect(offset, y); } - offset += 20; - ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, y, autoring); - offset += 20; - ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, y, bouncering); - offset += 20; - ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, y, scatterring); - offset += 20; - ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, y, grenadering); - offset += 20; - ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, y, explosionring); - offset += 20; - ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, y, railring); + ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset + 20, y, autoring); + ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset + 40, y, bouncering); + ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset + 60, y, scatterring); + ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset + 80, y, grenadering); + ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset + 100, y, explosionring); + ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset + 120, y, railring); + + if (stplyr->ammoremovaltimer && leveltime % 8 < 4) + { + sprintf(penaltystr, "-%d", stplyr->ammoremoval); + V_DrawString(offset + 8 + stplyr->ammoremovalweapon * 20, y, + V_REDMAP, penaltystr); + } + } } @@ -2026,42 +2039,7 @@ static void ST_drawTextHUD(void) textHUDdraw(va("Lap:""\x82 %u/%d", stplyr->laps+1, cv_numlaps.value)) } - if (!stplyr->spectator && stplyr->exiting && cv_playersforexit.value && gametype == GT_COOP) - { - INT32 i, total = 0, exiting = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - if (players[i].lives <= 0) - continue; - - total++; - if (players[i].exiting) - exiting++; - } - - if (cv_playersforexit.value != 4) - { - total *= cv_playersforexit.value; - if (total & 3) - total += 4; // round up - total /= 4; - } - - if (exiting < total) - { - if (!splitscreen && !donef12) - { - textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) - donef12 = true; - } - total -= exiting; - textHUDdraw(va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))) - } - } - else if (gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) + if (gametype != GT_COOP && (stplyr->exiting || (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1))) { if (!splitscreen && !donef12) { @@ -2069,7 +2047,7 @@ static void ST_drawTextHUD(void) donef12 = true; } } - else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) //Death overrides spectator text. + else if (!G_PlatformGametype() && stplyr->playerstate == PST_DEAD && stplyr->lives) // Death overrides spectator text. { INT32 respawntime = cv_respawntime.value - stplyr->deadtimer/TICRATE; @@ -2089,7 +2067,7 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""JUMP:""\x80 Rise")) textHUDdraw(M_GetText("\x82""SPIN:""\x80 Lower")) - if (G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) + if (G_IsSpecialStage(gamemap)) textHUDdraw(M_GetText("\x82""Wait for the stage to end...")) else if (gametype == GT_COOP) { @@ -2122,7 +2100,46 @@ static void ST_drawTextHUD(void) textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game")) } - if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) + if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && stplyr->exiting) + { + UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); + if (numneeded) + { + INT32 i, total = 0, exiting = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + if (players[i].lives <= 0) + continue; + + total++; + if (players[i].exiting) + exiting++; + } + + if (numneeded != 4) + { + total *= cv_playersforexit.value; + if (total & 3) + total += 4; // round up + total /= 4; + } + + if (exiting < total) + { + if (!splitscreen && !donef12) + { + textHUDdraw(M_GetText("\x82""VIEWPOINT:""\x80 Switch view")) + donef12 = true; + } + total -= exiting; + textHUDdraw(va(M_GetText("%d player%s remaining"), total, ((total == 1) ? "" : "s"))) + } + } + } + else if ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && (!stplyr->spectator)) { if (leveltime < hidetime * TICRATE) { @@ -2406,25 +2423,20 @@ static void ST_overlayDrawer(void) } } - // GAME OVER pic + // GAME OVER hud if ((gametype == GT_COOP) && (netgame || multiplayer) && (cv_cooplives.value == 0)) ; - else if (G_GametypeUsesLives() && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer))) + else if ((G_GametypeUsesLives() || gametype == GT_RACE) && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer))) { - patch_t *p; - - if (countdown == 1) - p = timeover; - else - p = sboover; + INT32 i = MAXPLAYERS; + INT32 deadtimer = stplyr->spectator ? TICRATE : (stplyr->deadtimer-(TICRATE<<1)); if ((gametype == GT_COOP) && (netgame || multiplayer) && (cv_cooplives.value != 1)) { - INT32 i; for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) @@ -2434,15 +2446,18 @@ static void ST_overlayDrawer(void) continue; if (players[i].lives > 0) - { - p = NULL; break; - } } } - if (p) - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, BASEVIDHEIGHT/2 - (SHORT(p->height)/2), V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS), p); + if (i == MAXPLAYERS && deadtimer >= 0) + { + INT32 lvlttlx = min(6*deadtimer, BASEVIDWIDTH/2); + UINT32 flags = V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS); + + V_DrawScaledPatch(lvlttlx - 8, BASEVIDHEIGHT/2, flags, (countdown == 1 ? slidtime : slidgame)); + V_DrawScaledPatch(BASEVIDWIDTH + 8 - lvlttlx, BASEVIDHEIGHT/2, flags, slidover); + } } if (G_GametypeHasTeams()) diff --git a/src/st_stuff.h b/src/st_stuff.h index 40574f46c..aaf01ca15 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -70,6 +70,7 @@ extern patch_t *sboperiod; extern patch_t *faceprefix[MAXSKINS]; // face status patches extern patch_t *superprefix[MAXSKINS]; // super face status patches extern patch_t *livesback; +extern patch_t *stlivex; extern patch_t *ngradeletters[7]; /** HUD location information (don't move this comment) diff --git a/src/v_video.c b/src/v_video.c index 2ec06a787..93fefdd97 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -856,8 +856,8 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ return; #ifdef HWRENDER - // Done - if (rendermode != render_soft && !con_startup) + //if (rendermode != render_soft && !con_startup) // Not this again + if (rendermode != render_soft) { HWR_DrawCroppedPatch((GLPatch_t*)patch,x,y,pscale,scrn,sx,sy,w,h); return; @@ -1045,9 +1045,15 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ prevdelta = topdelta; source = (const UINT8 *)(column) + 3; dest = desttop; - dest += FixedInt(FixedMul(topdelta< 0) + { + dest += FixedInt(FixedMul((topdelta-sy)<>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) + for (; dest < deststop && (ofs>>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) { if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) *dest = patchdrawfunc(dest, source, ofs); @@ -1064,17 +1070,17 @@ 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) { - if (skinnum < 0 || skinnum >= numskins || (skins[skinnum].flags & SF_HIRES)) - V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); - else + if (skinnum >= 0 && skinnum < numskins && skins[skinnum].sprites[SPR2_XTRA].numframes >= 4) { - spriteframe_t *sprframe = &skins[skinnum].sprites[SPR2_WAIT].spriteframes[0]; - patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; + spriteframe_t *sprframe = &sprdef->spriteframes[3]; + patch_t *patch = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); const UINT8 *colormap = R_GetTranslationColormap(skinnum, skincolor, GTC_CACHE); - // No variant for translucency - V_DrawTinyMappedPatch(x, y, flags, patch, colormap); + V_DrawMappedPatch(x, y, flags, patch, colormap); } + else + V_DrawScaledPatch(x - 10, y - 14, flags, W_CachePatchName("CONTINS", PU_CACHE)); } // @@ -1174,7 +1180,8 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) return; #ifdef HWRENDER - if (rendermode != render_soft && !con_startup) + //if (rendermode != render_soft && !con_startup) // Not this again + if (rendermode != render_soft) { HWR_DrawFill(x, y, w, h, c); return; diff --git a/src/w_wad.c b/src/w_wad.c index d02ce9ce6..4d08b26dc 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -789,6 +789,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile) // set up caching // Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache); + Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); #ifdef HWRENDER // allocates GLPatch info structures and store them in a tree @@ -1182,8 +1183,6 @@ void zerr(int ret) } #endif -#define NO_PNG_LUMPS - #ifdef NO_PNG_LUMPS static void ErrorIfPNG(UINT8 *d, size_t s, char *f, char *l) { @@ -1459,6 +1458,38 @@ boolean W_IsLumpCached(lumpnum_t lumpnum, void *ptr) return W_IsLumpCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr); } +// +// W_IsPatchCached +// +// If a patch is already cached return true, otherwise +// return false. +// +// no outside code uses the PWAD form, for now +static inline boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr) +{ + void *lcache; + + if (!TestValidLump(wad, lump)) + return false; + + lcache = wadfiles[wad]->patchcache[lump]; + + if (ptr) + { + if (ptr == lcache) + return true; + } + else if (lcache) + return true; + + return false; +} + +boolean W_IsPatchCached(lumpnum_t lumpnum, void *ptr) +{ + return W_IsPatchCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr); +} + // ========================================================================== // W_CacheLumpName // ========================================================================== @@ -1482,18 +1513,53 @@ void *W_CacheLumpName(const char *name, INT32 tag) // Cache a patch into heap memory, convert the patch format as necessary // -// Software-only compile cache the data without conversion -#ifdef HWRENDER -static inline void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) +void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) { +#ifdef HWRENDER GLPatch_t *grPatch; - - if (rendermode == render_soft || rendermode == render_none) - return W_CacheLumpNumPwad(wad, lump, tag); +#endif if (!TestValidLump(wad, lump)) return NULL; +#ifdef HWRENDER + // Software-only compile cache the data without conversion + if (rendermode == render_soft || rendermode == render_none) + { +#endif + lumpcache_t *lumpcache = wadfiles[wad]->patchcache; + if (!lumpcache[lump]) + { + size_t len = W_LumpLengthPwad(wad, lump); + void *ptr, *lumpdata, *srcdata = NULL; + + ptr = Z_Malloc(len, tag, &lumpcache[lump]); + lumpdata = Z_Malloc(len, tag, NULL); + + // read the lump in full + W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); + +#ifndef NO_PNG_LUMPS + // lump is a png so convert it + if (R_IsLumpPNG((UINT8 *)lumpdata, len)) + { + size_t newlen; + srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen, true); + ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]); + M_Memcpy(ptr, srcdata, newlen); + Z_Free(srcdata); + } + else // just copy it into the patch cache +#endif + M_Memcpy(ptr, lumpdata, len); + } + else + Z_ChangeTag(lumpcache[lump], tag); + + return lumpcache[lump]; +#ifdef HWRENDER + } + grPatch = HWR_GetCachedGLPatchPwad(wad, lump); if (grPatch->mipmap.grInfo.data) @@ -1517,6 +1583,7 @@ static inline void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) // return GLPatch_t, which can be casted to (patch_t) with valid patch header info return (void *)grPatch; +#endif } void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag) @@ -1524,8 +1591,6 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag) return W_CachePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag); } -#endif // HWRENDER - void W_UnlockCachedPatch(void *patch) { // The hardware code does its own memory management, as its patches @@ -1621,13 +1686,145 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5) #endif } +// Verify versions for different archive +// formats. checklist assumed to be valid. + +static int +W_VerifyName (const char *name, lumpchecklist_t *checklist, boolean status) +{ + size_t j; + for (j = 0; checklist[j].len && checklist[j].name; ++j) + { + if (( strncmp(name, checklist[j].name, + checklist[j].len) != false ) == status) + { + return true; + } + } + return false; +} + +static int +W_VerifyWAD (FILE *fp, lumpchecklist_t *checklist, boolean status) +{ + size_t i; + + // assume wad file + wadinfo_t header; + filelump_t lumpinfo; + + // read the header + if (fread(&header, 1, sizeof header, fp) == sizeof header + && header.numlumps < INT16_MAX + && strncmp(header.identification, "ZWAD", 4) + && strncmp(header.identification, "IWAD", 4) + && strncmp(header.identification, "PWAD", 4) + && strncmp(header.identification, "SDLL", 4)) + { + return true; + } + + header.numlumps = LONG(header.numlumps); + header.infotableofs = LONG(header.infotableofs); + + // let seek to the lumpinfo list + if (fseek(fp, header.infotableofs, SEEK_SET) == -1) + return true; + + for (i = 0; i < header.numlumps; i++) + { + // fill in lumpinfo for this wad file directory + if (fread(&lumpinfo, sizeof (lumpinfo), 1 , fp) != 1) + return true; + + lumpinfo.filepos = LONG(lumpinfo.filepos); + lumpinfo.size = LONG(lumpinfo.size); + + if (lumpinfo.size == 0) + continue; + + if (! W_VerifyName(lumpinfo.name, checklist, status)) + return false; + } + + return true; +} + +static int +W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) +{ + zend_t zend; + zentry_t zentry; + + UINT16 numlumps; + size_t i; + + char pat_central[] = {0x50, 0x4b, 0x01, 0x02, 0x00}; + char pat_end[] = {0x50, 0x4b, 0x05, 0x06, 0x00}; + + char lumpname[9]; + + // Haha the ResGetLumpsZip function doesn't + // check for file errors, so neither will I. + + // Central directory bullshit + + fseek(fp, 0, SEEK_END); + if (!ResFindSignature(fp, pat_end, max(0, ftell(fp) - (22 + 65536)))) + return true; + + fseek(fp, -4, SEEK_CUR); + if (fread(&zend, 1, sizeof zend, fp) < sizeof zend) + return true; + + numlumps = zend.entries; + + fseek(fp, zend.cdiroffset, SEEK_SET); + for (i = 0; i < numlumps; i++) + { + char* fullname; + char* trimname; + char* dotpos; + + if (fread(&zentry, 1, sizeof(zentry_t), fp) < sizeof(zentry_t)) + return true; + if (memcmp(zentry.signature, pat_central, 4)) + return true; + + fullname = malloc(zentry.namelen + 1); + if (fgets(fullname, zentry.namelen + 1, fp) != fullname) + return true; + + // Strip away file address and extension for the 8char name. + if ((trimname = strrchr(fullname, '/')) != 0) + trimname++; + else + trimname = fullname; // Care taken for root files. + + if (*trimname) // Ignore directories + { + if ((dotpos = strrchr(trimname, '.')) == 0) + dotpos = fullname + strlen(fullname); // Watch for files without extension. + + memset(lumpname, '\0', 9); // Making sure they're initialized to 0. Is it necessary? + strncpy(lumpname, trimname, min(8, dotpos - trimname)); + + if (! W_VerifyName(lumpname, checklist, status)) + return false; + } + + free(fullname); + } + + return true; +} + // Note: This never opens lumps themselves and therefore doesn't have to // deal with compressed lumps. static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, boolean status) { FILE *handle; - size_t i, j; int goodfile = false; if (!checklist) @@ -1636,66 +1833,18 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, if ((handle = W_OpenWadFile(&filename, false)) == NULL) return -1; - // detect wad file by the absence of the other supported extensions - if (stricmp(&filename[strlen(filename) - 4], ".soc") -#ifdef HAVE_BLUA - && stricmp(&filename[strlen(filename) - 4], ".lua") -#endif - && stricmp(&filename[strlen(filename) - 4], ".pk3")) + if (stricmp(&filename[strlen(filename) - 4], ".pk3") == 0) + goodfile = W_VerifyPK3(handle, checklist, status); + else { - // assume wad file - wadinfo_t header; - filelump_t lumpinfo; - - // read the header - if (fread(&header, 1, sizeof header, handle) == sizeof header - && header.numlumps < INT16_MAX - && strncmp(header.identification, "ZWAD", 4) - && strncmp(header.identification, "IWAD", 4) - && strncmp(header.identification, "PWAD", 4) - && strncmp(header.identification, "SDLL", 4)) + // detect wad file by the absence of the other supported extensions + if (stricmp(&filename[strlen(filename) - 4], ".soc") +#ifdef HAVE_BLUA + && stricmp(&filename[strlen(filename) - 4], ".lua") +#endif + ) { - fclose(handle); - return true; - } - - header.numlumps = LONG(header.numlumps); - header.infotableofs = LONG(header.infotableofs); - - // let seek to the lumpinfo list - if (fseek(handle, header.infotableofs, SEEK_SET) == -1) - { - fclose(handle); - return false; - } - - goodfile = true; - for (i = 0; i < header.numlumps; i++) - { - // fill in lumpinfo for this wad file directory - if (fread(&lumpinfo, sizeof (lumpinfo), 1 , handle) != 1) - { - fclose(handle); - return -1; - } - - lumpinfo.filepos = LONG(lumpinfo.filepos); - lumpinfo.size = LONG(lumpinfo.size); - - if (lumpinfo.size == 0) - continue; - - for (j = 0; j < NUMSPRITES; j++) - if (sprnames[j] && !strncmp(lumpinfo.name, sprnames[j], 4)) // Sprites - continue; - - goodfile = false; - for (j = 0; checklist[j].len && checklist[j].name && !goodfile; j++) - if ((strncmp(lumpinfo.name, checklist[j].name, checklist[j].len) != false) == status) - goodfile = true; - - if (!goodfile) - break; + goodfile = W_VerifyWAD(handle, checklist, status); } } fclose(handle); diff --git a/src/w_wad.h b/src/w_wad.h index 651738850..91d4e733e 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -102,6 +102,7 @@ typedef struct wadfile_s restype_t type; lumpinfo_t *lumpinfo; lumpcache_t *lumpcache; + lumpcache_t *patchcache; #ifdef HWRENDER aatree_t *hwrcache; // patches are cached in renderer's native format #endif @@ -167,17 +168,13 @@ void *W_CacheLumpNum(lumpnum_t lump, INT32 tag); void *W_CacheLumpNumForce(lumpnum_t lumpnum, INT32 tag); boolean W_IsLumpCached(lumpnum_t lump, void *ptr); +boolean W_IsPatchCached(lumpnum_t lump, void *ptr); void *W_CacheLumpName(const char *name, INT32 tag); void *W_CachePatchName(const char *name, INT32 tag); -#ifdef HWRENDER -//void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch_t +void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch_t void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); // return a patch_t -#else -//#define W_CachePatchNumPwad(wad, lump, tag) W_CacheLumpNumPwad(wad, lump, tag) -#define W_CachePatchNum(lumpnum, tag) W_CacheLumpNum(lumpnum, tag) -#endif void W_UnlockCachedPatch(void *patch); diff --git a/src/win32/Srb2win.ico b/src/win32/Srb2win.ico index 700276fd4..3b37433db 100644 Binary files a/src/win32/Srb2win.ico and b/src/win32/Srb2win.ico differ diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc index b60ba750d..8e7fdccc9 100644 --- a/src/win32/Srb2win.rc +++ b/src/win32/Srb2win.rc @@ -1,6 +1,7 @@ //Microsoft Developer Studio generated resource script. // #include "resource.h" +#include "winver.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -62,9 +63,11 @@ END // Version // +#include "../doomdef.h" // Needed for version string + VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,9,0 - PRODUCTVERSION 1,0,9,0 + FILEVERSION 2,2,0,0 + PRODUCTVERSION 2,2,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -82,14 +85,14 @@ BEGIN VALUE "Comments", "Visit our web site at www.srb2.org for news and updates!\0" VALUE "CompanyName", "Sonic Team Junior\0" VALUE "FileDescription", "Sonic Robo Blast 2\0" - VALUE "FileVersion", "1, 09\0" + VALUE "FileVersion", VERSIONSTRING VALUE "InternalName", "srb2\0" - VALUE "LegalCopyright", "Copyright � 1998-2018 by Sonic Team Junior\0" + VALUE "LegalCopyright", "Copyright 1998-2019 by Sonic Team Junior\0" VALUE "LegalTrademarks", "Sonic the Hedgehog and related characters are trademarks of Sega.\0" VALUE "OriginalFilename", "srb2win.exe\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "Sonic Robo Blast 2\0" - VALUE "ProductVersion", "1, 09\0" + VALUE "ProductVersion", VERSIONSTRING VALUE "SpecialBuild", "\0" END END diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index d10f73b58..93b3ff523 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -327,7 +327,7 @@ static inline VOID I_GetConsoleEvents(VOID) break; case VK_RETURN: entering_con_command = false; - // Fall through. + /* FALLTHRU */ default: ev.data1 = MapVirtualKey(input.Event.KeyEvent.wVirtualKeyCode,2); // convert in to char } diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c index e2f32fa61..11c7a6744 100644 --- a/src/win32/win_vid.c +++ b/src/win32/win_vid.c @@ -322,9 +322,9 @@ static inline boolean I_SkipFrame(void) case GS_LEVEL: if (!paused) return false; - /* FALLTHRU */ //case GS_TIMEATTACK: -- sorry optimisation but now we have a cool level platter and that being laggardly looks terrible #ifndef CLIENT_LOADINGSCREEN + /* FALLTHRU */ case GS_WAITINGPLAYERS: #endif return skip; // Skip odd frames diff --git a/src/y_inter.c b/src/y_inter.c index 975902ab0..0d6a3d03c 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -261,7 +261,7 @@ void Y_IntermissionDrawer(void) // draw time ST_DrawPatchFromHud(HUD_TIME, sbotime); - if (cv_timetic.value == 1) + if (cv_timetic.value == 3) ST_DrawNumFromHud(HUD_SECONDS, data.coop.tics); else { @@ -275,8 +275,7 @@ void Y_IntermissionDrawer(void) ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon); // Colon ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2); // Seconds - // we should show centiseconds on the intermission screen too, if the conditions are right. - if (modeattacking || cv_timetic.value == 2) + if (cv_timetic.value == 1 || cv_timetic.value == 2 || modeattacking) // there's not enough room for tics in splitscreen, don't even bother trying! { ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics @@ -429,7 +428,7 @@ void Y_IntermissionDrawer(void) { if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10)) break; - V_DrawContinueIcon(246 + xoffset5 - (i*12), 162+yoffset, 0, *data.spec.playerchar, *data.spec.playercolor); + V_DrawContinueIcon(246 + xoffset5 - (i*20), 162+yoffset, 0, *data.spec.playerchar, *data.spec.playercolor); } } }