diff --git a/src/console.c b/src/console.c index bd19cdf3b..ab8635b66 100644 --- a/src/console.c +++ b/src/console.c @@ -33,6 +33,7 @@ #include "i_system.h" #include "d_main.h" #include "m_menu.h" +#include "filesrch.h" #ifdef _WINDOWS #include "win32/win_main.h" @@ -1303,12 +1304,15 @@ void CONS_Alert(alerttype_t level, const char *fmt, ...) switch (level) { case CONS_NOTICE: + // no notice for notices, hehe CONS_Printf("\x83" "%s" "\x80 ", M_GetText("NOTICE:")); break; case CONS_WARNING: + refreshdirmenu |= REFRESHDIR_WARNING; CONS_Printf("\x82" "%s" "\x80 ", M_GetText("WARNING:")); break; case CONS_ERROR: + refreshdirmenu |= REFRESHDIR_ERROR; CONS_Printf("\x85" "%s" "\x80 ", M_GetText("ERROR:")); break; } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 12ff0a962..c8e8b0080 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -343,6 +343,7 @@ typedef struct } ATTRPACK clientconfig_pak; #define MAXSERVERNAME 32 +#define MAXFILENEEDED 915 // This packet is too large typedef struct { @@ -364,7 +365,7 @@ typedef struct unsigned char mapmd5[16]; UINT8 actnum; UINT8 iszone; - UINT8 fileneeded[915]; // is filled with writexxx (byteptr.h) + UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) } ATTRPACK serverinfo_pak; typedef struct diff --git a/src/d_main.c b/src/d_main.c index 698216982..e56a631a2 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -74,6 +74,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "m_cond.h" // condition initialization #include "fastcmp.h" #include "keys.h" +#include "filesrch.h" // refreshdirmenu, mainwadstally #ifdef CMAKECONFIG #include "config.h" @@ -681,6 +682,8 @@ void D_SRB2Loop(void) realtics = entertic - oldentertics; oldentertics = entertic; + refreshdirmenu = 0; // not sure where to put this, here as good as any? + #ifdef DEBUGFILE if (!realtics) if (debugload) @@ -954,43 +957,29 @@ static void IdentifyVersion(void) D_AddFile(va(pandf,srb2waddir,"patch.dta")); #endif +#define MUSICTEST(str) \ + {\ + const char *musicpath = va(pandf,srb2waddir,str);\ + int ms = W_VerifyNMUSlumps(musicpath); \ + if (ms == 1) \ + D_AddFile(musicpath); \ + else if (ms == 0) \ + I_Error("File "str" has been modified with non-music/sound lumps"); \ + } + // SRB2kart - Add graphics (temp) // The command for md5 checks is "W_VerifyFileMD5" - looks for ASSET_HASH_SRB2_SRB in config.h.in D_AddFile(va(pandf,srb2waddir,"gfx.kart")); D_AddFile(va(pandf,srb2waddir,"chars.kart")); D_AddFile(va(pandf,srb2waddir,"maps.kart")); - D_AddFile(va(pandf,srb2waddir,"sounds.kart")); + //D_AddFile(va(pandf,srb2waddir,"sounds.kart")); + MUSICTEST("sounds.kart") #ifdef USE_PATCH_KART D_AddFile(va(pandf,srb2waddir,"patch.kart")); #endif -#if !defined (HAVE_SDL) || defined (HAVE_MIXER) - { -#if defined (DC) && 0 - const char *musicfile = "music_dc.dta"; -#else - const char *musicfile = "music.dta"; -#endif - const char *kmusicfile; - const char *musicpath = va(pandf,srb2waddir,musicfile); - const char *kmusicpath; - int ms = W_VerifyNMUSlumps(musicpath); // Don't forget the music! - int kms; - if (ms == 1) - D_AddFile(musicpath); - else if (ms == 0) - I_Error("File %s has been modified with non-music lumps",musicfile); - - kmusicfile = "music.kart"; - kmusicpath = va(pandf,srb2waddir,kmusicfile); - kms = W_VerifyNMUSlumps(kmusicpath); // kill me now - - if (kms == 1) - D_AddFile(kmusicpath); - else if (kms == 0) - I_Error("File %s has been modified with non-music lumps",kmusicfile); - } -#endif + MUSICTEST("music.dta") + MUSICTEST("music.kart") } /* ======================================================================== */ @@ -1250,26 +1239,43 @@ void D_SRB2Main(void) #endif D_CleanFile(); + mainwads = 0; + #ifndef DEVELOP // md5s last updated 12/14/14 // Check MD5s of autoloaded files - mainwads = 0; - W_VerifyFileMD5(mainwads, ASSET_HASH_SRB2_SRB); mainwads++; // srb2.srb/srb2.wad + W_VerifyFileMD5(mainwads, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad #ifdef USE_PATCH_DTA - W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_DTA); mainwads++; // patch.dta + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_DTA); // patch.dta #endif - W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); mainwads++; // gfx.kart - W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); mainwads++; // chars.kart - W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); mainwads++; // maps.kart - //W_VerifyFileMD5(mainwads, ASSET_HASH_SOUNDS_KART); mainwads++; // sounds.kart - doesn't trigger modifiedgame, doesn't need an MD5...? + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_KART); // gfx.kart + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_KART); // chars.kart + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_KART); // maps.kart + mainwads++; //W_VerifyFileMD5(5, ASSET_HASH_SOUNDS_KART); -- sounds.kart - doesn't trigger modifiedgame, doesn't need an MD5...? #ifdef USE_PATCH_KART - W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_KART); mainwads++; // patch.kart + mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_KART); // patch.kart #endif - - // don't check music.dta because people like to modify it, and it doesn't matter if they do + mainwads++; // music.dta + mainwads++; // music.kart + // don't check music.dta or kart because people like to modify it, and it doesn't matter if they do // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. +#else +#ifdef USE_PATCH_DTA + mainwads++; // patch.dta +#endif + mainwads++; // gfx.kart + mainwads++; // chars.kart + mainwads++; // maps.kart + mainwads++; // sounds.kart +#ifdef USE_PATCH_KART + mainwads++; // patch.kart +#endif + mainwads++; // music.dta + mainwads++; // music.kart #endif //ifndef DEVELOP + mainwadstally = packetsizetally; + cht_Init(); //---------------------------------------------------- READY SCREEN diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 72ea15888..144e4bf94 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -38,6 +38,7 @@ #include "d_main.h" #include "m_random.h" #include "f_finale.h" +#include "filesrch.h" #include "mserv.h" #include "md5.h" #include "z_zone.h" @@ -371,6 +372,7 @@ static CV_PossibleValue_t kartdebugamount_cons_t[] = {{1, "MIN"}, {255, "MAX"}, consvar_t cv_kartdebugamount = {"kartdebugamount", "1", CV_NETVAR|CV_CHEAT, kartdebugamount_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugshrink = {"kartdebugshrink", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugdistribution = {"kartdebugdistribution", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartdebughuddrop = {"kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugcheckpoint = {"kartdebugcheckpoint", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -831,6 +833,14 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_driftaxis3); CV_RegisterVar(&cv_driftaxis4); + // filesrch.c + CV_RegisterVar(&cv_addons_option); + CV_RegisterVar(&cv_addons_folder); + CV_RegisterVar(&cv_addons_md5); + CV_RegisterVar(&cv_addons_showall); + CV_RegisterVar(&cv_addons_search_type); + CV_RegisterVar(&cv_addons_search_case); + // WARNING: the order is important when initialising mouse2 // we need the mouse2port CV_RegisterVar(&cv_mouse2port); @@ -3758,25 +3768,12 @@ static void Command_Addfile(void) break; ++p; // check total packet size and no of files currently loaded + // See W_LoadWadFile in w_wad.c + if ((numwadfiles >= MAX_WADFILES) + || ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8))) { - size_t packetsize = 0; - serverinfo_pak *dummycheck = NULL; - - // Shut the compiler up. - (void)dummycheck; - - // See W_LoadWadFile in w_wad.c - for (i = 0; i < numwadfiles; i++) - packetsize += nameonlylength(wadfiles[i]->filename) + 22; - - packetsize += nameonlylength(fn) + 22; - - if ((numwadfiles >= MAX_WADFILES) - || (packetsize > sizeof(dummycheck->fileneeded))) - { - CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); - return; - } + CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); + return; } WRITESTRINGN(buf_p,p,240); @@ -3862,11 +3859,6 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) boolean kick = false; boolean toomany = false; INT32 i,j; - size_t packetsize = 0; - serverinfo_pak *dummycheck = NULL; - - // Shut the compiler up. - (void)dummycheck; READSTRINGN(*cp, filename, 240); READMEM(*cp, md5sum, 16); @@ -3893,13 +3885,8 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) } // See W_LoadWadFile in w_wad.c - for (i = 0; i < numwadfiles; i++) - packetsize += nameonlylength(wadfiles[i]->filename) + 22; - - packetsize += nameonlylength(filename) + 22; - if ((numwadfiles >= MAX_WADFILES) - || (packetsize > sizeof(dummycheck->fileneeded))) + || ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8))) toomany = true; else ncs = findfile(filename,md5sum,true); @@ -4068,6 +4055,9 @@ static void Command_Playintro_f(void) if (netgame) return; + if (dirmenu) + closefilemenu(true); + F_StartIntro(); } @@ -4777,6 +4767,9 @@ void Command_ExitGame_f(void) cv_debug = 0; emeralds = 0; + if (dirmenu) + closefilemenu(true); + if (!modeattacking) D_StartTitle(); } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 40ec3fc3b..aee243cf3 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -133,7 +133,7 @@ extern consvar_t cv_karteliminatelast; extern consvar_t cv_votetime; -extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution; +extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop; extern consvar_t cv_kartdebugcheckpoint; extern consvar_t cv_itemfinder; diff --git a/src/d_netfil.c b/src/d_netfil.c index 6742cfe28..7927c4ecf 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -104,6 +104,7 @@ INT32 lastfilenum = -1; /** Fills a serverinfo packet with information about wad files loaded. * * \todo Give this function a better name since it is in global scope. + * Used to have size limiting built in - now handed via W_LoadWadFile in w_wad.c * */ UINT8 *PutFileNeeded(void) @@ -112,29 +113,22 @@ UINT8 *PutFileNeeded(void) UINT8 *p = netbuffer->u.serverinfo.fileneeded; char wadfilename[MAX_WADPATH] = ""; UINT8 filestatus; - size_t bytesused = 0; for (i = 0; i < numwadfiles; i++) { - // If it has only music/sound lumps, mark it as unimportant - if (W_VerifyNMUSlumps(wadfiles[i]->filename)) - filestatus = 0; - else - filestatus = 1; // Important + // If it has only music/sound lumps, don't put it in the list + if (!wadfiles[i]->important) + continue; + + filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS // Store in the upper four bits if (!cv_downloading.value) filestatus += (2 << 4); // Won't send - else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)) - filestatus += (0 << 4); // Won't send - else + else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024)) filestatus += (1 << 4); // Will send if requested - - bytesused += (nameonlylength(wadfilename) + 22); - - // Don't write too far... - if (bytesused > sizeof(netbuffer->u.serverinfo.fileneeded)) - I_Error("Too many wad files added to host a game. (%s, stopped on %s)\n", sizeu1(bytesused), wadfilename); + // else + // filestatus += (0 << 4); -- Won't send, too big WRITEUINT8(p, filestatus); @@ -167,7 +161,6 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) { fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet filestatus = READUINT8(p); // The first byte is the file status - fileneeded[i].important = (UINT8)(filestatus & 3); fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size fileneeded[i].file = NULL; // The file isn't open yet @@ -197,7 +190,7 @@ boolean CL_CheckDownloadable(void) UINT8 i,dlstatus = 0; for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && fileneeded[i].important) + if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { if (fileneeded[i].willsend == 1) continue; @@ -218,7 +211,7 @@ boolean CL_CheckDownloadable(void) // not downloadable, put reason in console CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n")); for (i = 0; i < fileneedednum; i++) - if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN && fileneeded[i].important) + if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) { CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10); @@ -271,7 +264,7 @@ boolean CL_SendRequestFile(void) for (i = 0; i < fileneedednum; i++) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN - && fileneeded[i].important && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) + && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) { I_Error("Attempted to download files that were not sendable"); } @@ -280,8 +273,7 @@ boolean CL_SendRequestFile(void) netbuffer->packettype = PT_REQUESTFILE; p = (char *)netbuffer->u.textcmd; for (i = 0; i < fileneedednum; i++) - if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) - && fileneeded[i].important) + if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) { totalfreespaceneeded += fileneeded[i].totalsize; nameonly(fileneeded[i].filename); @@ -339,10 +331,6 @@ INT32 CL_CheckFiles(void) INT32 ret = 1; size_t packetsize = 0; size_t filestoget = 0; - serverinfo_pak *dummycheck = NULL; - - // Shut the compiler up. - (void)dummycheck; // if (M_CheckParm("-nofiles")) // return 1; @@ -360,13 +348,7 @@ INT32 CL_CheckFiles(void) CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n"); for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;) { - if (i < fileneedednum && !fileneeded[i].important) - { - // Eh whatever, don't care - ++i; - continue; - } - if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename)) + if (j < numwadfiles && !wadfiles[j]->important) { // Unimportant on our side. still don't care. ++j; @@ -392,8 +374,7 @@ INT32 CL_CheckFiles(void) } // See W_LoadWadFile in w_wad.c - for (i = 0; i < numwadfiles; i++) - packetsize += nameonlylength(wadfiles[i]->filename) + 22; + packetsize = packetsizetally; for (i = 1; i < fileneedednum; i++) { @@ -411,13 +392,13 @@ INT32 CL_CheckFiles(void) break; } } - if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important) + if (fileneeded[i].status != FS_NOTFOUND) continue; packetsize += nameonlylength(fileneeded[i].filename) + 22; if ((numwadfiles+filestoget >= MAX_WADFILES) - || (packetsize > sizeof(dummycheck->fileneeded))) + || (packetsize > MAXFILENEEDED*sizeof(UINT8))) return 3; filestoget++; @@ -449,27 +430,8 @@ void CL_LoadServerFiles(void) fileneeded[i].status = FS_OPEN; } else if (fileneeded[i].status == FS_MD5SUMBAD) - { - // If the file is marked important, don't even bother proceeding. - if (fileneeded[i].important) - I_Error("Wrong version of important file %s", fileneeded[i].filename); - - // If it isn't, no need to worry the user with a console message, - // although it can't hurt to put something in the debug file. - - // ...but wait a second. What if the local version is "important"? - if (!W_VerifyNMUSlumps(fileneeded[i].filename)) - I_Error("File %s should only contain music and sound effects!", - fileneeded[i].filename); - - // Okay, NOW we know it's safe. Whew. - P_AddWadFile(fileneeded[i].filename, NULL); - if (fileneeded[i].important) - G_SetGameModified(true); - fileneeded[i].status = FS_OPEN; - DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename)); - } - else if (fileneeded[i].important) + I_Error("Wrong version of file %s", fileneeded[i].filename); + else { const char *s; switch(fileneeded[i].status) @@ -939,10 +901,11 @@ void nameonly(char *s) { ns = &(s[j+1]); len = strlen(ns); - if (false) +#if 0 M_Memcpy(s, ns, len+1); - else +#else memmove(s, ns, len+1); +#endif return; } } diff --git a/src/d_netfil.h b/src/d_netfil.h index b9b7b2f2e..6fdd0a8a1 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -35,7 +35,6 @@ typedef enum typedef struct { - UINT8 important; UINT8 willsend; // Is the server willing to send it? char filename[MAX_WADPATH]; UINT8 md5sum[16]; diff --git a/src/d_player.h b/src/d_player.h index 822ea305a..373110dd3 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -305,6 +305,7 @@ typedef enum k_accelboost, // Boost value smoothing for acceleration k_boostcam, // Camera push forward on boost k_destboostcam, // Ditto + k_aizdriftstrat, // Let go of your drift while boosting? Helper for the SICK STRATZ you have just unlocked k_itemroulette, // Used for the roulette when deciding what item to give you (was "pw_kartitem") k_roulettetype, // Used for the roulette, for deciding type (currently only used for Battle, to give you better items from Karma items) diff --git a/src/dehacked.c b/src/dehacked.c index 373289527..99d952596 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1830,6 +1830,7 @@ static actionpointer_t actionpointers[] = {{A_JawzExplode}, "A_JAWZEXPLODE"}, // SRB2kart {{A_MineExplode}, "A_MINEEXPLODE"}, // SRB2kart {{A_BallhogExplode}, "A_BALLHOGEXPLODE"}, // SRB2kart + {{A_LightningFollowPlayer}, "A_LIGHTNINGFOLLOWPLAYER"}, //SRB2kart {{A_OrbitNights}, "A_ORBITNIGHTS"}, {{A_GhostMe}, "A_GHOSTME"}, {{A_SetObjectState}, "A_SETOBJECTSTATE"}, @@ -6205,6 +6206,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_RANDOMITEMPOP4", //} + "S_ITEMICON", + // Signpost sparkles "S_SIGNSPARK1", "S_SIGNSPARK2", @@ -6270,6 +6273,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_KARTFIRE7", "S_KARTFIRE8", + // Angel Island Drift Strat Dust (what a mouthful!) + "S_KARTAIZDRIFTSTRAT", + // Invincibility Sparks "S_KARTINVULN_SMALL1", "S_KARTINVULN_SMALL2", @@ -6518,16 +6524,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Audience Members "S_RANDOMAUDIENCE", - "S_AUDIENCE_TOAD1", - "S_AUDIENCE_TOAD2", - "S_AUDIENCE_BOO1", - "S_AUDIENCE_BOO2", - "S_AUDIENCE_GMBA1", - "S_AUDIENCE_GMBA2", - "S_AUDIENCE_SHYG1", - "S_AUDIENCE_SHYG2", - "S_AUDIENCE_SNIF1", - "S_AUDIENCE_SNIF2", + "S_AUDIENCE_CHAO_CHEER1", + "S_AUDIENCE_CHAO_CHEER2", + "S_AUDIENCE_CHAO_WIN1", + "S_AUDIENCE_CHAO_WIN2", + "S_AUDIENCE_CHAO_LOSE", "S_FANCHAR_KOTE", "S_FANCHAR_RYAN", @@ -6703,6 +6704,54 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_KARMAWHEEL", // Karma player wheels + // Thunder shield use stuff; + "S_KSPARK1", // Sparkling Radius + "S_KSPARK2", + "S_KSPARK3", + "S_KSPARK4", + "S_KSPARK5", + "S_KSPARK6", + "S_KSPARK7", + "S_KSPARK8", + "S_KSPARK9", + "S_KSPARK10", + "S_KSPARK11", + "S_KSPARK12", + "S_KSPARK13", // ... that's an awful lot. + + "S_LZIO11", // Straight lightning bolt + "S_LZIO12", + "S_LZIO13", + "S_LZIO14", + "S_LZIO15", + "S_LZIO16", + "S_LZIO17", + "S_LZIO18", + "S_LZIO19", + + "S_LZIO21", // Straight lightning bolt (flipped) + "S_LZIO22", + "S_LZIO23", + "S_LZIO24", + "S_LZIO25", + "S_LZIO26", + "S_LZIO27", + "S_LZIO28", + "S_LZIO29", + + "S_KLIT1", // Diagonal lightning. No, it not being straight doesn't make it gay. + "S_KLIT2", + "S_KLIT3", + "S_KLIT4", + "S_KLIT5", + "S_KLIT6", + "S_KLIT7", + "S_KLIT8", + "S_KLIT9", + "S_KLIT10", + "S_KLIT11", + "S_KLIT12", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -7219,6 +7268,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BLUEDIAG", "MT_RANDOMITEM", "MT_RANDOMITEMPOP", + "MT_FLOATINGITEM", + "MT_SIGNSPARKLE", "MT_FASTLINE", @@ -7226,6 +7277,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BOOSTFLAME", "MT_BOOSTSMOKE", "MT_SNEAKERTRAIL", + "MT_AIZDRIFTSTRAT", "MT_SPARKLETRAIL", "MT_INVULNFLASH", "MT_WIPEOUTTRAIL", @@ -7706,6 +7758,7 @@ static const char *const KARTSTUFF_LIST[] = { "ACCELBOOST", "BOOSTCAM", "DESTBOOSTCAM", + "AIZDRIFTSTRAT", "ITEMROULETTE", "ROULETTETYPE", diff --git a/src/filesrch.c b/src/filesrch.c index 2463e7178..98be1f39c 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -31,6 +31,8 @@ #include "filesrch.h" #include "d_netfil.h" #include "m_misc.h" +#include "z_zone.h" +#include "m_menu.h" // Addons_option_Onchange #if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) && !defined (_XBOX) @@ -255,6 +257,28 @@ readdir (DIR * dirp) return (struct dirent *) 0; } +/* + * rewinddir + * + * Makes the next readdir start from the beginning. + */ +int +rewinddir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) + { + errno = EFAULT; + return -1; + } + + dirp->dd_stat = 0; + + return 0; +} + /* * closedir * @@ -285,6 +309,41 @@ closedir (DIR * dirp) return rc; } #endif + +static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"}, +#if 1 + {1, "HOME"}, {2, "SRB2"}, +#endif + {3, "CUSTOM"}, {0, NULL}}; + +consvar_t cv_addons_option = {"addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_addons_folder = {"addons_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; + +static CV_PossibleValue_t addons_md5_cons_t[] = {{0, "Name"}, {1, "Contents"}, {0, NULL}}; +consvar_t cv_addons_md5 = {"addons_md5", "Name", CV_SAVE, addons_md5_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_addons_showall = {"addons_showall", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; + +consvar_t cv_addons_search_case = {"addons_search_case", "No", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; + +static CV_PossibleValue_t addons_search_type_cons_t[] = {{0, "Start"}, {1, "Anywhere"}, {0, NULL}}; +consvar_t cv_addons_search_type = {"addons_search_type", "Anywhere", CV_SAVE, addons_search_type_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + +char menupath[1024]; +size_t menupathindex[menudepth]; +size_t menudepthleft = menudepth; + +char menusearch[MAXSTRINGLENGTH+1]; + +char **dirmenu, **coredirmenu; // core only local for this file +size_t sizedirmenu, sizecoredirmenu; // ditto +size_t dir_on[menudepth]; +UINT8 refreshdirmenu = 0; +char *refreshdirname = NULL; + +size_t packetsizetally = 0; +size_t mainwadstally = 0; + #if defined (_XBOX) && defined (_MSC_VER) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -296,6 +355,25 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want completepath = false; return FS_NOTFOUND; } + +void closefilemenu(boolean validsize) +{ + (void)validsize; + return; +} + +void searchfilemenu(char *tempname) +{ + (void)tempname; + return; +} + +boolean preparefilemenu(boolean samedepth) +{ + (void)samedepth; + return false; +} + #elif defined (_WIN32_WCE) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) @@ -346,7 +424,27 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want #endif return FS_NOTFOUND; } + +void closefilemenu(boolean validsize) +{ + (void)validsize; + return; +} + +void searchfilemenu(char *tempname) +{ + (void)tempname; + return; +} + +boolean preparefilemenu(boolean samedepth) +{ + (void)samedepth; + return false; +} + #else + filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) { filestatus_t retval = FS_NOTFOUND; @@ -387,25 +485,29 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want { searchpath[searchpathindex[depthleft]]=0; dent = readdir(dirhandle[depthleft]); - if (dent) - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); if (!dent) + { closedir(dirhandle[depthleft++]); - else if (dent->d_name[0]=='.' && + continue; + } + + if (dent->d_name[0]=='.' && (dent->d_name[1]=='\0' || (dent->d_name[1]=='.' && dent->d_name[2]=='\0'))) { // we don't want to scan uptree + continue; } - else if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat - { - // was the file (re)moved? can't stat it - } + + // okay, now we actually want searchpath to incorporate d_name + strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); + + if (stat(searchpath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it else if (S_ISDIR(fsstat.st_mode) && depthleft) { - strcpy(&searchpath[searchpathindex[depthleft]],dent->d_name); searchpathindex[--depthleft] = strlen(searchpath) + 1; dirhandle[depthleft] = opendir(searchpath); if (!dirhandle[depthleft]) @@ -444,6 +546,361 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want free(searchname); free(searchpathindex); free(dirhandle); + return retval; } + +char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two) + "\5.txt", "\5.cfg", // exec + "\5.wad", "\6.kart", /*"\5.pk3",*/ "\5.soc", "\5.lua"}; // addfile + +char filenamebuf[MAX_WADFILES][MAX_WADPATH]; + + +static boolean filemenucmp(char *haystack, char *needle) +{ + static char localhaystack[128]; + strlcpy(localhaystack, haystack, 128); + if (!cv_addons_search_case.value) + strupr(localhaystack); + if (cv_addons_search_type.value) + return (strstr(localhaystack, needle) != 0); + return (!strncmp(localhaystack, needle, menusearch[0])); +} + +void closefilemenu(boolean validsize) +{ + // search + if (dirmenu) + { + if (dirmenu != coredirmenu) + { + if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS)) + { + Z_Free(dirmenu[0]); + dirmenu[0] = NULL; + } + Z_Free(dirmenu); + } + dirmenu = NULL; + sizedirmenu = 0; + } + + if (coredirmenu) + { + // core + if (validsize) + { + for (; sizecoredirmenu > 0; sizecoredirmenu--) + { + Z_Free(coredirmenu[sizecoredirmenu-1]); + coredirmenu[sizecoredirmenu-1] = NULL; + } + } + else + sizecoredirmenu = 0; + + Z_Free(coredirmenu); + coredirmenu = NULL; + } + + if (refreshdirname) + Z_Free(refreshdirname); + refreshdirname = NULL; +} + +void searchfilemenu(char *tempname) +{ + size_t i, first; + char localmenusearch[MAXSTRINGLENGTH] = ""; + + if (dirmenu) + { + if (dirmenu != coredirmenu) + { + if (dirmenu[0] && ((UINT8)(dirmenu[0][DIR_TYPE]) == EXT_NORESULTS)) + { + Z_Free(dirmenu[0]); + dirmenu[0] = NULL; + } + //Z_Free(dirmenu); -- Z_Realloc later tho... + } + else + dirmenu = NULL; + } + + first = (((UINT8)(coredirmenu[0][DIR_TYPE]) == EXT_UP) ? 1 : 0); // skip UP... + + if (!menusearch[0]) + { + if (dirmenu) + Z_Free(dirmenu); + dirmenu = coredirmenu; + sizedirmenu = sizecoredirmenu; + + if (tempname) + { + for (i = first; i < sizedirmenu; i++) + { + if (!strcmp(dirmenu[i]+DIR_STRING, tempname)) + { + dir_on[menudepthleft] = i; + break; + } + } + + if (i == sizedirmenu) + dir_on[menudepthleft] = first; + + Z_Free(tempname); + } + + return; + } + + strcpy(localmenusearch, menusearch+1); + if (!cv_addons_search_case.value) + strupr(localmenusearch); + + sizedirmenu = 0; + for (i = first; i < sizecoredirmenu; i++) + { + if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch)) + sizedirmenu++; + } + + if (!sizedirmenu) // no results... + { + if ((!(dirmenu = Z_Realloc(dirmenu, sizeof(char *), PU_STATIC, NULL))) + || !(dirmenu[0] = Z_StrDup(va("%c\13No results...", EXT_NORESULTS)))) + I_Error("searchfilemenu(): could not create \"No results...\"."); + sizedirmenu = 1; + dir_on[menudepthleft] = 0; + if (tempname) + Z_Free(tempname); + return; + } + + if (!(dirmenu = Z_Realloc(dirmenu, sizedirmenu*sizeof(char *), PU_STATIC, NULL))) + I_Error("searchfilemenu(): could not reallocate dirmenu."); + + sizedirmenu = 0; + for (i = first; i < sizecoredirmenu; i++) + { + if (filemenucmp(coredirmenu[i]+DIR_STRING, localmenusearch)) + { + if (tempname && !strcmp(coredirmenu[i]+DIR_STRING, tempname)) + { + dir_on[menudepthleft] = sizedirmenu; + Z_Free(tempname); + tempname = NULL; + } + dirmenu[sizedirmenu++] = coredirmenu[i]; // pointer reuse + } + } + + if (tempname) + { + dir_on[menudepthleft] = 0; //first; -- can't be first, causes problems + Z_Free(tempname); + } +} + +boolean preparefilemenu(boolean samedepth) +{ + DIR *dirhandle; + struct dirent *dent; + struct stat fsstat; + size_t pos = 0, folderpos = 0, numfolders = 0; + char *tempname = NULL; + + if (samedepth) + { + if (dirmenu && dirmenu[dir_on[menudepthleft]]) + tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL + } + else + menusearch[0] = menusearch[1] = 0; // clear search + + if (!(dirhandle = opendir(menupath))) // get directory + { + closefilemenu(true); + return false; + } + + for (; sizecoredirmenu > 0; sizecoredirmenu--) // clear out existing items + { + Z_Free(coredirmenu[sizecoredirmenu-1]); + coredirmenu[sizecoredirmenu-1] = NULL; + } + + while (true) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + if (!S_ISDIR(fsstat.st_mode)) // file + { + if (!cv_addons_showall.value) + { + size_t len = strlen(dent->d_name)+1; + UINT8 ext; + for (ext = 0; ext < NUM_EXT_TABLE; ext++) + if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison + if (ext == NUM_EXT_TABLE) continue; // not an addfile-able (or exec-able) file + } + } + else // directory + numfolders++; + + sizecoredirmenu++; + } + } + + if (!sizecoredirmenu) + { + closedir(dirhandle); + closefilemenu(false); + if (tempname) + Z_Free(tempname); + return false; + } + + if (menudepthleft != menudepth-1) // Make room for UP... + { + sizecoredirmenu++; + numfolders++; + folderpos++; + } + + if (dirmenu && dirmenu == coredirmenu) + dirmenu = NULL; + + if (!(coredirmenu = Z_Realloc(coredirmenu, sizecoredirmenu*sizeof(char *), PU_STATIC, NULL))) + { + closedir(dirhandle); // just in case + I_Error("preparefilemenu(): could not reallocate coredirmenu."); + } + + rewinddir(dirhandle); + + while ((pos+folderpos) < sizecoredirmenu) + { + menupath[menupathindex[menudepthleft]] = 0; + dent = readdir(dirhandle); + + if (!dent) + break; + else if (dent->d_name[0]=='.' && + (dent->d_name[1]=='\0' || + (dent->d_name[1]=='.' && + dent->d_name[2]=='\0'))) + continue; // we don't want to scan uptree + + strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); + + if (stat(menupath,&fsstat) < 0) // do we want to follow symlinks? if not: change it to lstat + ; // was the file (re)moved? can't stat it + else // is a file or directory + { + char *temp; + size_t len = strlen(dent->d_name)+1; + UINT8 ext = EXT_FOLDER; + UINT8 folder; + + if (!S_ISDIR(fsstat.st_mode)) // file + { + if (!((numfolders+pos) < sizecoredirmenu)) continue; // crash prevention + for (; ext < NUM_EXT_TABLE; ext++) + if (!strcasecmp(exttable[ext]+1, dent->d_name+len-(exttable[ext][0]))) break; // extension comparison + if (ext == NUM_EXT_TABLE && !cv_addons_showall.value) continue; // not an addfile-able (or exec-able) file + ext += EXT_START; // moving to be appropriate position + + if (ext >= EXT_LOADSTART) + { + size_t i; + for (i = 0; i < numwadfiles; i++) + { + if (!filenamebuf[i][0]) + { + strncpy(filenamebuf[i], wadfiles[i]->filename, MAX_WADPATH); + filenamebuf[i][MAX_WADPATH - 1] = '\0'; + nameonly(filenamebuf[i]); + } + + if (strcmp(dent->d_name, filenamebuf[i])) + continue; + if (cv_addons_md5.value && !checkfilemd5(menupath, wadfiles[i]->md5sum)) + continue; + + ext |= EXT_LOADED; + } + } + else if (ext == EXT_TXT) + { + if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt")) + ext |= EXT_LOADED; + } + + if (!strcmp(dent->d_name, configfile)) + ext |= EXT_LOADED; + + folder = 0; + } + else // directory + len += (folder = 1); + + if (len > 255) + len = 255; + + if (!(temp = Z_Malloc((len+DIR_STRING+folder) * sizeof (char), PU_STATIC, NULL))) + I_Error("preparefilemenu(): could not create file entry."); + temp[DIR_TYPE] = ext; + temp[DIR_LEN] = (UINT8)(len); + strlcpy(temp+DIR_STRING, dent->d_name, len); + if (folder) + { + strcpy(temp+len, PATHSEP); + coredirmenu[folderpos++] = temp; + } + else + coredirmenu[numfolders + pos++] = temp; + } + } + + closedir(dirhandle); + + if ((menudepthleft != menudepth-1) // now for UP... entry + && !(coredirmenu[0] = Z_StrDup(va("%c\5UP...", EXT_UP)))) + I_Error("preparefilemenu(): could not create \"UP...\"."); + + menupath[menupathindex[menudepthleft]] = 0; + sizecoredirmenu = (numfolders+pos); // just in case things shrink between opening and rewind + + if (!sizecoredirmenu) + { + dir_on[menudepthleft] = 0; + closefilemenu(false); + return false; + } + + searchfilemenu(tempname); + + return true; +} + #endif diff --git a/src/filesrch.h b/src/filesrch.h index 33b148d4b..75fd70af7 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -6,6 +6,9 @@ #include "doomdef.h" #include "d_netfil.h" +#include "m_menu.h" // MAXSTRINGLENGTH + +extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type; /** \brief The filesearch function @@ -25,4 +28,69 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth); +#define menudepth 20 + +extern char menupath[1024]; +extern size_t menupathindex[menudepth]; +extern size_t menudepthleft; + +extern char menusearch[MAXSTRINGLENGTH+1]; + +extern char **dirmenu; +extern size_t sizedirmenu; +extern size_t dir_on[menudepth]; +extern UINT8 refreshdirmenu; +extern char *refreshdirname; + +extern size_t packetsizetally; +extern size_t mainwadstally; + +typedef enum +{ + EXT_FOLDER = 0, + EXT_UP, + EXT_NORESULTS, + EXT_START, + EXT_TXT = EXT_START, + EXT_CFG, + EXT_LOADSTART, + EXT_WAD = EXT_LOADSTART, + EXT_KART, + //EXT_PK3, + EXT_SOC, + EXT_LUA, // allowed even if not HAVE_BLUA so that we can yell on load attempt + NUM_EXT, + NUM_EXT_TABLE = NUM_EXT-EXT_START, + EXT_LOADED = 0x80 + /* + obviously there can only be 0x7F supported extensions in + addons menu because we're cramming this into a char out of + laziness/easy memory allocation (what's the difference?) + and have stolen a bit to show whether it's loaded or not + in practice the size of the data type is probably overkill + toast 02/05/17 + */ +} ext_enum; + +typedef enum +{ + DIR_TYPE = 0, + DIR_LEN, + DIR_STRING +} dirname_enum; + +typedef enum +{ + REFRESHDIR_NORMAL = 1, + REFRESHDIR_ADDFILE = 2, + REFRESHDIR_WARNING = 4, + REFRESHDIR_ERROR = 8, + REFRESHDIR_NOTLOADED = 16, + REFRESHDIR_MAX = 32 +} refreshdir_enum; + +void closefilemenu(boolean validsize); +void searchfilemenu(char *tempname); +boolean preparefilemenu(boolean samedepth); + #endif // __FILESRCH_H__ diff --git a/src/info.c b/src/info.c index 91e4020cd..c0fb24fb4 100644 --- a/src/info.c +++ b/src/info.c @@ -60,7 +60,8 @@ char sprnames[NUMSPRITES + 1][5] = "KRBM","BHOG","BHBM","BLIG","LIGH","THNS","SINK","SITR","KBLN","DEZL", "POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO", "CRAB","SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO", - "ITEM","ITMO","ITMI","ITMN","WANT","PBOM","RETI","VIEW" + "ITEM","ITMO","ITMI","ITMN","WANT","PBOM","RETI","AIDU","KSPK","LZI1", + "LZI2","KLIT","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -1725,11 +1726,11 @@ state_t states[NUMSTATES] = {SPR_IVSP, FF_ANIMATE, 32, {NULL}, 31, 1, S_NULL}, // S_IVSP // Super Sonic Spark - {SPR_SSPK, 0, 2, {NULL}, 0, 0, S_SSPK2}, // S_SSPK1 - {SPR_SSPK, 1, 2, {NULL}, 0, 0, S_SSPK3}, // S_SSPK2 - {SPR_SSPK, 2, 2, {NULL}, 0, 0, S_SSPK4}, // S_SSPK3 - {SPR_SSPK, 1, 2, {NULL}, 0, 0, S_SSPK5}, // S_SSPK4 - {SPR_SSPK, 0, 2, {NULL}, 0, 0, S_NULL}, // S_SSPK5 + {SPR_SSPK, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK2}, // S_SSPK1 + {SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK3}, // S_SSPK2 + {SPR_SSPK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK4}, // S_SSPK3 + {SPR_SSPK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK5}, // S_SSPK4 + {SPR_SSPK, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_SSPK5 // Freed Birdie {SPR_BIRD, 0, 4, {NULL}, 0, 0, S_BIRD2}, // S_BIRD1 @@ -2535,6 +2536,9 @@ state_t states[NUMSTATES] = {SPR_RPOP, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_RANDOMITEMPOP4}, // S_RANDOMITEMPOP3 {SPR_RPOP, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL}, // S_RANDOMITEMPOP4 + + {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON + {SPR_SGNS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1 {SPR_SGNS, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 {SPR_SGNS, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3 @@ -2594,6 +2598,8 @@ state_t states[NUMSTATES] = {SPR_KFRE, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_KARTFIRE8}, // S_KARTFIRE7 {SPR_KFRE, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_NULL}, // S_KARTFIRE8 + {SPR_AIDU, FF_ANIMATE|FF_PAPERSPRITE, 5*2, {NULL}, 5, 2, S_NULL}, // S_KARTAIZDRIFTSTRAT + {SPR_KINV, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_KARTINVULN_SMALL2}, // S_KARTINVULN_SMALL1 {SPR_KINV, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_KARTINVULN_SMALL3}, // S_KARTINVULN_SMALL2 {SPR_KINV, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_KARTINVULN_SMALL4}, // S_KARTINVULN_SMALL3 @@ -2777,30 +2783,30 @@ state_t states[NUMSTATES] = {SPR_LIGH, 2, 2, {NULL}, 0, 0, S_LIGHTNING4}, // S_LIGHTNING3 {SPR_LIGH, 3, 2, {NULL}, 0, 0, S_NULL}, // S_LIGHTNING4 - {SPR_THNS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_THUNDERSHIELD2}, // S_THUNDERSHIELD1 - {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD3}, // S_THUNDERSHIELD2 - {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD4}, // S_THUNDERSHIELD3 - {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD5}, // S_THUNDERSHIELD4 - {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD6}, // S_THUNDERSHIELD5 - {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD7}, // S_THUNDERSHIELD6 - {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD8}, // S_THUNDERSHIELD7 - {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD9}, // S_THUNDERSHIELD8 - {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD10}, // S_THUNDERSHIELD9 - {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD11}, // S_THUNDERSHIELD10 - {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD12}, // S_THUNDERSHIELD11 - {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD13}, // S_THUNDERSHIELD12 - {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD14}, // S_THUNDERSHIELD13 - {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD15}, // S_THUNDERSHIELD14 - {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD16}, // S_THUNDERSHIELD15 - {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD17}, // S_THUNDERSHIELD16 - {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD18}, // S_THUNDERSHIELD17 - {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD19}, // S_THUNDERSHIELD18 - {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD20}, // S_THUNDERSHIELD19 - {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD21}, // S_THUNDERSHIELD20 - {SPR_THNS, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_THUNDERSHIELD22}, // S_THUNDERSHIELD21 - {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD23}, // S_THUNDERSHIELD22 - {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD24}, // S_THUNDERSHIELD23 - {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD1}, // S_THUNDERSHIELD24 + {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD2}, // S_THUNDERSHIELD1 + {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD3}, // S_THUNDERSHIELD2 + {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD4}, // S_THUNDERSHIELD3 + {SPR_THNS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_THUNDERSHIELD5}, // S_THUNDERSHIELD4 + {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD6}, // S_THUNDERSHIELD5 + {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD7}, // S_THUNDERSHIELD6 + {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD8}, // S_THUNDERSHIELD7 + {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD9}, // S_THUNDERSHIELD8 + {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD10}, // S_THUNDERSHIELD9 + {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD11}, // S_THUNDERSHIELD10 + {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD12}, // S_THUNDERSHIELD11 + {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD13}, // S_THUNDERSHIELD12 + {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD14}, // S_THUNDERSHIELD13 + {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD15}, // S_THUNDERSHIELD14 + {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_THUNDERSHIELD16}, // S_THUNDERSHIELD15 + {SPR_THNS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_THUNDERSHIELD17}, // S_THUNDERSHIELD16 + {SPR_THNS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_THUNDERSHIELD18}, // S_THUNDERSHIELD17 + {SPR_THNS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_THUNDERSHIELD19}, // S_THUNDERSHIELD18 + {SPR_THNS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_THUNDERSHIELD20}, // S_THUNDERSHIELD19 + {SPR_THNS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_THUNDERSHIELD21}, // S_THUNDERSHIELD20 + {SPR_THNS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_THUNDERSHIELD22}, // S_THUNDERSHIELD21 + {SPR_THNS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_THUNDERSHIELD23}, // S_THUNDERSHIELD22 + {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD24}, // S_THUNDERSHIELD23 + {SPR_THNS, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_THUNDERSHIELD1}, // S_THUNDERSHIELD24 {SPR_SINK, 0, 1, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK {SPR_SINK, 0|FF_TRANS80|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_SINK_SHIELD}, // S_SINK_SHIELD @@ -2824,18 +2830,15 @@ state_t states[NUMSTATES] = {SPR_POKE, 3, 2, {A_MoveAbsolute}, 180, 2, S_POKEY5}, // S_POKEY8 {SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_POKEYIDLE - {SPR_NULL, 0, 1, {A_RandomStateRange}, S_AUDIENCE_TOAD1, S_AUDIENCE_SNIF1, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE + {SPR_NULL, 0, 1, {A_RandomStateRange}, S_AUDIENCE_CHAO_CHEER1, S_AUDIENCE_CHAO_CHEER2, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE - {SPR_AUDI, 0, 5, {NULL}, 0, 0, S_AUDIENCE_TOAD2}, // S_AUDIENCE_TOAD1 - {SPR_AUDI, 1, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_TOAD1}, // S_AUDIENCE_TOAD2 - {SPR_AUDI, 2, 5, {NULL}, 0, 0, S_AUDIENCE_BOO2}, // S_AUDIENCE_BOO1 - {SPR_AUDI, 3, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_BOO1}, // S_AUDIENCE_BOO2 - {SPR_AUDI, 4, 5, {NULL}, 0, 0, S_AUDIENCE_GMBA2}, // S_AUDIENCE_GMBA1 - {SPR_AUDI, 5, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_GMBA1}, // S_AUDIENCE_GMBA2 - {SPR_AUDI, 6, 5, {NULL}, 0, 0, S_AUDIENCE_SHYG2}, // S_AUDIENCE_SHYG1 - {SPR_AUDI, 7, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_SHYG1}, // S_AUDIENCE_SHYG2 - {SPR_AUDI, 8, 5, {NULL}, 0, 0, S_AUDIENCE_SNIF2}, // S_AUDIENCE_SNIF1 - {SPR_AUDI, 9, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_SNIF1}, // S_AUDIENCE_SNIF2 + {SPR_AUDI, 0, 5, {NULL}, 0, 0, S_AUDIENCE_CHAO_CHEER2}, // S_AUDIENCE_CHAO_CHEER1 + {SPR_AUDI, 1, 20, {A_BunnyHop}, 7, 0, S_AUDIENCE_CHAO_CHEER1}, // S_AUDIENCE_CHAO_CHEER2 + + {SPR_AUDI, 2, 5, {NULL}, 0, 0, S_AUDIENCE_CHAO_WIN2}, // S_AUDIENCE_CHAO_WIN1 + {SPR_AUDI, 3, 25, {A_BunnyHop}, 10, 0, S_AUDIENCE_CHAO_WIN1}, // S_AUDIENCE_CHAO_WIN2 + + {SPR_AUDI, 4|FF_ANIMATE, -1, {NULL}, 1, 17, S_NULL}, // S_AUDIENCE_CHAO_LOSE {SPR_AUDI, 10, -1, {NULL}, 0, 0, S_NULL}, // S_FANCHAR_KOTE {SPR_AUDI, 11, -1, {NULL}, 0, 0, S_NULL}, // S_FANCHAR_RYAN @@ -3005,6 +3008,57 @@ state_t states[NUMSTATES] = {SPR_RNDM, FF_ANIMATE, -1, {NULL}, 23, 3, S_NULL}, // S_PLAYERITEM {SPR_PBOM, 4, -1, {NULL}, 0, 0, S_NULL}, // S_KARMAWHEEL + + // Oh no it's annoying lightning states....... + // Lightning Sparks (it's the ones we'll use for the radius) + {SPR_KSPK, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK2}, // S_KSPARK1 + {SPR_NULL, FF_FULLBRIGHT, 1, {A_LightningFollowPlayer}, 0, 0, S_KSPARK3}, // S_KSPARK2 + {SPR_KSPK, FF_FULLBRIGHT|1, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK4}, // S_KSPARK3 + {SPR_NULL, FF_FULLBRIGHT, 1, {A_LightningFollowPlayer}, 0, 0, S_KSPARK5}, // S_KSPARK4 + {SPR_KSPK, FF_FULLBRIGHT|2, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK6}, // S_KSPARK5 + {SPR_NULL, FF_FULLBRIGHT, 1, {A_LightningFollowPlayer}, 0, 0, S_KSPARK7}, // S_KSPARK6 + {SPR_KSPK, FF_FULLBRIGHT|3, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK8}, // S_KSPARK7 + {SPR_NULL, FF_FULLBRIGHT, 1, {A_LightningFollowPlayer}, 0, 0, S_KSPARK9}, // S_KSPARK8 + {SPR_KSPK, FF_TRANS40|FF_FULLBRIGHT|4, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK10}, // S_KSPARK9 + {SPR_NULL, FF_FULLBRIGHT, 1, {A_LightningFollowPlayer}, 0, 0, S_KSPARK11}, // S_KSPARK10 + {SPR_KSPK, FF_TRANS50|FF_FULLBRIGHT|5, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK12}, // S_KSPARK11 + {SPR_NULL, FF_FULLBRIGHT, 1, {A_LightningFollowPlayer}, 0, 0, S_KSPARK13}, // S_KSPARK12 + {SPR_KSPK, FF_TRANS60|FF_FULLBRIGHT|6, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_KSPARK13 + + // The straight bolt... + {SPR_LZI1, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO12}, // S_LZIO11 + {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO13}, // S_LZIO12 + {SPR_LZI1, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO14}, // S_LZIO13 + {SPR_LZI1, FF_FULLBRIGHT|1, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO15}, // S_LZIO14 + {SPR_NULL, FF_FULLBRIGHT, 4, {A_LightningFollowPlayer}, 0, 0, S_LZIO16}, // S_LZIO15 + {SPR_LZI1, FF_FULLBRIGHT|1, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO17}, // S_LZIO16 + {SPR_NULL, 0, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO18}, // S_LZIO17 + {SPR_LZI1, FF_TRANS50|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO19}, // S_LZIO18 + {SPR_LZI1, FF_TRANS70|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_LZIO19 + + {SPR_NULL, FF_FULLBRIGHT, 6, {A_LightningFollowPlayer}, 0, 0, S_LZIO22}, // S_LZIO21 + {SPR_LZI2, FF_FULLBRIGHT|1, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO23}, // S_LZIO22 + {SPR_LZI2, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO24}, // S_LZIO23 + {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO25}, // S_LZIO24 + {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO26}, // S_LZIO25 + {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO27}, // S_LZIO26 + {SPR_LZI2, FF_TRANS30|FF_FULLBRIGHT|2, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO28}, // S_LZIO27 + {SPR_NULL, 0, 4, {A_LightningFollowPlayer}, 0, 0, S_LZIO29}, // S_LZIO28 + {SPR_LZI2, FF_TRANS70|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_LZIO29 + + // The slanted bolt. Man these states are boring as all heck to do. + {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT2}, // S_KLIT1 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT3}, // S_KLIT2 + {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|1, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT4}, // S_KLIT3 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT5}, // S_KLIT4 + {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|2, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT6}, // S_KLIT5 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT7}, // S_KLIT6 + {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|3, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT8}, // S_KLIT7 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT9}, // S_KLIT8 + {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|4, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT10}, // S_KLIT9 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT11}, // S_KLIT10 + {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|5, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT12}, // S_KLIT11 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT1}, // S_KLIT12 #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK @@ -4035,7 +4089,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4, // mass 0, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_SCENERY, // flags S_NULL // raisestate }, @@ -14397,6 +14451,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_FLOATINGITEM + -1, // doomednum + S_ITEMICON, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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_mcitm1, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SPECIAL|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_SIGNSPARKLE -1, // doomednum S_SIGNSPARK1, // spawnstate @@ -14559,6 +14640,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_AIZDRIFTSTRAT + -1, // doomednum + S_KARTAIZDRIFTSTRAT,// 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 + 8, // speed + 14*FRACUNIT, // radius + 14*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_SPARKLETRAIL -1, // doomednum S_KARTINVULN_SMALL1, // spawnstate @@ -14738,7 +14846,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_kc2e, // deathsound 0, // speed - 16*FRACUNIT, // radius + 24*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset 100, // mass @@ -14819,7 +14927,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_s3k5d, // deathsound 64*FRACUNIT, // speed - 16*FRACUNIT, // radius + 24*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset 100, // mass @@ -15305,7 +15413,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 8, // speed - 16*FRACUNIT, // radius + 20*FRACUNIT, // radius 56*FRACUNIT, // height 1, // display offset 16, // mass @@ -15548,8 +15656,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 8, // speed - 16*FRACUNIT, // radius - 40*FRACUNIT, // height + 8*FRACUNIT, // radius + 20*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage diff --git a/src/info.h b/src/info.h index ccbcc51db..d0f4be596 100644 --- a/src/info.h +++ b/src/info.h @@ -168,6 +168,7 @@ void A_JawzChase(); // SRB2kart void A_JawzExplode(); // SRB2kart void A_MineExplode(); // SRB2kart void A_BallhogExplode(); // SRB2kart +void A_LightningFollowPlayer(); // SRB2kart: Lightning shield effect player chasing void A_OrbitNights(); void A_GhostMe(); void A_SetObjectState(); @@ -644,8 +645,15 @@ typedef enum sprite SPR_PBOM, // player bomb SPR_RETI, // player reticule - SPR_VIEW, // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw! + SPR_AIDU, + SPR_KSPK, // Spark radius for the lightning shield + SPR_LZI1, // Lightning that falls on the player for lightning shield + SPR_LZI2, // ditto + SPR_KLIT, // You have a twisted mind. But this actually is for the diagonal lightning. + + SPR_VIEW, // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw! + SPR_FIRSTFREESLOT, SPR_LASTFREESLOT = SPR_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1, NUMSPRITES @@ -3051,6 +3059,8 @@ typedef enum state S_RANDOMITEMPOP4, //} + S_ITEMICON, + // Signpost sparkles S_SIGNSPARK1, S_SIGNSPARK2, @@ -3116,6 +3126,9 @@ typedef enum state S_KARTFIRE7, S_KARTFIRE8, + // Angel Island Drift Strat Dust (what a mouthful!) + S_KARTAIZDRIFTSTRAT, + // Invincibility Sparks S_KARTINVULN_SMALL1, S_KARTINVULN_SMALL2, @@ -3364,16 +3377,11 @@ typedef enum state // Audience Members S_RANDOMAUDIENCE, - S_AUDIENCE_TOAD1, - S_AUDIENCE_TOAD2, - S_AUDIENCE_BOO1, - S_AUDIENCE_BOO2, - S_AUDIENCE_GMBA1, - S_AUDIENCE_GMBA2, - S_AUDIENCE_SHYG1, - S_AUDIENCE_SHYG2, - S_AUDIENCE_SNIF1, - S_AUDIENCE_SNIF2, + S_AUDIENCE_CHAO_CHEER1, + S_AUDIENCE_CHAO_CHEER2, + S_AUDIENCE_CHAO_WIN1, + S_AUDIENCE_CHAO_WIN2, + S_AUDIENCE_CHAO_LOSE, S_FANCHAR_KOTE, S_FANCHAR_RYAN, @@ -3548,6 +3556,54 @@ typedef enum state S_PLAYERITEM, S_KARMAWHEEL, + + // Thunder shield use stuff; + S_KSPARK1, // Sparkling Radius + S_KSPARK2, + S_KSPARK3, + S_KSPARK4, + S_KSPARK5, + S_KSPARK6, + S_KSPARK7, + S_KSPARK8, + S_KSPARK9, + S_KSPARK10, + S_KSPARK11, + S_KSPARK12, + S_KSPARK13, // ... that's an awful lot. + + S_LZIO11, // Straight lightning bolt + S_LZIO12, + S_LZIO13, + S_LZIO14, + S_LZIO15, + S_LZIO16, + S_LZIO17, + S_LZIO18, + S_LZIO19, + + S_LZIO21, // Straight lightning bolt (flipped) + S_LZIO22, + S_LZIO23, + S_LZIO24, + S_LZIO25, + S_LZIO26, + S_LZIO27, + S_LZIO28, + S_LZIO29, + + S_KLIT1, // Diagonal lightning. No, it not being straight doesn't make it gay. + S_KLIT2, + S_KLIT3, + S_KLIT4, + S_KLIT5, + S_KLIT6, + S_KLIT7, + S_KLIT8, + S_KLIT9, + S_KLIT10, + S_KLIT11, + S_KLIT12, #ifdef SEENAMES S_NAMECHECK, @@ -4082,6 +4138,8 @@ typedef enum mobj_type MT_BLUEDIAG, MT_RANDOMITEM, MT_RANDOMITEMPOP, + MT_FLOATINGITEM, + MT_SIGNSPARKLE, MT_FASTLINE, @@ -4089,6 +4147,7 @@ typedef enum mobj_type MT_BOOSTFLAME, MT_BOOSTSMOKE, MT_SNEAKERTRAIL, + MT_AIZDRIFTSTRAT, MT_SPARKLETRAIL, MT_INVULNFLASH, MT_WIPEOUTTRAIL, diff --git a/src/k_kart.c b/src/k_kart.c index dd0c60116..db3178035 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -439,6 +439,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartdebugamount); CV_RegisterVar(&cv_kartdebugshrink); CV_RegisterVar(&cv_kartdebugdistribution); + CV_RegisterVar(&cv_kartdebughuddrop); CV_RegisterVar(&cv_kartdebugcheckpoint); } @@ -1140,7 +1141,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) fx->eflags |= MFE_VERTICALFLIP; else fx->eflags &= ~MFE_VERTICALFLIP; - fx->scale = mobj1->scale; + P_SetScale(fx, mobj1->scale); // Because this is done during collision now, rmomx and rmomy need to be recalculated // so that friction doesn't immediately decide to stop the player if they're at a standstill @@ -1830,6 +1831,10 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem P_SetPlayerMobjState(player->mo, S_KART_SPIN); player->kartstuff[k_instashield] = 15; + if (cv_kartdebughuddrop.value) + K_DropItems(player); + else + K_DropHnextList(player); return; } @@ -1899,6 +1904,10 @@ void K_SquishPlayer(player_t *player, mobj_t *source) P_PlayRinglossSound(player->mo); player->kartstuff[k_instashield] = 15; + if (cv_kartdebughuddrop.value) + K_DropItems(player); + else + K_DropHnextList(player); return; } @@ -1976,6 +1985,10 @@ void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we ju } player->kartstuff[k_instashield] = 15; + //if (cv_kartdebughuddrop.value) + K_DropItems(player); + /*else + K_DropHnextList(player);*/ return; } @@ -2051,6 +2064,10 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force) victim->kartstuff[k_comebacktimer] = comebacktime;*/ victim->kartstuff[k_instashield] = 15; + if (cv_kartdebughuddrop.value) + K_DropItems(victim); + else + K_DropHnextList(victim); return; } @@ -2158,14 +2175,14 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) { dust = P_SpawnMobj(source->x, source->y, source->z, MT_SMOKE); dust->angle = (ANGLE_180/16) * i; - dust->scale = source->scale; + P_SetScale(dust, source->scale); dust->destscale = source->scale*10; P_InstaThrust(dust, dust->angle, FixedMul(20*FRACUNIT, source->scale)); truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, source->y + P_RandomRange(-radius, radius)*FRACUNIT, source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMEXPLODE); - truc->scale = source->scale*2; + P_SetScale(truc, source->scale); truc->destscale = source->scale*6; speed = FixedMul(10*FRACUNIT, source->scale)>>FRACBITS; truc->momx = P_RandomRange(-speed, speed)*FRACUNIT; @@ -2180,7 +2197,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, source->y + P_RandomRange(-radius, radius)*FRACUNIT, source->z + P_RandomRange(0, height)*FRACUNIT, MT_SMOKE); - dust->scale = source->scale; + P_SetScale(dust, source->scale); dust->destscale = source->scale*10; dust->tics = 30; dust->momz = P_RandomRange(FixedMul(3*FRACUNIT, source->scale)>>FRACBITS, FixedMul(7*FRACUNIT, source->scale)>>FRACBITS)*FRACUNIT; @@ -2188,7 +2205,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, source->y + P_RandomRange(-radius, radius)*FRACUNIT, source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMPARTICLE); - truc->scale = source->scale; + P_SetScale(truc, source->scale); truc->destscale = source->scale*5; speed = FixedMul(20*FRACUNIT, source->scale)>>FRACBITS; truc->momx = P_RandomRange(-speed, speed)*FRACUNIT; @@ -2377,6 +2394,41 @@ static void K_SpawnDriftSparks(player_t *player) } } +static void K_SpawnAIZDust(player_t *player) +{ + fixed_t newx; + fixed_t newy; + mobj_t *spark; + angle_t travelangle; + + I_Assert(player != NULL); + I_Assert(player->mo != NULL); + I_Assert(!P_MobjWasRemoved(player->mo)); + + if (leveltime % 2 == 1) + return; + + if (!P_IsObjectOnGround(player->mo)) + return; + + travelangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + + { + newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle - (player->kartstuff[k_aizdriftstrat]*ANGLE_45), FixedMul(24*FRACUNIT, player->mo->scale)); + newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle - (player->kartstuff[k_aizdriftstrat]*ANGLE_45), FixedMul(24*FRACUNIT, player->mo->scale)); + spark = P_SpawnMobj(newx, newy, player->mo->z, MT_AIZDRIFTSTRAT); + + spark->angle = travelangle+(player->kartstuff[k_aizdriftstrat]*ANGLE_90); + P_SetScale(spark, (spark->destscale = (3*player->mo->scale)>>2)); + + spark->momx = (6*player->mo->momx)/5; + spark->momy = (6*player->mo->momy)/5; + //spark->momz = player->mo->momz/2; + + K_MatchGenericExtraFlags(spark, player->mo); + } +} + void K_SpawnBoostTrail(player_t *player) { fixed_t newx; @@ -2551,7 +2603,7 @@ void K_DriftDustHandling(mobj_t *spawner) dust->momx = FixedMul(spawner->momx + (P_RandomRange(-speedrange, speedrange)<momy = FixedMul(spawner->momy + (P_RandomRange(-speedrange, speedrange)<momz = P_MobjFlip(spawner) * P_RandomRange(1, 4)<scale = spawner->scale/2; + P_SetScale(dust, spawner->scale/2); dust->destscale = spawner->scale * 3; if (leveltime % 6 == 0) @@ -2790,13 +2842,59 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map return mo; } +#define THUNDERRADIUS 320 + static void K_DoThunderShield(player_t *player) { - S_StartSound(player->mo, sfx_s3k45); + mobj_t *mo; + int i = 0; + fixed_t sx; + fixed_t sy; + + S_StartSound(player->mo, sfx_zio3); //player->kartstuff[k_thunderanim] = 35; P_NukeEnemies(player->mo, player->mo, RING_DIST/4); + + // spawn vertical bolt + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THOK); + P_SetTarget(&mo->target, player->mo); + P_SetMobjState(mo, S_LZIO11); + mo->color = SKINCOLOR_TEAL; + mo->scale = player->mo->scale*3 + (player->mo->scale/2); + + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THOK); + P_SetTarget(&mo->target, player->mo); + P_SetMobjState(mo, S_LZIO21); + mo->color = SKINCOLOR_CYAN; + mo->scale = player->mo->scale*3 + (player->mo->scale/2); + + // spawn horizontal bolts; + for (i=0; i<7; i++) + { + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THOK); + mo->angle = P_RandomRange(0, 359)*ANG1; + mo->fuse = P_RandomRange(20, 50); + P_SetTarget(&mo->target, player->mo); + P_SetMobjState(mo, S_KLIT1); + } + + // spawn the radius thing: + angle_t an = ANGLE_22h; + for (i=0; i<15; i++) + { + sx = player->mo->x + FixedMul((player->mo->scale*THUNDERRADIUS), FINECOSINE((an*i)>>ANGLETOFINESHIFT)); + sy = player->mo->y + FixedMul((player->mo->scale*THUNDERRADIUS), FINESINE((an*i)>>ANGLETOFINESHIFT)); + mo = P_SpawnMobj(sx, sy, player->mo->z, MT_THOK); + mo-> angle = an*i; + mo->extravalue1 = THUNDERRADIUS; // Used to know whether we should teleport by radius or something. + mo->scale = player->mo->scale*3; + P_SetTarget(&mo->target, player->mo); + P_SetMobjState(mo, S_KSPARK1); + } } +#undef THUNDERRADIUS + static void K_DoHyudoroSteal(player_t *player) { INT32 i, numplayers = 0; @@ -3016,46 +3114,191 @@ killnext: } // Just for firing/dropping items. -void K_CleanHnextList(mobj_t *work) -{ - mobj_t *nextwork; - - if (!work) - return; - - work = work->hnext; - - while (work && !P_MobjWasRemoved(work)) - { - nextwork = work->hnext; - - P_RemoveMobj(work); - - work = nextwork; - } -} - -// Ditto. -void K_UpdateHnextList(player_t *player) +void K_UpdateHnextList(player_t *player, boolean clean) { mobj_t *work = player->mo, *nextwork; if (!work) return; - work = work->hnext; + nextwork = work->hnext; - while (work && !P_MobjWasRemoved(work)) + while ((work = nextwork) && !P_MobjWasRemoved(work)) { nextwork = work->hnext; - if (work->movedir > 0 && work->movedir > (UINT16)player->kartstuff[k_itemamount]) - P_RemoveMobj(work); + if (!clean && (!work->movedir || work->movedir <= (UINT16)player->kartstuff[k_itemamount])) + continue; - work = nextwork; + P_RemoveMobj(work); } } +// For getting hit! +void K_DropHnextList(player_t *player) +{ + mobj_t *work = player->mo, *nextwork, *dropwork; + INT32 flip; + mobjtype_t type; + boolean orbit, ponground; + + if (!work) + return; + + flip = P_MobjFlip(player->mo); + ponground = P_IsObjectOnGround(player->mo); + + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD && player->kartstuff[k_itemamount]) + { + K_DoThunderShield(player); + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_itemtype] = KITEM_NONE; + player->kartstuff[k_curshield] = 0; + } + + nextwork = work->hnext; + + while ((work = nextwork) && !P_MobjWasRemoved(work)) + { + nextwork = work->hnext; + + switch (work->type) + { + // Kart orbit items + case MT_ORBINAUT_SHIELD: + orbit = true; + type = MT_ORBINAUT; + break; + case MT_JAWZ_SHIELD: + orbit = true; + type = MT_JAWZ_DUD; + break; + // Kart trailing items + case MT_BANANA_SHIELD: + orbit = false; + type = MT_BANANA; + break; + case MT_SSMINE_SHIELD: + orbit = false; + type = MT_SSMINE; + break; + case MT_FAKESHIELD: + orbit = false; + type = MT_FAKEITEM; + break; + // intentionally do nothing + case MT_SINK_SHIELD: + return; + default: + continue; + } + + dropwork = P_SpawnMobj(work->x, work->y, work->z, type); + P_SetTarget(&dropwork->target, player->mo); + dropwork->angle = work->angle; + dropwork->flags2 = work->flags2; + dropwork->flags |= MF_NOCLIPTHING; + dropwork->floorz = work->floorz; + dropwork->ceilingz = work->ceilingz; + + if (ponground) + { + // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn + // This should set it for FOFs + //P_TeleportMove(dropwork, dropwork->x, dropwork->y, dropwork->z); -- handled better by above floorz/ceilingz passing + + if (flip == 1) + { + if (dropwork->floorz > dropwork->target->z - dropwork->height) + { + dropwork->z = dropwork->floorz; + } + } + else + { + if (dropwork->ceilingz < dropwork->target->z + dropwork->target->height + dropwork->height) + { + dropwork->z = dropwork->ceilingz - dropwork->height; + } + } + } + + if (orbit) // splay out + { + dropwork->flags2 |= MF2_AMBUSH; + dropwork->z += flip; + dropwork->momx = player->mo->momx>>1; + dropwork->momy = player->mo->momy>>1; + dropwork->momz = 3*flip*mapheaderinfo[gamemap-1]->mobj_scale; + P_Thrust(dropwork, work->angle - ANGLE_90, 6*(mapheaderinfo[gamemap-1]->mobj_scale)); + dropwork->movecount = 2; + dropwork->movedir = work->angle - ANGLE_90; + P_SetMobjState(dropwork, dropwork->info->deathstate); + dropwork->tics = -1; + if (type == MT_JAWZ_DUD) + dropwork->z += 20*flip*dropwork->scale; + else + { + dropwork->color = work->color; + dropwork->angle -= ANGLE_90; + } + } + else // plop on the ground + { + dropwork->flags &= ~MF_NOCLIPTHING; + dropwork->threshold = 10; + } + + P_RemoveMobj(work); + } + + { + // we need this here too because this is done in afterthink - pointers are cleaned up at the START of each tic... + P_SetTarget(&player->mo->hnext, NULL); + player->kartstuff[k_bananadrag] = 0; + if (player->kartstuff[k_eggmanheld]) + player->kartstuff[k_eggmanheld] = 0; + else if (player->kartstuff[k_itemheld]) + { + player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; + player->kartstuff[k_itemtype] = KITEM_NONE; + } + } +} + +// For getting EXTRA hit! +void K_DropItems(player_t *player) +{ + boolean thunderhack = (player->kartstuff[k_curshield] && player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD); + + if (thunderhack) + player->kartstuff[k_itemtype] = KITEM_NONE; + + K_DropHnextList(player); + + if (player->mo && player->kartstuff[k_itemamount]) + { + mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM); + P_SetScale(drop, drop->scale>>4); + drop->destscale = (3*drop->destscale)/2;; + + drop->angle = player->mo->angle + ANGLE_90; + drop->momx = player->mo->momx>>1; + drop->momy = player->mo->momy>>1; + P_Thrust(drop, + FixedAngle(P_RandomFixed()*180) + player->mo->angle + ANGLE_90, + 8*(mapheaderinfo[gamemap-1]->mobj_scale)); + drop->momz = P_MobjFlip(player->mo)*3*(mapheaderinfo[gamemap-1]->mobj_scale); + + drop->threshold = (thunderhack ? KITEM_THUNDERSHIELD : player->kartstuff[k_itemtype]); + drop->movecount = player->kartstuff[k_itemamount]; + + drop->flags |= MF_NOCLIPTHING; + } + + K_StripItems(player); +} + // When an item in the hnext chain dies. void K_RepairOrbitChain(mobj_t *orbit) { @@ -3714,7 +3957,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) void K_KartPlayerAfterThink(player_t *player) { - if (player->kartstuff[k_invincibilitytimer] + if (player->kartstuff[k_curshield] + || player->kartstuff[k_invincibilitytimer] || (player->kartstuff[k_growshrinktimer] != 0 && player->kartstuff[k_growshrinktimer] % 5 == 4)) // 4 instead of 0 because this is afterthink! { player->mo->frame |= FF_FULLBRIGHT; @@ -3901,16 +4145,14 @@ static void K_KartDrift(player_t *player, boolean onground) { // Starting left drift player->kartstuff[k_drift] = 1; - player->kartstuff[k_driftend] = 0; - player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0; } else if ((player->cmd.driftturn < 0) && player->speed > FixedMul(10<<16, player->mo->scale) && player->kartstuff[k_jmp] == 1 && (player->kartstuff[k_drift] == 0 || player->kartstuff[k_driftend] == 1)) // && player->kartstuff[k_drift] != -1) { // Starting right drift player->kartstuff[k_drift] = -1; - player->kartstuff[k_driftend] = 0; - player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0; } else if (player->kartstuff[k_jmp] == 0) // || player->kartstuff[k_turndir] == 0) { @@ -3969,9 +4211,20 @@ static void K_KartDrift(player_t *player, boolean onground) if (player->kartstuff[k_spinouttimer] > 0 // banana peel || player->speed < FixedMul(10<<16, player->mo->scale)) // you're too slow! { - player->kartstuff[k_drift] = 0; - player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_drift] = player->kartstuff[k_driftcharge] = player->kartstuff[k_aizdriftstrat] = 0; } + + if ((!player->kartstuff[k_sneakertimer]) + || (!player->cmd.driftturn) + || (player->cmd.driftturn > 0) != (player->kartstuff[k_aizdriftstrat] > 0)) + { + if (!player->kartstuff[k_drift]) + player->kartstuff[k_aizdriftstrat] = 0; + else + player->kartstuff[k_aizdriftstrat] = ((player->kartstuff[k_drift] > 0) ? 1 : -1); + } + else if (player->kartstuff[k_aizdriftstrat] && !player->kartstuff[k_drift]) + K_SpawnAIZDust(player); } // // K_KartUpdatePosition @@ -3982,7 +4235,6 @@ static void K_KartUpdatePosition(player_t *player) fixed_t oldposition = player->kartstuff[k_position]; fixed_t i, ppcd, pncd, ipcd, incd; fixed_t pmo, imo; - thinker_t *th; mobj_t *mo; if (player->spectator || !player->mo) @@ -4007,16 +4259,8 @@ static void K_KartUpdatePosition(player_t *player) player->kartstuff[k_nextcheck] = players[i].kartstuff[k_nextcheck] = 0; // This checks every thing on the map, and looks for MT_BOSS3WAYPOINT (the thing we're using for checkpoint wp's, for now) - for (th = thinkercap.next; th != &thinkercap; th = th->next) + for (mo = waypointcap; mo != NULL; mo = mo->tracer) { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj at all, shoo - continue; - - mo = (mobj_t *)th; - - if (mo->type != MT_BOSS3WAYPOINT) // TODO: Change to 'MT_WAYPOINT'? - continue; - pmo = P_AproxDistance(P_AproxDistance( mo->x - player->mo->x, mo->y - player->mo->y), mo->z - player->mo->z) / FRACUNIT; @@ -4100,20 +4344,18 @@ static void K_KartUpdatePosition(player_t *player) // void K_StripItems(player_t *player) { - player->kartstuff[k_itemtype] = 0; + player->kartstuff[k_itemtype] = KITEM_NONE; player->kartstuff[k_itemamount] = 0; player->kartstuff[k_itemheld] = 0; - player->kartstuff[k_itemroulette] = 0; - player->kartstuff[k_roulettetype] = 0; - player->kartstuff[k_rocketsneakertimer] = 0; - player->kartstuff[k_invincibilitytimer] = 0; - player->kartstuff[k_growshrinktimer] = 0; + if (!player->kartstuff[k_itemroulette] || player->kartstuff[k_roulettetype] != 2) + { + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + } player->kartstuff[k_eggmanheld] = 0; - player->kartstuff[k_eggmanexplode] = 0; - player->kartstuff[k_eggmanblame] = 0; player->kartstuff[k_hyudorotimer] = 0; player->kartstuff[k_stealingtimer] = 0; @@ -4125,7 +4367,19 @@ void K_StripItems(player_t *player) player->kartstuff[k_sadtimer] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); +} + +void K_StripOther(player_t *player) +{ + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + + player->kartstuff[k_invincibilitytimer] = 0; + player->kartstuff[k_growshrinktimer] = 0; + + player->kartstuff[k_eggmanexplode] = 0; + player->kartstuff[k_eggmanblame] = 0; } // @@ -4191,7 +4445,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, false, MT_FAKEITEM, -1, 0); K_PlayAttackTaunt(player->mo); player->kartstuff[k_eggmanheld] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); } // Rocket Sneaker else if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO @@ -4281,7 +4535,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, false, MT_BANANA, -1, 0); K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player); + K_UpdateHnextList(player, false); } break; case KITEM_EGGMAN: @@ -4341,7 +4595,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0); K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player); + K_UpdateHnextList(player, false); } break; case KITEM_JAWZ: @@ -4384,7 +4638,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0); K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; - K_UpdateHnextList(player); + K_UpdateHnextList(player, false); } break; case KITEM_MINE: @@ -4410,7 +4664,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; player->kartstuff[k_itemheld] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); } break; case KITEM_BALLHOG: @@ -4489,6 +4743,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_curshield] <= 0) { mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD); + P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); P_SetTarget(&shield->target, player->mo); player->kartstuff[k_curshield] = 1; } @@ -4539,7 +4794,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayAttackTaunt(player->mo); player->kartstuff[k_itemamount]--; player->kartstuff[k_itemheld] = 0; - K_CleanHnextList(player->mo); + K_UpdateHnextList(player, true); } break; case KITEM_SAD: @@ -4618,7 +4873,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) // dead in match? you da bomb { - K_StripItems(player); + K_DropItems(player); //K_StripItems(player); + K_StripOther(player); player->mo->flags2 |= MF2_SHADOW; player->powers[pw_flashing] = player->kartstuff[k_comebacktimer]; } @@ -5275,52 +5531,52 @@ void K_LoadKartHUDGraphics(void) } // For the item toggle menu -const char *K_GetItemPatch(UINT8 item, boolean small) +const char *K_GetItemPatch(UINT8 item, boolean tiny) { switch (item) { case KITEM_SNEAKER: case KRITEM_TRIPLESNEAKER: - return (small ? "K_ISSHOE" : "K_ITSHOE"); + return (tiny ? "K_ISSHOE" : "K_ITSHOE"); case KITEM_ROCKETSNEAKER: - return (small ? "K_ISRSHE" : "K_ITRSHE"); + return (tiny ? "K_ISRSHE" : "K_ITRSHE"); case KITEM_INVINCIBILITY: - return (small ? "K_ISINV1" : "K_ITINV1"); + return (tiny ? "K_ISINV1" : "K_ITINV1"); case KITEM_BANANA: case KRITEM_TRIPLEBANANA: case KRITEM_TENFOLDBANANA: - return (small ? "K_ISBANA" : "K_ITBANA"); + return (tiny ? "K_ISBANA" : "K_ITBANA"); case KITEM_EGGMAN: - return (small ? "K_ISEGGM" : "K_ITEGGM"); + return (tiny ? "K_ISEGGM" : "K_ITEGGM"); case KITEM_ORBINAUT: - return (small ? "K_ISORBN" : "K_ITORB1"); + return (tiny ? "K_ISORBN" : "K_ITORB1"); case KITEM_JAWZ: case KRITEM_DUALJAWZ: - return (small ? "K_ISJAWZ" : "K_ITJAWZ"); + return (tiny ? "K_ISJAWZ" : "K_ITJAWZ"); case KITEM_MINE: - return (small ? "K_ISMINE" : "K_ITMINE"); + return (tiny ? "K_ISMINE" : "K_ITMINE"); case KITEM_BALLHOG: - return (small ? "K_ISBHOG" : "K_ITBHOG"); + return (tiny ? "K_ISBHOG" : "K_ITBHOG"); case KITEM_SPB: - return (small ? "K_ISSPB" : "K_ITSPB"); + return (tiny ? "K_ISSPB" : "K_ITSPB"); case KITEM_GROW: - return (small ? "K_ISGROW" : "K_ITGROW"); + return (tiny ? "K_ISGROW" : "K_ITGROW"); case KITEM_SHRINK: - return (small ? "K_ISSHRK" : "K_ITSHRK"); + return (tiny ? "K_ISSHRK" : "K_ITSHRK"); case KITEM_THUNDERSHIELD: - return (small ? "K_ISTHNS" : "K_ITTHNS"); + return (tiny ? "K_ISTHNS" : "K_ITTHNS"); case KITEM_HYUDORO: - return (small ? "K_ISHYUD" : "K_ITHYUD"); + return (tiny ? "K_ISHYUD" : "K_ITHYUD"); case KITEM_POGOSPRING: - return (small ? "K_ISPOGO" : "K_ITPOGO"); + return (tiny ? "K_ISPOGO" : "K_ITPOGO"); case KITEM_KITCHENSINK: - return (small ? "K_ISSINK" : "K_ITSINK"); + return (tiny ? "K_ISSINK" : "K_ITSINK"); case KRITEM_TRIPLEORBINAUT: - return (small ? "K_ISORBN" : "K_ITORB3"); + return (tiny ? "K_ISORBN" : "K_ITORB3"); case KRITEM_QUADORBINAUT: - return (small ? "K_ISORBN" : "K_ITORB4"); + return (tiny ? "K_ISORBN" : "K_ITORB4"); default: - return (small ? "K_ISSAD" : "K_ITSAD"); + return (tiny ? "K_ISSAD" : "K_ITSAD"); } } @@ -5603,10 +5859,10 @@ static void K_drawKartItem(void) case KITEM_JAWZ: localpatch = kp_jawz[offset]; break; case KITEM_MINE: localpatch = kp_mine[offset]; break; case KITEM_BALLHOG: localpatch = kp_ballhog[offset]; break; - case KITEM_SPB: localpatch = kp_selfpropelledbomb[offset]; break; + case KITEM_SPB: localpatch = kp_selfpropelledbomb[offset]; localbg = kp_itembg[offset+1]; break; case KITEM_GROW: localpatch = kp_grow[offset]; break; case KITEM_SHRINK: localpatch = kp_shrink[offset]; break; - case KITEM_THUNDERSHIELD: localpatch = kp_thundershield[offset]; break; + case KITEM_THUNDERSHIELD: localpatch = kp_thundershield[offset]; localbg = kp_itembg[offset+1]; break; case KITEM_HYUDORO: localpatch = kp_hyudoro[offset]; break; case KITEM_POGOSPRING: localpatch = kp_pogospring[offset]; break; case KITEM_KITCHENSINK: localpatch = kp_kitchensink[offset]; break; @@ -6348,7 +6604,7 @@ static void K_drawKartMinimap(void) // Draw the HUD only when playing in a level. // hu_stuff needs this, unlike st_stuff. - if (!(Playing() && gamestate == GS_LEVEL)) + if (gamestate != GS_LEVEL) return; if (stplyr != &players[displayplayer]) diff --git a/src/k_kart.h b/src/k_kart.h index c0cb63d57..7c37ef679 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -39,14 +39,16 @@ void K_DriftDustHandling(mobj_t *spawner); void K_DoSneaker(player_t *player, boolean doPFlag); void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, boolean mute); void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); -void K_CleanHnextList(mobj_t *work); -void K_UpdateHnextList(player_t *player); +void K_UpdateHnextList(player_t *player, boolean clean); +void K_DropHnextList(player_t *player); void K_RepairOrbitChain(mobj_t *orbit); player_t *K_FindJawzTarget(mobj_t *actor, player_t *source); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); fixed_t K_GetKartDriftSparkValue(player_t *player); +void K_DropItems(player_t *player); void K_StripItems(player_t *player); +void K_StripOther(player_t *player); void K_MomentumToFacing(player_t *player); fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower); fixed_t K_GetKartAccel(player_t *player); @@ -57,7 +59,7 @@ void K_CalculateBattleWanted(void); void K_CheckBumpers(void); void K_CheckSpectateStatus(void); -const char *K_GetItemPatch(UINT8 item, boolean small); +const char *K_GetItemPatch(UINT8 item, boolean tiny); INT32 K_calcSplitFlags(INT32 snapflags); void K_LoadKartHUDGraphics(void); fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fixed_t my); diff --git a/src/m_menu.c b/src/m_menu.c index 39a2bca0f..8be0b479c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -33,6 +33,9 @@ #include "s_sound.h" #include "i_system.h" +// Addfile +#include "filesrch.h" + #include "v_video.h" #include "i_video.h" #include "keys.h" @@ -68,6 +71,10 @@ int snprintf(char *str, size_t n, const char *fmt, ...); //int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); #endif +#if defined (__GNUC__) && (__GNUC__ >= 4) +#define FIXUPO0 +#endif + #define SKULLXOFF -32 #define LINEHEIGHT 16 #define STRINGHEIGHT 8 @@ -75,7 +82,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #define SMALLLINEHEIGHT 8 #define SLIDER_RANGE 10 #define SLIDER_WIDTH (8*SLIDER_RANGE+6) -#define MAXSTRINGLENGTH 32 #define SERVERS_PER_PAGE 11 typedef enum @@ -207,6 +213,8 @@ menu_t MessageDef; menu_t SPauseDef; +#define lsheadingheight 16 + // Sky Room //static void M_CustomLevelSelect(INT32 choice); //static void M_CustomWarp(INT32 choice); @@ -323,9 +331,16 @@ menu_t OP_MonitorToggleDef; static void M_ScreenshotOptions(INT32 choice); static void M_EraseData(INT32 choice); +static void M_Addons(INT32 choice); +static void M_AddonsOptions(INT32 choice); +static patch_t *addonsp[NUM_EXT+5]; + +#define numaddonsshown 4 + // Drawing functions static void M_DrawGenericMenu(void); static void M_DrawCenteredMenu(void); +static void M_DrawAddons(void); static void M_DrawSkyRoom(void); static void M_DrawChecklist(void); static void M_DrawEmblemHints(void); @@ -361,6 +376,7 @@ static boolean M_CancelConnect(void); #endif static boolean M_ExitPandorasBox(void); static boolean M_QuitMultiPlayerMenu(void); +static void M_HandleAddons(INT32 choice); static void M_HandleSoundTest(INT32 choice); static void M_HandleImageDef(INT32 choice); static void M_HandleLoadSave(INT32 choice); @@ -482,15 +498,16 @@ static consvar_t cv_dummystaff = {"dummystaff", "0", CV_HIDEN|CV_CALL, dummystaf // --------- static menuitem_t MainMenu[] = { - {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 84}, - {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 92}, + {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 76}, + {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, #ifdef NONET M_StartSplitServerMenu - {IT_CALL |IT_STRING, NULL, "Splitscreen", M_StartSplitServerMenu,100}, + {IT_CALL |IT_STRING, NULL, "Splitscreen", M_StartSplitServerMenu, 92}, #else - {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 100}, + {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, #endif - {IT_CALL |IT_STRING, NULL, "Options", M_Options, 108}, + {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, + {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, }; @@ -500,9 +517,15 @@ typedef enum singleplr, multiplr, options, + addons, quitdoom } main_e; +static menuitem_t MISC_AddonsMenu[] = +{ + {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleAddons, 0}, // dummy menuitem for the control func +}; + // --------------------------------- // Pause Menu Mode Attacking Edition // --------------------------------- @@ -525,8 +548,9 @@ typedef enum // --------------------- static menuitem_t MPauseMenu[] = { - {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, - {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24}, + {IT_STRING | IT_CALL, NULL, "Add-ons...", M_Addons, 8}, + {IT_STRING | IT_SUBMENU, NULL, "Scramble Teams...", &MISC_ScrambleTeamDef, 16}, + {IT_STRING | IT_CALL, NULL, "Switch Map..." , M_MapChange, 24}, {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,40}, {IT_CALL | IT_STRING, NULL, "P1 Setup...", M_SetupMultiPlayer, 48}, // splitscreen @@ -549,7 +573,8 @@ static menuitem_t MPauseMenu[] = typedef enum { - mpause_scramble = 0, + mpause_addons = 0, + mpause_scramble, mpause_switchmap, mpause_continue, @@ -1065,10 +1090,11 @@ static menuitem_t OP_MainMenu[] = {IT_SUBMENU|IT_STRING, NULL, "Gameplay Options...", &OP_GameOptionsDef, 90}, {IT_SUBMENU|IT_STRING, NULL, "Server Options...", &OP_ServerOptionsDef, 100}, + {IT_STRING|IT_CALL, NULL, "Add-on Options...", M_AddonsOptions, 110}, - {IT_CALL|IT_STRING, NULL, "Tricks & Secrets (F1)", M_Manual, 120}, - {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 130}, - {IT_SUBMENU|IT_STRING, NULL, "Erase Data...", &OP_EraseDataDef, 140}, + {IT_CALL|IT_STRING, NULL, "Tricks & Secrets (F1)", M_Manual, 130}, + {IT_CALL|IT_STRING, NULL, "Play Credits", M_Credits, 140}, + {IT_SUBMENU|IT_STRING, NULL, "Erase Data...", &OP_EraseDataDef, 150}, }; static menuitem_t OP_ControlsMenu[] = @@ -1426,6 +1452,24 @@ static menuitem_t OP_EraseDataMenu[] = {IT_STRING | IT_CALL, NULL, "\x85" "Erase ALL Data", M_EraseData, 40}, }; +static menuitem_t OP_AddonsOptionsMenu[] = +{ + {IT_HEADER, NULL, "Menu", NULL, 0}, + {IT_STRING|IT_CVAR, NULL, "Location", &cv_addons_option, 10}, + {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder", &cv_addons_folder, 20}, + {IT_STRING|IT_CVAR, NULL, "Identify add-ons via", &cv_addons_md5, 48}, + {IT_STRING|IT_CVAR, NULL, "Show unsupported file types", &cv_addons_showall, 58}, + + {IT_HEADER, NULL, "Search", NULL, 76}, + {IT_STRING|IT_CVAR, NULL, "Matching", &cv_addons_search_type, 86}, + {IT_STRING|IT_CVAR, NULL, "Case-sensitive", &cv_addons_search_case, 96}, +}; + +enum +{ + op_addons_folder = 2, +}; + static menuitem_t OP_HUDOptionsMenu[] = { {IT_STRING | IT_CVAR, NULL, "Show HUD (F3)", &cv_showhud, 10}, @@ -1572,6 +1616,18 @@ static menuitem_t OP_MonitorToggleMenu[] = // Main Menu and related menu_t MainDef = CENTERMENUSTYLE(NULL, MainMenu, NULL, 72); +menu_t MISC_AddonsDef = +{ + NULL, + sizeof (MISC_AddonsMenu)/sizeof (menuitem_t), + &MainDef, + MISC_AddonsMenu, + M_DrawAddons, + 50, 28, + 0, + NULL +}; + menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72); menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72); menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); @@ -2026,7 +2082,8 @@ menu_t OP_OpenGLColorDef = #endif //menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30); menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_MainDef, 30, 30); -menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_MainDef, 60, 30); +menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_MainDef, 30, 30); +menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_MainDef, 30, 30); // ========================================================================== // CVAR ONCHANGE EVENTS GO HERE @@ -2245,6 +2302,12 @@ void Moviemode_mode_Onchange(void) OP_ScreenshotOptionsMenu[i].status = IT_STRING|IT_CVAR; } +void Addons_option_Onchange(void) +{ + OP_AddonsOptionsMenu[op_addons_folder].status = + (cv_addons_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED); +} + // ========================================================================== // END ORGANIZATION STUFF. // ========================================================================== @@ -2732,6 +2795,7 @@ boolean M_Responder(event_t *ev) { // detach any keys associated with the game control G_ClearControlKeys(setupcontrols, currentMenu->menuitems[itemOn].alphaKey); + S_StartSound(NULL, sfx_shldls); return true; } @@ -2901,6 +2965,7 @@ void M_StartControlPanel(void) else // multiplayer { MPauseMenu[mpause_switchmap].status = IT_DISABLED; + MPauseMenu[mpause_addons].status = IT_DISABLED; MPauseMenu[mpause_scramble].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED; @@ -2921,6 +2986,7 @@ void M_StartControlPanel(void) if ((server || IsPlayerAdmin(consoleplayer))) { MPauseMenu[mpause_switchmap].status = IT_STRING | IT_CALL; + MPauseMenu[mpause_addons].status = IT_STRING | IT_CALL; if (G_GametypeHasTeams()) MPauseMenu[mpause_scramble].status = IT_STRING | IT_SUBMENU; } @@ -4264,6 +4330,547 @@ static void M_HandleImageDef(INT32 choice) // MISC MAIN MENU OPTIONS // ====================== +static void M_AddonsOptions(INT32 choice) +{ + (void)choice; + Addons_option_Onchange(); + + M_SetupNextMenu(&OP_AddonsOptionsDef); +} + +#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make add-ons!" +#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make add-ons!" + +static void M_Addons(INT32 choice) +{ + const char *pathname = "."; + + (void)choice; + +#if 1 + if (cv_addons_option.value == 0) + pathname = usehome ? srb2home : srb2path; + else if (cv_addons_option.value == 1) + pathname = srb2home; + else if (cv_addons_option.value == 2) + pathname = srb2path; + else +#endif + if (cv_addons_option.value == 3 && *cv_addons_folder.string != '\0') + pathname = cv_addons_folder.string; + + strlcpy(menupath, pathname, 1024); + menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath) + 1; + + if (menupath[menupathindex[menudepthleft]-2] != PATHSEP[0]) + { + menupath[menupathindex[menudepthleft]-1] = PATHSEP[0]; + menupath[menupathindex[menudepthleft]] = 0; + } + else + --menupathindex[menudepthleft]; + + if (!preparefilemenu(false)) + { + M_StartMessage(va("No files/folders found.\n\n%s\n\n(Press a key)\n", (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)),NULL,MM_NOTHING); + return; + } + else + dir_on[menudepthleft] = 0; + + if (addonsp[0]) // never going to have some provided but not all, saves individually checking + { + size_t i; + for (i = 0; i < NUM_EXT+5; i++) + W_UnlockCachedPatch(addonsp[i]); + } + + addonsp[EXT_FOLDER] = W_CachePatchName("M_FFLDR", PU_STATIC); + addonsp[EXT_UP] = W_CachePatchName("M_FBACK", PU_STATIC); + addonsp[EXT_NORESULTS] = W_CachePatchName("M_FNOPE", PU_STATIC); + addonsp[EXT_TXT] = W_CachePatchName("M_FTXT", PU_STATIC); + addonsp[EXT_CFG] = W_CachePatchName("M_FCFG", PU_STATIC); + addonsp[EXT_WAD] = W_CachePatchName("M_FWAD", PU_STATIC); + addonsp[EXT_KART] = W_CachePatchName("M_FKART", PU_STATIC); + //addonsp[EXT_PK3] = W_CachePatchName("M_FPK3", PU_STATIC); + addonsp[EXT_SOC] = W_CachePatchName("M_FSOC", PU_STATIC); + addonsp[EXT_LUA] = W_CachePatchName("M_FLUA", PU_STATIC); + addonsp[NUM_EXT] = W_CachePatchName("M_FUNKN", PU_STATIC); + addonsp[NUM_EXT+1] = W_CachePatchName("M_FSEL", PU_STATIC); + addonsp[NUM_EXT+2] = W_CachePatchName("M_FLOAD", PU_STATIC); + addonsp[NUM_EXT+3] = W_CachePatchName("M_FSRCH", PU_STATIC); + addonsp[NUM_EXT+4] = W_CachePatchName("M_FSAVE", PU_STATIC); + + MISC_AddonsDef.prevMenu = currentMenu; + M_SetupNextMenu(&MISC_AddonsDef); +} + +#define width 4 +#define vpadding 27 +#define h (BASEVIDHEIGHT-(2*vpadding)) +#define NUMCOLOURS 8 // when toast's coding it's british english hacker fucker +static void M_DrawTemperature(INT32 x, fixed_t t) +{ + INT32 y; + + // bounds check + if (t > FRACUNIT) + t = FRACUNIT; + /*else if (t < 0) -- not needed + t = 0;*/ + + // scale + if (t > 1) + t = (FixedMul(h<>FRACBITS); + + // border + V_DrawFill(x - 1, vpadding, 1, h, 120); + V_DrawFill(x + width, vpadding, 1, h, 120); + V_DrawFill(x - 1, vpadding-1, width+2, 1, 120); + V_DrawFill(x - 1, vpadding+h, width+2, 1, 120); + + // bar itself + y = h; + if (t) + for (t = h - t; y > 0; y--) + { + UINT8 colours[NUMCOLOURS] = {135, 133, 92, 77, 114, 178, 161, 162}; + UINT8 c; + if (y <= t) break; + if (y+vpadding >= BASEVIDHEIGHT/2) + c = 185; + else + c = colours[(NUMCOLOURS*(y-1))/(h/2)]; + V_DrawFill(x, y-1 + vpadding, width, 1, c); + } + + // fill the rest of the backing + if (y) + V_DrawFill(x, vpadding, width, y, 30); +} +#undef width +#undef vpadding +#undef h +#undef NUMCOLOURS + +static char *M_AddonsHeaderPath(void) +{ + UINT32 len; + static char header[1024]; + + strlcpy(header, va("%s folder%s", cv_addons_option.string, menupath+menupathindex[menudepth-1]-1), 1024); + len = strlen(header); + if (len > 34) + { + len = len-34; + header[len] = header[len+1] = header[len+2] = '.'; + } + else + len = 0; + + return header+len; +} + +#define UNEXIST S_StartSound(NULL, sfx_lose);\ + M_SetupNextMenu(MISC_AddonsDef.prevMenu);\ + M_StartMessage(va("\x82%s\x80\nThis folder no longer exists!\nAborting to main menu.\n\n(Press a key)\n", M_AddonsHeaderPath()),NULL,MM_NOTHING) + +#define CLEARNAME Z_Free(refreshdirname);\ + refreshdirname = NULL + +static void M_AddonsClearName(INT32 choice) +{ + CLEARNAME; + M_StopMessage(choice); +} + +// returns whether to do message draw +static boolean M_AddonsRefresh(void) +{ + if ((refreshdirmenu & REFRESHDIR_NORMAL) && !preparefilemenu(true)) + { + UNEXIST; + return true; + } + + if (refreshdirmenu & REFRESHDIR_ADDFILE) + { + char *message = NULL; + + if (refreshdirmenu & REFRESHDIR_NOTLOADED) + { + 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); + 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); + } + else if (refreshdirmenu & (REFRESHDIR_WARNING|REFRESHDIR_ERROR)) + { + S_StartSound(NULL, sfx_skid); + message = va("%c%s\x80\nA file was loaded with %s.\nCheck the console log for more information.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname, ((refreshdirmenu & REFRESHDIR_ERROR) ? "errors" : "warnings")); + } + + if (message) + { + M_StartMessage(message,M_AddonsClearName,MM_EVENTHANDLER); + return true; + } + + S_StartSound(NULL, sfx_strpst); + CLEARNAME; + } + + return false; +} + +#ifdef FIXUPO0 +#pragma GCC optimize ("0") +#endif + +static void M_DrawAddons(void) +{ + INT32 x, y; + ssize_t i, m; + const UINT8 *flashcol = NULL; + UINT8 hilicol; + + // hack - need to refresh at end of frame to handle addfile... + if (refreshdirmenu & M_AddonsRefresh()) + { + M_DrawMessageMenu(); + return; + } + + if (Playing()) + V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems."); + else + V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1)); + + if (numwadfiles <= mainwads+1) + y = 0; + else if (numwadfiles >= MAX_WADFILES) + y = FRACUNIT; + else + { + x = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))< y) + y = x; + if (y > FRACUNIT) // happens because of how we're shrinkin' it a little + y = FRACUNIT; + } + + M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y); + + // DRAW MENU + x = currentMenu->x; + y = currentMenu->y + 1; + + hilicol = V_GetStringColormap(highlightflags)[120]; + + 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); + + m = (BASEVIDHEIGHT - currentMenu->y + 2) - (y - 1); + V_DrawFill(x - 21, y - 1, MAXSTRINGLENGTH*8+6, m, 239); + + // scrollbar! + if (sizedirmenu <= (2*numaddonsshown + 1)) + i = 0; + else + { + ssize_t q = m; + m = ((2*numaddonsshown + 1) * m)/sizedirmenu; + 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)); + } + + V_DrawFill(x + MAXSTRINGLENGTH*8+5 - 21, (y - 1) + i, 1, m, hilicol); + + // get bottom... + m = dir_on[menudepthleft] + numaddonsshown + 1; + if (m > (ssize_t)sizedirmenu) + m = sizedirmenu; + + // then top... + i = m - (2*numaddonsshown + 1); + + // then adjust! + if (i < 0) + { + if ((m -= i) > (ssize_t)sizedirmenu) + m = sizedirmenu; + i = 0; + } + + if (i != 0) + V_DrawString(19, y+4 - (skullAnimCounter/5), highlightflags, "\x1A"); + + if (skullAnimCounter < 4) + flashcol = V_GetStringColormap(highlightflags); + + for (; i < m; i++) + { + UINT32 flags = V_ALLOWLOWERCASE; + if (y > BASEVIDHEIGHT) break; + if (dirmenu[i]) +#define type (UINT8)(dirmenu[i][DIR_TYPE]) + { + if (type & EXT_LOADED) + { + flags |= V_TRANSLUCENT; + V_DrawSmallScaledPatch(x-(16+4), y, V_TRANSLUCENT, addonsp[(type & ~EXT_LOADED)]); + V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[NUM_EXT+2]); + } + else + V_DrawSmallScaledPatch(x-(16+4), y, 0, addonsp[(type & ~EXT_LOADED)]); + + 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))); +#undef charsonside + else + V_DrawString(x, y+4, flags, dirmenu[i]+DIR_STRING); + } +#undef type + y += 16; + } + + if (m != (ssize_t)sizedirmenu) + V_DrawString(19, y-12 + (skullAnimCounter/5), highlightflags, "\x1B"); + + y = BASEVIDHEIGHT - currentMenu->y + 1; + + M_DrawTextBox(x - (21 + 5), y, MAXSTRINGLENGTH, 1); + if (menusearch[0]) + V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE, menusearch+1); + else + V_DrawString(x - 18, y + 8, V_ALLOWLOWERCASE|V_TRANSLUCENT, "Type to search..."); + if (skullAnimCounter < 4) + V_DrawCharacter(x - 18 + V_StringWidth(menusearch+1, 0), y + 8, + '_' | 0x80, false); + + x -= (21 + 5 + 16); + V_DrawSmallScaledPatch(x, y + 4, (menusearch[0] ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+3]); + + x = BASEVIDWIDTH - x - 16; + V_DrawSmallScaledPatch(x, y + 4, ((!modifiedgame || savemoddata) ? 0 : V_TRANSLUCENT), addonsp[NUM_EXT+4]); + + if (modifiedgame) + V_DrawSmallScaledPatch(x, y + 4, 0, addonsp[NUM_EXT+2]); +} + +#ifdef FIXUPO0 +#pragma GCC reset_options +#endif + +static void M_AddonExec(INT32 ch) +{ + if (ch != 'y' && ch != KEY_ENTER) + return; + + S_StartSound(NULL, sfx_zoom); + COM_BufAddText(va("exec \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); +} + +#define len menusearch[0] +static boolean M_ChangeStringAddons(INT32 choice) +{ + if (shiftdown && choice >= 32 && choice <= 127) + choice = shiftxform[choice]; + + switch (choice) + { + case KEY_DEL: + if (len) + { + len = menusearch[1] = 0; + return true; + } + break; + case KEY_BACKSPACE: + if (len) + { + menusearch[1+--len] = 0; + return true; + } + break; + default: + if (choice >= 32 && choice <= 127) + { + if (len < MAXSTRINGLENGTH - 1) + { + menusearch[1+len++] = (char)choice; + menusearch[1+len] = 0; + return true; + } + } + break; + } + return false; +} +#undef len + +static void M_HandleAddons(INT32 choice) +{ + boolean exitmenu = false; // exit to previous menu + + if (M_ChangeStringAddons(choice)) + { + char *tempname = NULL; + if (dirmenu && dirmenu[dir_on[menudepthleft]]) + tempname = Z_StrDup(dirmenu[dir_on[menudepthleft]]+DIR_STRING); // don't need to I_Error if can't make - not important, just QoL +#if 0 // much slower + if (!preparefilemenu(true)) + { + UNEXIST; + return; + } +#else // streamlined + searchfilemenu(tempname); +#endif + } + + switch (choice) + { + case KEY_DOWNARROW: + if (dir_on[menudepthleft] < sizedirmenu-1) + dir_on[menudepthleft]++; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_UPARROW: + if (dir_on[menudepthleft]) + dir_on[menudepthleft]--; + S_StartSound(NULL, sfx_menu1); + break; + case KEY_PGDN: + { + UINT8 i; + for (i = numaddonsshown; i && (dir_on[menudepthleft] < sizedirmenu-1); i--) + dir_on[menudepthleft]++; + } + S_StartSound(NULL, sfx_menu1); + break; + case KEY_PGUP: + { + UINT8 i; + for (i = numaddonsshown; i && (dir_on[menudepthleft]); i--) + dir_on[menudepthleft]--; + } + S_StartSound(NULL, sfx_menu1); + break; + case KEY_ENTER: + { + boolean refresh = true; + if (!dirmenu[dir_on[menudepthleft]]) + S_StartSound(NULL, sfx_lose); + else + { + switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE]) + { + case EXT_FOLDER: + strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING); + if (menudepthleft) + { + menupathindex[--menudepthleft] = strlen(menupath); + menupath[menupathindex[menudepthleft]] = 0; + + if (!preparefilemenu(false)) + { + S_StartSound(NULL, sfx_skid); + M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); + menupath[menupathindex[++menudepthleft]] = 0; + + if (!preparefilemenu(true)) + { + UNEXIST; + return; + } + } + else + { + S_StartSound(NULL, sfx_menu1); + dir_on[menudepthleft] = 1; + } + refresh = false; + } + else + { + S_StartSound(NULL, sfx_lose); + M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING); + menupath[menupathindex[menudepthleft]] = 0; + } + break; + case EXT_UP: + S_StartSound(NULL, sfx_menu1); + menupath[menupathindex[++menudepthleft]] = 0; + if (!preparefilemenu(false)) + { + UNEXIST; + return; + } + break; + case EXT_TXT: + M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press 'Y' to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),M_AddonExec,MM_YESNO); + break; + case EXT_CFG: + M_AddonExec(KEY_ENTER); + break; + case EXT_LUA: +#ifndef HAVE_BLUA + S_StartSound(NULL, sfx_lose); + M_StartMessage(va("%c%s\x80\nThis copy of SRB2 was compiled\nwithout support for .lua files.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING),NULL,MM_NOTHING); + break; +#endif + // else intentional fallthrough + case EXT_SOC: + case EXT_WAD: + case EXT_KART: + //case EXT_PK3: + COM_BufAddText(va("addfile \"%s%s\"", menupath, dirmenu[dir_on[menudepthleft]]+DIR_STRING)); + break; + default: + S_StartSound(NULL, sfx_lose); + } + } + if (refresh) + refreshdirmenu |= REFRESHDIR_NORMAL; + } + break; + + case KEY_ESCAPE: + exitmenu = true; + break; + + default: + break; + } + if (exitmenu) + { + closefilemenu(true); + + // Secret menu! + //MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + + if (currentMenu->prevMenu) + M_SetupNextMenu(currentMenu->prevMenu); + else + M_ClearMenus(true); + } +} + static void M_PandorasBox(INT32 choice) { (void)choice; @@ -4366,8 +4973,8 @@ static void M_Options(INT32 choice) OP_MainMenu[5].status = OP_MainMenu[6].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // if the player is playing _at all_, disable the erase data & credits options - OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); - OP_MainMenu[9].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); + OP_MainMenu[9].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); + OP_MainMenu[10].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); OP_GameOptionsMenu[3].status = (M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore @@ -8067,23 +8674,22 @@ static void M_ChangecontrolResponse(event_t *ev) setupcontrols[control][found] = ch-KEY_4JOY1+KEY_DBL4JOY1; } else - { - // check if change key1 or key2, or replace the two by the new - found = 0; - if (setupcontrols[control][0] == KEY_NULL) - found++; - if (setupcontrols[control][1] == KEY_NULL) - found++; - if (found == 2) - { - found = 0; - setupcontrols[control][1] = KEY_NULL; //replace key 1,clear key2 - } - G_CheckDoubleUsage(ch); - setupcontrols[control][found] = ch; - } - + { + // check if change key1 or key2, or shuffle them along in a queue + found = 0; + if (setupcontrols[control][0] != KEY_NULL) + { + found++; + if (setupcontrols[control][1] != KEY_NULL) + setupcontrols[control][0] = setupcontrols[control][1]; + } + G_CheckDoubleUsage(ch); + setupcontrols[control][found] = ch; + } + S_StartSound(NULL, sfx_strpst); } + else + S_StartSound(NULL, sfx_skid); M_StopMessage(0); } diff --git a/src/m_menu.h b/src/m_menu.h index 51559489f..cb083b0e4 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -124,6 +124,8 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); #define IT_HEADER (IT_SPACE +IT_HEADERTEXT) #define IT_SECRET (IT_SPACE +IT_QUESTIONMARKS) +#define MAXSTRINGLENGTH 32 + typedef union { struct menu_s *submenu; // IT_SUBMENU @@ -223,6 +225,9 @@ void M_CheatActivationResponder(INT32 ch); void Moviemode_mode_Onchange(void); void Screenshot_option_Onchange(void); +// Addons menu updating +void Addons_option_Onchange(void); + // These defines make it a little easier to make menus #define DEFAULTMENUSTYLE(header, source, prev, x, y)\ {\ diff --git a/src/p_enemy.c b/src/p_enemy.c index ded0a20f5..7cdc354de 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -192,6 +192,7 @@ void A_JawzChase(mobj_t *actor); // SRB2kart void A_JawzExplode(mobj_t *actor); // SRB2kart void A_MineExplode(mobj_t *actor); // SRB2kart void A_BallhogExplode(mobj_t *actor); // SRB2kart +void A_LightningFollowPlayer(mobj_t *actor); // SRB2kart void A_OrbitNights(mobj_t *actor); void A_GhostMe(mobj_t *actor); void A_SetObjectState(mobj_t *actor); @@ -8312,6 +8313,34 @@ void A_BallhogExplode(mobj_t *actor) S_StartSound(mo2, actor->info->deathsound); return; } + +// A_LightningFollowPlayer: +// Dumb simple function that gives a mobj its target's momentums without updating its angle. +void A_LightningFollowPlayer(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_LightningFollowPlayer", actor)) + return; +#endif + fixed_t sx, sy; + if (actor->target) + { + if (actor->extravalue1) // Make the radius also follow the player somewhat accuratly + { + sx = actor->target->x + FixedMul((actor->target->scale*actor->extravalue1), FINECOSINE((actor->angle)>>ANGLETOFINESHIFT)); + sy = actor->target->y + FixedMul((actor->target->scale*actor->extravalue1), FINESINE((actor->angle)>>ANGLETOFINESHIFT)); + P_TeleportMove(actor, sx, sy, actor->target->z); + } + else // else just teleport to player directly + P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z); + + actor->momx = actor->target->momx; + actor->momy = actor->target->momy; + actor->momz = actor->target->momz; // Give momentum since we don't teleport to our player literally every frame. + } + return; +} + //} // Function: A_OrbitNights diff --git a/src/p_inter.c b/src/p_inter.c index 7a1484647..4a120a42a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -181,13 +181,13 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) { // Item-specific timer going off if (player->kartstuff[k_stealingtimer] || player->kartstuff[k_stolentimer] - || player->kartstuff[k_growshrinktimer] != 0 || player->kartstuff[k_rocketsneakertimer] + || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_rocketsneakertimer] || player->kartstuff[k_eggmanexplode]) return false; // Item slot already taken up if (player->kartstuff[k_itemroulette] - || player->kartstuff[k_itemamount] + || (weapon != 3 && player->kartstuff[k_itemamount]) || player->kartstuff[k_itemheld]) return false; } @@ -429,6 +429,27 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // We now identify by object type, not sprite! Tails 04-11-2001 switch (special->type) { + case MT_FLOATINGITEM: // SRB2kart + if (!P_CanPickupItem(player, 3) || (player->kartstuff[k_itemamount] && player->kartstuff[k_itemtype] != special->threshold)) + return; + + if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) + return; + + player->kartstuff[k_itemtype] = special->threshold; + player->kartstuff[k_itemamount] += special->movecount; + if (player->kartstuff[k_itemamount] > 255) + player->kartstuff[k_itemamount] = 255; + + S_StartSound(special, special->info->deathsound); + + P_SetTarget(&special->tracer, toucher); + special->flags2 |= MF2_NIGHTSPULL; + special->destscale = mapheaderinfo[gamemap-1]->mobj_scale>>4; + special->scalespeed <<= 1; + + special->flags &= ~MF_SPECIAL; + return; case MT_RANDOMITEM: // SRB2kart if (!P_CanPickupItem(player, 1)) return; @@ -469,9 +490,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); S_StartSound(poof, special->info->deathsound); - K_StripItems(player); - if (player->kartstuff[k_itemroulette] <= 0) - player->kartstuff[k_itemroulette] = 1; + K_DropItems(player); //K_StripItems(player); + K_StripOther(player); + player->kartstuff[k_itemroulette] = 1; player->kartstuff[k_roulettetype] = 2; if (special->target && special->target->player && (G_RaceGametype() || special->target->player->kartstuff[k_bumper] > 0)) @@ -2625,6 +2646,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) } } + if ((target->type == MT_JAWZ || target->type == MT_JAWZ_DUD || target->type == MT_JAWZ_SHIELD) && !(target->flags2 & MF2_AMBUSH)) + { + target->z += P_MobjFlip(target)*20*target->scale; + } + if (target->type == MT_SPIKE && inflictor && target->info->deathstate != S_NULL) { const fixed_t x=target->x,y=target->y,z=target->z; @@ -3334,6 +3360,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->mo->destscale = 6*player->mo->destscale/8; // Wipeout + K_DropItems(player); K_SpinPlayer(player, source, 1, false); damage = player->mo->health - 1; P_RingDamage(player, inflictor, source, damage); @@ -3345,7 +3372,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da quake.time = 5; } - K_StripItems(player); player->kartstuff[k_growshrinktimer] -= (200+(40*(16-player->kartstuff[k_position]))); } // Grow? Let's take that away. diff --git a/src/p_map.c b/src/p_map.c index e9d38272f..11dda089e 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -497,7 +497,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } - if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE))) + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE)) || (thing->flags & MF_NOCLIPTHING)) return true; // Don't collide with your buddies while NiGHTS-flying. diff --git a/src/p_mobj.c b/src/p_mobj.c index 233b307f6..456c0acfa 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -48,6 +48,7 @@ actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; static mobj_t *shadowcap = NULL; +mobj_t *waypointcap = NULL; void P_InitCachedActions(void) { @@ -6011,7 +6012,7 @@ void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on y return; // change angle - source->angle = R_PointToAngle2(source->x, source->y, tx, ty); + //source->angle = R_PointToAngle2(source->x, source->y, tx, ty); // change slope dist = P_AproxDistance(P_AproxDistance(tx - source->x, ty - source->y), tz - source->z); @@ -6020,7 +6021,7 @@ void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on y dist = 1; if (nightsgrab) - speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(8*FRACUNIT, source->scale); + speedmul = P_AproxDistance(dest->momx, dest->momy) + source->scale; else speedmul = P_AproxDistance(dest->momx, dest->momy) + FixedMul(source->info->speed, source->scale); @@ -6284,16 +6285,18 @@ static void P_RemoveOverlay(mobj_t *thing) void P_RunShadows(void) { - mobj_t *mobj; - mobj_t *next; + mobj_t *mobj, *next, *dest; for (mobj = shadowcap; mobj; mobj = next) { next = mobj->hnext; P_SetTarget(&mobj->hnext, NULL); - if (!mobj->target) + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + mobj->flags2 |= MF2_DONTDRAW; continue; // shouldn't you already be dead? + } if ((mobj->target->flags2 & MF2_DONTDRAW) || (((mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z+mobj->target->height > mobj->target->ceilingz) @@ -6330,7 +6333,12 @@ void P_RunShadows(void) // First scale to the same radius P_SetScale(mobj, FixedDiv(mobj->target->radius, mobj->info->radius)); - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); + dest = mobj->target; + + if (dest->type == MT_THUNDERSHIELD) + dest = dest->target; + + P_TeleportMove(mobj, dest->x, dest->y, mobj->target->z); if (((mobj->eflags & MFE_VERTICALFLIP) && (mobj->ceilingz > mobj->z+mobj->height)) || (!(mobj->eflags & MFE_VERTICALFLIP) && (mobj->floorz < mobj->z))) @@ -6348,7 +6356,7 @@ void P_RunShadows(void) P_SetScale(mobj, FixedDiv(mobj->scale, max(FRACUNIT, ((mobj->target->z-mobj->z)/200)+FRACUNIT))); // Check new position to see if you should still be on that ledge - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->z); + P_TeleportMove(mobj, dest->x, dest->y, mobj->z); mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : mobj->floorz); @@ -6356,6 +6364,9 @@ void P_RunShadows(void) break; } } + + if (mobj->target->type == MT_FLOATINGITEM) + P_SetScale(mobj, mobj->scale/2); } P_SetTarget(&shadowcap, NULL); } @@ -6631,7 +6642,7 @@ void P_MobjThinker(mobj_t *mobj) /*if (mobj->health > 0 && mobj->target && mobj->target->player && mobj->target->player->health > 0 && !mobj->target->player->spectator) { - // Was this so hard? -- Handled this with K_UpdateHnextList and K_ClearHnextList instead of thinking it away... + // Was this so hard? -- Handled this with K_UpdateHnextList instead of thinking it away... if ((mobj->type == MT_ORBINAUT_SHIELD && mobj->target->player->kartstuff[k_itemtype] != KITEM_ORBINAUT) || (mobj->type == MT_JAWZ_SHIELD && mobj->target->player->kartstuff[k_itemtype] != KITEM_JAWZ) || (mobj->movedir > 0 && ((UINT16)mobj->target->player->kartstuff[k_itemamount] < mobj->movedir)) @@ -6815,14 +6826,16 @@ void P_MobjThinker(mobj_t *mobj) mobj->x = mobj->target->x; mobj->y = mobj->target->y; + mobj->angle = R_PointToAngle(mobj->x, mobj->y) + ANGLE_90; // literally only happened because i wanted to ^L^R the SPR_ITEM's + if (!(mobj->target->eflags & MFE_VERTICALFLIP)) { - mobj->z = mobj->target->z + P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT; + mobj->z = mobj->target->z + P_GetPlayerHeight(mobj->target->player)+(16+11)*mapheaderinfo[gamemap-1]->mobj_scale; mobj->eflags &= ~MFE_VERTICALFLIP; } else { - mobj->z = mobj->target->z - P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT; + mobj->z = mobj->target->z - P_GetPlayerHeight(mobj->target->player)+(16+11)*mapheaderinfo[gamemap-1]->mobj_scale; mobj->eflags |= MFE_VERTICALFLIP; } P_SetThingPosition(mobj); @@ -6838,7 +6851,8 @@ void P_MobjThinker(mobj_t *mobj) mobj->tracer = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); P_SetTarget(&mobj->tracer->target, mobj); P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); - P_SetScale(mobj->tracer, mobj->scale); + P_SetMobjState(mobj->tracer, S_ITEMICON); // null sprite and frame to be overwritten later + P_SetScale(mobj->tracer, (mobj->tracer->destscale = mobj->scale)); } if (!(mobj->flags2 & MF2_DONTDRAW)) @@ -6939,7 +6953,7 @@ void P_MobjThinker(mobj_t *mobj) else { P_SetMobjState(mobj, S_PLAYERARROW); - P_SetMobjState(mobj->tracer, S_INVISIBLE); + P_SetMobjState(mobj->tracer, S_ITEMICON); // null sprite and frame to be overwritten later } mobj->tracer->destscale = scale; @@ -7009,12 +7023,12 @@ void P_MobjThinker(mobj_t *mobj) if (!(mobj->target->eflags & MFE_VERTICALFLIP)) { - mobj->z = mobj->target->z + (P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT+(64*mobj->scale)); + mobj->z = mobj->target->z + (P_GetPlayerHeight(mobj->target->player)+16*mapheaderinfo[gamemap-1]->mobj_scale+(64*mobj->scale)); mobj->eflags &= ~MFE_VERTICALFLIP; } else { - mobj->z = mobj->target->z - (P_GetPlayerHeight(mobj->target->player)+16*FRACUNIT+(64*mobj->scale)); + mobj->z = mobj->target->z - (P_GetPlayerHeight(mobj->target->player)+16*mapheaderinfo[gamemap-1]->mobj_scale+(64*mobj->scale)); mobj->eflags |= MFE_VERTICALFLIP; } P_SetThingPosition(mobj); @@ -7919,46 +7933,120 @@ void P_MobjThinker(mobj_t *mobj) mobj->threshold = 0; } break; - case MT_ORBINAUT: + case MT_FLOATINGITEM: { - sector_t *sec2; - fixed_t finalspeed = mobj->info->speed; - - P_SpawnGhostMobj(mobj); - - if (gamespeed == 0) - finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); - else if (gamespeed == 2) - finalspeed = FixedMul(finalspeed, FRACUNIT+FRACUNIT/4); - - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); - if (mobj->health <= 5) + if (mobj->flags & MF_NOCLIPTHING) { - INT32 i; - for (i = 5; i >= mobj->health; i--) + if (P_IsObjectOnGround(mobj)) { - finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); + mobj->momx = 1; + mobj->momy = 0; + mobj->flags &= ~MF_NOCLIPTHING; + mobj->flags |= MF_NOGRAVITY; } - finalspeed = FixedMul(finalspeed, mapheaderinfo[gamemap-1]->mobj_scale); - P_InstaThrust(mobj, mobj->angle, finalspeed); } else { - finalspeed = FixedMul(finalspeed, mapheaderinfo[gamemap-1]->mobj_scale); - P_InstaThrust(mobj, mobj->angle, finalspeed); + mobj->angle += 2*ANG2; + if (mobj->flags2 & MF2_NIGHTSPULL) + { + if (!mobj->tracer || !mobj->tracer->health + || mobj->scale <= mapheaderinfo[gamemap-1]->mobj_scale>>4) + { + P_RemoveMobj(mobj); + return; + } + P_Attract(mobj, mobj->tracer, true); + } + else + { + fixed_t adj = FixedMul(FRACUNIT - FINECOSINE((mobj->movedir>>ANGLETOFINESHIFT) & FINEMASK), (mapheaderinfo[gamemap-1]->mobj_scale<<3)); + mobj->movedir += 2*ANG2; + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->ceilingz - mobj->height - adj; + else + mobj->z = mobj->floorz + adj; + } } - sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) - || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) - && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) - K_DoPogoSpring(mobj, 0, false); + switch (mobj->threshold) + { + case KITEM_ORBINAUT: + mobj->sprite = SPR_ITMO; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(min(mobj->movecount-1, 3)); + break; + case KITEM_INVINCIBILITY: + mobj->sprite = SPR_ITMI; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|((leveltime % (7*3)) / 3); + break; + case KITEM_SAD: + mobj->sprite = SPR_ITEM; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE; + break; + default: + mobj->sprite = SPR_ITEM; + mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(mobj->threshold); + break; + } + break; + } + case MT_ORBINAUT: + { + boolean grounded = P_IsObjectOnGround(mobj); + if (mobj->flags2 & MF2_AMBUSH) + { + if (grounded && (mobj->flags & MF_NOCLIPTHING)) + { + mobj->momx = 1; + mobj->momy = 0; + mobj->frame = 3; + S_StartSound(mobj, mobj->info->activesound); + mobj->flags &= ~MF_NOCLIPTHING; + } + else if (mobj->movecount) + mobj->movecount--; + else if (mobj->frame < 3) + { + mobj->movecount = 2; + mobj->frame++; + } + } + else + { + fixed_t finalspeed = mobj->info->speed; - if (mobj->threshold > 0) - mobj->threshold--; + P_SpawnGhostMobj(mobj); - if (leveltime % 6 == 0) - S_StartSound(mobj, mobj->info->activesound); + if (gamespeed == 0) + finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); + else if (gamespeed == 2) + finalspeed = FixedMul(finalspeed, FRACUNIT+FRACUNIT/4); + + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + if (mobj->health <= 5) + { + INT32 i; + for (i = 5; i >= mobj->health; i--) + finalspeed = FixedMul(finalspeed, FRACUNIT-FRACUNIT/4); + } + finalspeed = FixedMul(finalspeed, mapheaderinfo[gamemap-1]->mobj_scale); + P_InstaThrust(mobj, mobj->angle, finalspeed); + + if (grounded) + { + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); + if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) + || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) + && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) + K_DoPogoSpring(mobj, 0, false); + } + + if (mobj->threshold > 0) + mobj->threshold--; + + if (leveltime % 6 == 0) + S_StartSound(mobj, mobj->info->activesound); + } break; } case MT_JAWZ: @@ -8031,23 +8119,38 @@ void P_MobjThinker(mobj_t *mobj) } case MT_JAWZ_DUD: { - sector_t *sec2; + boolean grounded = P_IsObjectOnGround(mobj); + if (mobj->flags2 & MF2_AMBUSH) + { + if (grounded && (mobj->flags & MF_NOCLIPTHING)) + { + mobj->momx = 1; + mobj->momy = 0; + S_StartSound(mobj, mobj->info->deathsound); + mobj->flags &= ~MF_NOCLIPTHING; + } + } + else + { + P_SpawnGhostMobj(mobj); + mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); + P_InstaThrust(mobj, mobj->angle, mobj->info->speed); - P_SpawnGhostMobj(mobj); - mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); - P_InstaThrust(mobj, mobj->angle, mobj->info->speed); + if (grounded) + { + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); + if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) + || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) + && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) + K_DoPogoSpring(mobj, 0, false); + } - sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) - || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) - && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) - K_DoPogoSpring(mobj, 0, false); + if (mobj->threshold > 0) + mobj->threshold--; - if (mobj->threshold > 0) - mobj->threshold--; - - if (leveltime % TICRATE == 0) - S_StartSound(mobj, mobj->info->activesound); + if (leveltime % TICRATE == 0) + S_StartSound(mobj, mobj->info->activesound); + } break; } @@ -8214,13 +8317,41 @@ void P_MobjThinker(mobj_t *mobj) P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); break; case MT_THUNDERSHIELD: + { + fixed_t destx, desty; if (!mobj->target || !mobj->target->health || (mobj->target->player && mobj->target->player->kartstuff[k_curshield] != 1)) { P_RemoveMobj(mobj); return; } - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); + P_SetScale(mobj, (mobj->destscale = (5*mobj->target->destscale)>>2)); + + if (!splitscreen /*&& rendermode != render_soft*/) + { + angle_t viewingangle; + statenum_t curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); + + if (players[displayplayer].awayviewtics) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayer].awayviewmobj->x, players[displayplayer].awayviewmobj->y); + else if (!camera.chase && players[displayplayer].mo) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayer].mo->x, players[displayplayer].mo->y); + else + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera.x, camera.y); + + if (curstate > S_THUNDERSHIELD15) + viewingangle += ANGLE_180; + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); + desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); + } + else + { + destx = mobj->target->x; + desty = mobj->target->y; + } + + P_TeleportMove(mobj, destx, desty, mobj->target->z); break; + } case MT_KARMAHITBOX: if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator || (G_RaceGametype() || mobj->target->player->kartstuff[k_bumper])) @@ -8869,6 +9000,41 @@ void P_SceneryThinker(mobj_t *mobj) } P_CycleMobjState(mobj); + + if (mobj->type != MT_RANDOMAUDIENCE) + return; + + { + if (!mobj->colorized) // a fan of someone? + return; + + if (mobj->threshold >= 0) // not already happy or sad? + { + if (!playeringame[mobj->threshold] || players[mobj->threshold].spectator) // focused on a valid player? + return; + + if (!(players[mobj->threshold].exiting) && !(players[mobj->threshold].pflags & PF_TIMEOVER)) // not finished yet? + return; + + if (K_IsPlayerLosing(&players[mobj->threshold])) + mobj->threshold = -2; + else + { + mobj->threshold = -1; + S_StartSound(mobj, sfx_chaooo); + } + } + + if (mobj->threshold == -1) + mobj->angle += ANGLE_22h; + + if (((statenum_t)(mobj->state-states) != S_AUDIENCE_CHAO_CHEER2) || (mobj->tics != states[S_AUDIENCE_CHAO_CHEER2].tics)) // not at the start of your cheer jump? + return; + + mobj->momz = 0; + + P_SetMobjState(mobj, ((mobj->threshold == -1) ? S_AUDIENCE_CHAO_WIN2 : S_AUDIENCE_CHAO_LOSE)); + } } // @@ -9116,9 +9282,43 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } break; case MT_BIGRING: - mobj->destscale = 3*FRACUNIT; - P_SetScale(mobj, 3*FRACUNIT); + P_SetScale(mobj, (mobj->destscale = 3*FRACUNIT)); break; + case MT_RANDOMAUDIENCE: + { + fixed_t randu = P_RandomFixed(); + P_SetScale(mobj, (mobj->destscale <<= 1)); + if (randu < (FRACUNIT/9)) // a fan of someone? + { + UINT8 i, pcount = 0; + UINT8 pnum[MAXPLAYERS]; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + pnum[pcount] = i; + pcount++; + } + + if (pcount) + { + mobj->threshold = pnum[P_RandomKey(pcount)]; + mobj->color = players[mobj->threshold].skincolor; + mobj->colorized = true; + break; + } + } + + if (randu > (FRACUNIT/2)) + { + mobj->color = P_RandomKey(MAXSKINCOLORS-1)+1; + break; + } + + mobj->color = SKINCOLOR_AQUA; + break; + } default: break; } @@ -9129,6 +9329,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BIGMACE: case MT_SMALLMACE: case MT_FALLINGROCK: //case MT_RANDOMITEM: + case MT_FLOATINGITEM: case MT_BATTLEBUMPER: case MT_BANANA: case MT_BANANA_SHIELD: //case MT_FAKEITEM: case MT_FAKESHIELD: @@ -9136,6 +9337,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_JAWZ: case MT_JAWZ_DUD: case MT_JAWZ_SHIELD: case MT_SSMINE: case MT_SSMINE_SHIELD: case MT_BALLHOG: case MT_SINK: + case MT_THUNDERSHIELD: P_SpawnShadowMobj(mobj); default: break; @@ -9228,6 +9430,8 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster) if (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->mobj_scale != FRACUNIT) //&& !(mobj->type == MT_BLACKEGGMAN) mobj->destscale = mapheaderinfo[gamemap-1]->mobj_scale; + P_SetScale(mobj, mobj->destscale); + // set subsector and/or block links P_SetThingPosition(mobj); I_Assert(mobj->subsector != NULL); @@ -10875,6 +11079,8 @@ ML_NOCLIMB : Direction not controllable else if (i == MT_BOSS3WAYPOINT) // SRB2kart 120217 - Used to store checkpoint num { mobj->health = mthing->angle; + P_SetTarget(&mobj->tracer, waypointcap); + P_SetTarget(&waypointcap, mobj); } else if (i == MT_SPIKE) { diff --git a/src/p_mobj.h b/src/p_mobj.h index 34d1f644e..df6e7642e 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -429,6 +429,8 @@ typedef struct actioncache_s extern actioncache_t actioncachehead; +extern mobj_t *waypointcap; + void P_InitCachedActions(void); void P_RunCachedActions(void); void P_AddCachedAction(mobj_t *mobj, INT32 statenum); diff --git a/src/p_saveg.c b/src/p_saveg.c index d9f430008..ffcc8789a 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -945,11 +945,10 @@ typedef enum MD2_EXTVAL2 = 1<<6, MD2_HNEXT = 1<<7, MD2_HPREV = 1<<8, + MD2_COLORIZED = 1<<9, + MD2_WAYPOINTCAP = 1<<10 #ifdef ESLOPE - MD2_SLOPE = 1<<9, - MD2_COLORIZED = 1<<10 -#else - MD2_COLORIZED = 1<<9 + , MD2_SLOPE = 1<<11 #endif } mobj_diff2_t; @@ -1146,6 +1145,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) #endif if (mobj->colorized) diff2 |= MD2_COLORIZED; + if (mobj == waypointcap) + diff2 |= MD2_WAYPOINTCAP; if (diff2 != 0) diff |= MD_MORE; @@ -2165,6 +2166,9 @@ static void LoadMobjThinker(actionf_p1 thinker) P_AddThinker(&mobj->thinker); + if (diff2 & MD2_WAYPOINTCAP) + P_SetTarget(&waypointcap, mobj); + mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function } diff --git a/src/p_setup.c b/src/p_setup.c index 501c80d9c..6c7b6e927 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -54,6 +54,8 @@ #include "v_video.h" +#include "filesrch.h" // refreshdirmenu + // wipes #include "f_finale.h" @@ -3132,6 +3134,7 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) if ((numlumps = W_LoadWadFile(wadfilename)) == INT16_MAX) { + refreshdirmenu |= REFRESHDIR_NOTLOADED; CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), wadfilename); return false; } diff --git a/src/p_slopes.c b/src/p_slopes.c index c516fa970..35d4c4234 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -251,7 +251,7 @@ void P_SpawnSlope_Line(int linenum) UINT8 flags = 0; // Slope flags if (line->flags & ML_NOSONIC) flags |= SL_NOPHYSICS; - if (line->flags & ML_NOTAILS) + if (!(line->flags & ML_NOTAILS)) flags |= SL_NODYNAMIC; if (line->flags & ML_NOKNUX) flags |= SL_ANCHORVERTEX; diff --git a/src/p_tick.c b/src/p_tick.c index 3a55353d7..3c5ed0b9e 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -180,6 +180,7 @@ void Command_CountMobjs_f(void) void P_InitThinkers(void) { thinkercap.prev = thinkercap.next = &thinkercap; + waypointcap = NULL; } // diff --git a/src/r_things.c b/src/r_things.c index 80882e649..bede9cd13 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -920,6 +920,16 @@ static void R_DrawVisSprite(vissprite_t *vis) for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale) { + if (vis->scalestep) // currently papersprites only + { +#ifndef RANGECHECK + if ((frac>>FRACBITS) < 0 || (frac>>FRACBITS) >= SHORT(patch->width)) // if this doesn't work i'm removing papersprites + break; +#endif + sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); + dc_iscale = (0xffffffffu / (unsigned)spryscale); + spryscale += vis->scalestep; + } #ifdef RANGECHECK texturecolumn = frac>>FRACBITS; @@ -929,16 +939,10 @@ static void R_DrawVisSprite(vissprite_t *vis) #else column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); #endif - if (vis->scalestep) - { - sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); - dc_iscale = (0xffffffffu / (unsigned)spryscale); - } if (vis->vflip) R_DrawFlippedMaskedColumn(column, patch->height); else R_DrawMaskedColumn(column); - spryscale += vis->scalestep; } colfunc = basecolfunc; @@ -1262,7 +1266,7 @@ static void R_ProjectSprite(mobj_t *thing) offset2 = FixedMul(spritecachedinfo[lump].width, this_scale); tx += FixedMul(offset2, ang_scale); - x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - (papersprite ? 2 : 1); + x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - 1; // off the left side if (x2 < 0) @@ -1271,7 +1275,9 @@ static void R_ProjectSprite(mobj_t *thing) if (papersprite) { fixed_t yscale2, cosmul, sinmul, tz2; - INT32 range; + + if (x2 <= x1) + return; if (ang >= ANGLE_180) { @@ -1301,12 +1307,7 @@ static void R_ProjectSprite(mobj_t *thing) if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier return; - if (x2 > x1) - range = (x2 - x1); - else - range = 1; - - scalestep = (yscale2 - yscale)/range; + scalestep = (yscale2 - yscale)/(x2 - x1); // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2? // sortscale = max(yscale, yscale2); diff --git a/src/sounds.c b/src/sounds.c index e02321235..8e0ed4e08 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -815,6 +815,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"hogbom", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"kpogos", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"ddash", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"zio3", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, + {"mcitm1", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, + {"chaooo", false, 110, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"dbgsal", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, diff --git a/src/sounds.h b/src/sounds.h index 44a1a2bd6..301b39121 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -890,6 +890,9 @@ typedef enum sfx_hogbom, sfx_kpogos, sfx_ddash, + sfx_zio3, + sfx_mcitm1, + sfx_chaooo, sfx_itfree, sfx_dbgsal, diff --git a/src/v_video.c b/src/v_video.c index 50ad0a262..46d34acce 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1253,6 +1253,7 @@ void V_DrawFadeConsBack(INT32 plines) // UINT8 *V_GetStringColormap(INT32 colorflags) { +#if 0 // perfect switch ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT) { case 1: // 0x81, purple @@ -1288,6 +1289,12 @@ UINT8 *V_GetStringColormap(INT32 colorflags) default: // reset return NULL; } +#else // optimised + colorflags = ((colorflags & V_CHARCOLORMASK) >> V_CHARCOLORSHIFT); + if (!colorflags || colorflags > 15) // INT32 is signed, but V_CHARCOLORMASK is a very restrictive mask. + return NULL; + return (purplemap+((colorflags-1)<<8)); +#endif } // Writes a single character (draw WHITE if bit 7 set) diff --git a/src/w_wad.c b/src/w_wad.c index 89fdadde6..2b6b955b3 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -34,6 +34,8 @@ #include "z_zone.h" #include "fastcmp.h" +#include "filesrch.h" + #include "i_video.h" // rendermode #include "d_netfil.h" #include "dehacked.h" @@ -294,12 +296,22 @@ UINT16 W_LoadWadFile(const char *filename) UINT32 numlumps; size_t i; INT32 compressed = 0; - size_t packetsize = 0; - serverinfo_pak *dummycheck = NULL; + size_t packetsize; UINT8 md5sum[16]; + boolean important; - // Shut the compiler up. - (void)dummycheck; + if (!(refreshdirmenu & REFRESHDIR_ADDFILE)) + refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier + + if (refreshdirname) + Z_Free(refreshdirname); + if (dirmenu) + { + refreshdirname = Z_StrDup(filename); + nameonly(refreshdirname); + } + else + refreshdirname = NULL; //CONS_Debug(DBG_SETUP, "Loading %s\n", filename); // @@ -308,6 +320,7 @@ UINT16 W_LoadWadFile(const char *filename) if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); + refreshdirmenu |= REFRESHDIR_MAX; return INT16_MAX; } @@ -317,21 +330,21 @@ UINT16 W_LoadWadFile(const char *filename) // Check if wad files will overflow fileneededbuffer. Only the filename part // is send in the packet; cf. - for (i = 0; i < numwadfiles; i++) + // see PutFileNeeded in d_netfil.c + if ((important = !W_VerifyNMUSlumps(filename))) { - packetsize += nameonlylength(wadfiles[i]->filename); - packetsize += 22; // MD5, etc. - } + packetsize = packetsizetally + nameonlylength(filename) + 22; - packetsize += nameonlylength(filename); - packetsize += 22; + if (packetsize > MAXFILENEEDED*sizeof(UINT8)) + { + CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); + refreshdirmenu |= REFRESHDIR_MAX; + if (handle) + fclose(handle); + return INT16_MAX; + } - if (packetsize > sizeof(dummycheck->fileneeded)) - { - CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); - if (handle) - fclose(handle); - return INT16_MAX; + packetsizetally = packetsize; } // detect dehacked file with the "soc" extension @@ -470,6 +483,7 @@ UINT16 W_LoadWadFile(const char *filename) wadfile->handle = handle; wadfile->numlumps = (UINT16)numlumps; wadfile->lumpinfo = lumpinfo; + wadfile->important = important; fseek(handle, 0, SEEK_END); wadfile->filesize = (unsigned)ftell(handle); @@ -1240,19 +1254,27 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist, */ int W_VerifyNMUSlumps(const char *filename) { - // MIDI, MOD/S3M/IT/XM/OGG/MP3/WAV, WAVE SFX - // ENDOOM text and palette lumps lumpchecklist_t NMUSlist[] = { - {"D_", 2}, - {"O_", 2}, - {"DS", 2}, - {"ENDOOM", 6}, - {"PLAYPAL", 7}, - {"COLORMAP", 8}, - {"PAL", 3}, - {"CLM", 3}, - {"TRANS", 5}, + {"D_", 2}, // MIDI music + {"O_", 2}, // Digital music + {"DS", 2}, // Sound effects + + {"ENDOOM", 6}, // ENDOOM text lump + {"PLAYPAL", 7}, // Palette + {"COLORMAP", 8}, // Colormap + {"PAL", 3}, // Palette changes + {"CLM", 3}, // Colormap changes + {"TRANS", 5}, // Translucency map + + {"LTFNT", 5}, // Level title font changes + {"STCFN", 5}, // Console font changes + {"TNYFN", 5}, // Tiny console font changes + {"MKFNT", 5}, // Kart font changes + + {"M_", 2}, // Menu changes + {"K_", 2}, // Kart graphic changes + {NULL, 0}, }; return W_VerifyFile(filename, NMUSlist, false); diff --git a/src/w_wad.h b/src/w_wad.h index f7ea64a56..8da228045 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -70,6 +70,7 @@ typedef struct wadfile_s FILE *handle; UINT32 filesize; // for network UINT8 md5sum[16]; + boolean important; } wadfile_t; #define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word