diff --git a/src/command.c b/src/command.c index 42cabe1b..e6279557 100644 --- a/src/command.c +++ b/src/command.c @@ -391,6 +391,39 @@ void COM_AddCommand(const char *name, com_func_t func) com_commands = cmd; } +/** Adds a console command for Lua. + * No I_Errors allowed; return a negative code instead. + * + * \param name Name of the command. + */ +int COM_AddLuaCommand(const char *name) +{ + xcommand_t *cmd; + + // fail if the command is a variable name + if (CV_StringValue(name)[0] != '\0') + return -1; + + // command already exists + for (cmd = com_commands; cmd; cmd = cmd->next) + { + if (!stricmp(name, cmd->name)) //case insensitive now that we have lower and uppercase! + { + // replace the built in command. + cmd->function = COM_Lua_f; + return 1; + } + } + + // Add a new command. + cmd = ZZ_Alloc(sizeof *cmd); + cmd->name = name; + cmd->function = COM_Lua_f; + cmd->next = com_commands; + com_commands = cmd; + return 0; +} + /** Tests if a command exists. * * \param com_name Name to test for. @@ -558,7 +591,7 @@ static void COM_CEchoFlags_f(void) HU_SetCEchoFlags(atoi(arg)); } else - CONS_Printf(M_GetText("cechoflags : set CEcho flags, prepend with 0x to use hexadecimal")); + CONS_Printf(M_GetText("cechoflags : set CEcho flags, prepend with 0x to use hexadecimal\n")); } /** Sets the duration for CECHO commands to stay on the screen @@ -1017,6 +1050,8 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) if (var->PossibleValue) { INT32 v = atoi(valstr); + if (!v && valstr[0] != '0') + v = INT32_MIN; // Invalid integer trigger if (var->PossibleValue[0].strvalue && !stricmp(var->PossibleValue[0].strvalue, "MIN")) // bounded cvar { @@ -1029,20 +1064,23 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) if (!var->PossibleValue[i].strvalue) I_Error("Bounded cvar \"%s\" without maximum!\n", var->name); #endif - if (v < var->PossibleValue[0].value || !stricmp(valstr, "MIN")) + + if ((v != INT32_MIN && v < var->PossibleValue[0].value) || !stricmp(valstr, "MIN")) { v = var->PossibleValue[0].value; valstr = var->PossibleValue[0].strvalue; override = true; overrideval = v; } - if (v > var->PossibleValue[i].value || !stricmp(valstr, "MAX")) + else if ((v != INT32_MIN && v > var->PossibleValue[i].value) || !stricmp(valstr, "MAX")) { v = var->PossibleValue[i].value; valstr = var->PossibleValue[i].strvalue; override = true; overrideval = v; } + if (v == INT32_MIN) + goto badinput; } else { @@ -1052,48 +1090,32 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) for (i = 0; var->PossibleValue[i].strvalue; i++) if (!stricmp(var->PossibleValue[i].strvalue, valstr)) goto found; - if (!v) - if (strcmp(valstr, "0")) - goto error; - // check INT32 now - for (i = 0; var->PossibleValue[i].strvalue; i++) - if (v == var->PossibleValue[i].value) - goto found; - -error: - // not found - - // But wait, there's hope! - if (var->PossibleValue == CV_OnOff - || var->PossibleValue == CV_YesNo) + if (v != INT32_MIN) { - INT32 hopevalue = -1; + // check INT32 now + for (i = 0; var->PossibleValue[i].strvalue; i++) + if (v == var->PossibleValue[i].value) + goto found; + } + // Not found ... but wait, there's hope! + if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo) + { + overrideval = -1; + if (!stricmp(valstr, "on") || !stricmp(valstr, "yes")) + overrideval = 1; + else if (!stricmp(valstr, "off") || !stricmp(valstr, "no")) + overrideval = 0; - if (!stricmp(valstr, "on")) - hopevalue = 1; - else if (!stricmp(valstr, "off")) - hopevalue = 0; - else if (!stricmp(valstr, "yes")) - hopevalue = 1; - else if (!stricmp(valstr, "no")) - hopevalue = 0; - - if (hopevalue != -1) + if (overrideval != -1) { for (i = 0; var->PossibleValue[i].strvalue; i++) - if (hopevalue == var->PossibleValue[i].value) + if (overrideval == var->PossibleValue[i].value) goto found; } } // ...or not. - if (var != &cv_nextmap) // Suppress errors for cv_nextmap - CONS_Printf(M_GetText("\"%s\" is not a possible value for \"%s\"\n"), valstr, var->name); - - if (var->defaultvalue == valstr) - I_Error("Variable %s default value \"%s\" is not a possible value\n", - var->name, var->defaultvalue); - return; + goto badinput; found: var->value = var->PossibleValue[i].value; var->string = var->PossibleValue[i].strvalue; @@ -1141,6 +1163,18 @@ finish: #endif if (var->flags & CV_CALL && !stealth) var->func(); + + return; + +// landing point for possiblevalue failures +badinput: + + if (var != &cv_nextmap) // Suppress errors for cv_nextmap + CONS_Printf(M_GetText("\"%s\" is not a possible value for \"%s\"\n"), valstr, var->name); + + // default value not valid... ?! + if (var->defaultvalue == valstr) + I_Error("Variable %s default value \"%s\" is not a possible value\n", var->name, var->defaultvalue); } // diff --git a/src/command.h b/src/command.h index c7962faf..a17e8eac 100644 --- a/src/command.h +++ b/src/command.h @@ -23,6 +23,7 @@ typedef void (*com_func_t)(void); void COM_AddCommand(const char *name, com_func_t func); +int COM_AddLuaCommand(const char *name); size_t COM_Argc(void); const char *COM_Argv(size_t arg); // if argv > argc, returns empty string diff --git a/src/d_main.c b/src/d_main.c index 9e00049e..2f3dd8b6 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1086,15 +1086,14 @@ void D_SRB2Main(void) #endif D_CleanFile(); -#if 1 // md5s last updated 3/22/14 +#if 1 // md5s last updated 4/13/14 // Check MD5s of autoloaded files W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad - W_VerifyFileMD5(1, "a894044b555dfcc71865cee16a996e88"); // zones.dta - W_VerifyFileMD5(2, "4c410c1de6e0440cc5b2858dcca80c3e"); // player.dta + W_VerifyFileMD5(1, "e956466eff2c79f7b1cdefad24761bce"); // zones.dta + W_VerifyFileMD5(2, "95a4cdbed287323dd361243f357a5fd2"); // player.dta W_VerifyFileMD5(3, "85901ad4bf94637e5753d2ac2c03ea26"); // rings.dta - W_VerifyFileMD5(4, "386ab4ffc8c9fb0fa62f788a16e5c218"); // patch.dta - + W_VerifyFileMD5(4, "1f37fe7bcc608a23eadb0e2c2d7c7124"); // patch.dta // don't check music.dta 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. #endif diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 13d4cb9d..1a1777a4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -134,6 +134,7 @@ static void Command_Skynum_f(void); static void Command_ExitLevel_f(void); static void Command_Showmap_f(void); +static void Command_Mapmd5_f(void); static void Command_Teamchange_f(void); static void Command_Teamchange2_f(void); @@ -330,7 +331,6 @@ consvar_t cv_itemfinder = {"itemfinder", "Off", CV_CALL, CV_OnOff, ItemFinder_On consvar_t cv_match_scoring = {"matchscoring", "Normal", CV_NETVAR|CV_CHEAT, match_scoring_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_realnames = {"realnames", "Off", CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_timetic = {"timerres", "Normal", 0, timetic_cons_t, NULL, CV_SAVE, NULL, NULL, 0, 0, NULL}; // use tics in display @@ -431,6 +431,7 @@ void D_RegisterServerCommands(void) COM_AddCommand("retry", Command_Retry_f); COM_AddCommand("exitlevel", Command_ExitLevel_f); COM_AddCommand("showmap", Command_Showmap_f); + COM_AddCommand("mapmd5", Command_Mapmd5_f); COM_AddCommand("addfile", Command_Addfile); COM_AddCommand("listwad", Command_ListWADS_f); @@ -643,7 +644,6 @@ void D_RegisterClientCommands(void) #ifdef SEENAMES CV_RegisterVar(&cv_seenames); #endif - CV_RegisterVar(&cv_realnames); CV_RegisterVar(&cv_rollingdemos); CV_RegisterVar(&cv_netstat); @@ -3866,6 +3866,20 @@ static void Command_Showmap_f(void) CONS_Printf(M_GetText("You must be in a level to use this.\n")); } +static void Command_Mapmd5_f(void) +{ + if (gamestate == GS_LEVEL) + { + INT32 i; + char md5tmp[33]; + for (i = 0; i < 16; ++i) + sprintf(&md5tmp[i*2], "%02x", mapmd5[i]); + CONS_Printf("%s: %s\n", G_BuildMapName(gamemap), md5tmp); + } + else + CONS_Printf(M_GetText("You must be in a level to use this.\n")); +} + static void Command_ExitLevel_f(void) { if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 932d7766..c1cc27ce 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -105,7 +105,7 @@ extern consvar_t cv_overtime; extern consvar_t cv_startinglives; // for F_finale.c -extern consvar_t cv_realnames, cv_rollingdemos; +extern consvar_t cv_rollingdemos; extern consvar_t cv_resetmusic; diff --git a/src/d_netfil.c b/src/d_netfil.c index bc2ff87c..84fe0fbf 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -60,6 +60,8 @@ #include "md5.h" #include "filesrch.h" +#include + static void SendFile(INT32 node, const char *filename, UINT8 fileid); // sender structure @@ -652,7 +654,7 @@ void Got_Filetxpak(void) { if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n"); fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb"); - if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: disk full ?",fileneeded[filenum].filename); + if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno)); CONS_Printf("\r%s...\n",fileneeded[filenum].filename); fileneeded[filenum].currentsize = 0; fileneeded[filenum].status = FS_DOWNLOADING; @@ -672,7 +674,7 @@ void Got_Filetxpak(void) // we can receive packet in the wrong order, anyway all os support gaped file fseek(fileneeded[filenum].phandle,pos,SEEK_SET); if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1) - I_Error("Can't write %s: disk full ? or %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle))); + I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle))); fileneeded[filenum].currentsize += size; // finished? diff --git a/src/dehacked.c b/src/dehacked.c index 35e672eb..cf40ac3e 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -71,8 +71,6 @@ static powertype_t get_power(const char *word); #endif boolean deh_loaded = false; -boolean modcredits = false; // Whether a mod creator's name will show in the credits. -char modcreditname[32]; static int dbg_line; static boolean gamedataadded = false; @@ -3285,12 +3283,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) } DEH_WriteUndoline(word, word2, UNDO_HEADER); } - else if (fastcmp(word, "MODBY")) - { - memset(modcreditname, 0, sizeof(char) * 32); - strcpy(modcreditname, origpos+6); - modcredits = true; - } /* else if (fastcmp(word, "ANIMTEX")) { readAnimTex(f, i); @@ -4451,6 +4443,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CYBRAKDEMONTARGETRETICULE13", "S_CYBRAKDEMONTARGETRETICULE14", + "S_CYBRAKDEMONTARGETDOT", + "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1", "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2", "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3", @@ -6648,6 +6642,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_CYBRAKDEMON_FLAMESHOT", "MT_CYBRAKDEMON_FLAMEREST", "MT_CYBRAKDEMON_TARGET_RETICULE", + "MT_CYBRAKDEMON_TARGET_DOT", "MT_CYBRAKDEMON_NAPALM_BOMB_LARGE", "MT_CYBRAKDEMON_NAPALM_BOMB_SMALL", "MT_CYBRAKDEMON_NAPALM_FLAMES", @@ -7301,12 +7296,12 @@ static const char *const POWERS_LIST[] = { // Weapon ammunition "INFINITYRING", - "BOUNCERING", - "RAILRING", "AUTOMATICRING", - "EXPLOSIONRING", + "BOUNCERING", "SCATTERRING", "GRENADERING", + "EXPLOSIONRING", + "RAILRING", // Power Stones "EMERALDS", // stored like global 'emeralds' variable @@ -7441,6 +7436,7 @@ struct { {"TOL_MATCH",TOL_MATCH}, {"TOL_TAG",TOL_TAG}, {"TOL_CTF",TOL_CTF}, + {"TOL_CUSTOM",TOL_CUSTOM}, {"TOL_2D",TOL_2D}, {"TOL_MARIO",TOL_MARIO}, {"TOL_NIGHTS",TOL_NIGHTS}, @@ -7926,8 +7922,9 @@ static fixed_t find_const(const char **rword) free(word); return r; } - if (*word >= 'A' && !*(word+1)) { // Turn a single A-z symbol into numbers, like sprite frames. - r = *word-'A'; + if (!*(word+1) && // Turn a single A-z symbol into numbers, like sprite frames. + (*word >= 'A' && *word <= 'Z') || (*word >= 'a' && *word <= 'z')) { + r = R_Char2Frame(*word); free(word); return r; } diff --git a/src/dehacked.h b/src/dehacked.h index 7ef376f3..d87d2267 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -47,8 +47,7 @@ const char *LUA_GetActionName(void *action); void LUA_SetActionByName(void *state, const char *actiontocompare); #endif -extern boolean deh_loaded, modcredits; -extern char modcreditname[32]; +extern boolean deh_loaded; #define MAXRECURSION 30 extern const char *superactions[MAXRECURSION]; diff --git a/src/doomdef.h b/src/doomdef.h index b38bb507..93503de3 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -144,8 +144,8 @@ extern FILE *logstream; #define VERSIONSTRING "Trunk" #else #define VERSION 201 // Game version -#define SUBVERSION 6 // more precise version number -#define VERSIONSTRING "v2.1.6" +#define SUBVERSION 7 // more precise version number +#define VERSIONSTRING "v2.1.7" #endif // Modification options @@ -201,7 +201,7 @@ extern FILE *logstream; // it's only for detection of the version the player is using so the MS can alert them of an update. // Only set it higher, not lower, obviously. // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". -#define MODVERSION 11 +#define MODVERSION 12 @@ -259,6 +259,13 @@ typedef enum SKINCOLOR_SUPER4, SKINCOLOR_SUPER5, + // Super Tails + SKINCOLOR_TSUPER1, + SKINCOLOR_TSUPER2, + SKINCOLOR_TSUPER3, + SKINCOLOR_TSUPER4, + SKINCOLOR_TSUPER5, + // Super Knuckles SKINCOLOR_KSUPER1, SKINCOLOR_KSUPER2, diff --git a/src/f_finale.c b/src/f_finale.c index 4b743238..0b40eecd 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -991,7 +991,7 @@ static const char *credits[] = { "\1Texture Artists", "Ryan \"Blaze Hedgehog\" Bloom", "Buddy \"KinkaJoy\" Fischer", - "Pedro \"Nev3r\" Iceta", + "Kepa \"Nev3r\" Iceta", "Jarrett \"JEV3\" Voight", "", "\1Music and Sound", @@ -1002,7 +1002,7 @@ static const char *credits[] = { "David \"Bulmybag\" Bulmer", "Paul \"Boinciel\" Clempson", "Cyan Helkaraxe", - "Pedro \"Nev3r\" Iceta", + "Kepa \"Nev3r\" Iceta", "\"Monster\" Iestyn Jealous", "Jarel \"Arrow\" Jones", "Stefan \"Stuf\" Rimalia", @@ -1020,7 +1020,7 @@ static const char *credits[] = { "Ben \"Mystic\" Geyer", "Nathan \"Jazz\" Giroux", "Dan \"Blitzzo\" Hagerstrand", - "Pedro \"Nev3r\" Iceta", + "Kepa \"Nev3r\" Iceta", "Thomas \"Shadow Hog\" Igoe", "Erik \"Torgo\" Nielsen", "Wessel \"Spherallic\" Smit", @@ -1046,7 +1046,9 @@ static const char *credits[] = { "Alex \"MistaED\" Fuller", "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "Randy Heit ()", // For his MSPaint sprite that we nicked +#if 0 // (don't take your anger out on me anymore, ok, JTE...?) "Abigail \"Raspberry\" Fox", // (Inuyasha's girlfriend. >_> <_< >_>) +#endif "", "\1Thank you", "\1for playing!", diff --git a/src/g_game.c b/src/g_game.c index 414f27d0..3d42f9b8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -234,13 +234,16 @@ static UINT8 *demobuffer = NULL; static UINT8 *demo_p, *demotime_p; static UINT8 *demoend; static UINT8 demoflags; +static UINT16 demoversion; boolean singledemo; // quit after playing a demo from cmdline boolean demo_start; // don't start playing demo right away +static boolean demosynced = true; // console warning message boolean metalrecording; // recording as metal sonic mobj_t *metalplayback; static UINT8 *metalbuffer = NULL; static UINT8 *metal_p; +static UINT16 metalversion; boolean metal_start; // extra data stuff (events registered this frame while recording) @@ -262,7 +265,8 @@ static struct { // There is no conflict here. typedef struct demoghost { UINT8 checksum[16]; - UINT8 *buffer, *p; + UINT8 *buffer, *p, color; + UINT16 version; mobj_t oldmo, *mo; struct demoghost *next; } demoghost; @@ -3577,7 +3581,7 @@ char *G_BuildMapTitle(INT32 mapnum) // DEMO RECORDING // -#define DEMOVERSION 0x0008 +#define DEMOVERSION 0x0009 #define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -3608,6 +3612,8 @@ static ticcmd_t oldcmd; // GZT_EXTRA flags #define EZT_THOK 0x01 // Spawned a thok object #define EZT_SPIN 0x02 // Because one type of thok object apparently wasn't enough +#define EZT_REV 0x03 // And two types wasn't enough either yet +#define EZT_THOKMASK 0x03 #define EZT_COLOR 0x04 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.) #define EZT_FLIP 0x08 // Reversed gravity #define EZT_SCALE 0x10 // Changed size @@ -3725,14 +3731,21 @@ void G_GhostAddThok(void) { if (!demorecording || !(demoflags & DF_GHOST)) return; - ghostext.flags |= EZT_THOK; + ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_THOK; } void G_GhostAddSpin(void) { if (!demorecording || !(demoflags & DF_GHOST)) return; - ghostext.flags |= EZT_SPIN; + ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_SPIN; +} + +void G_GhostAddRev(void) +{ + if (!demorecording || !(demoflags & DF_GHOST)) + return; + ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_REV; } void G_GhostAddFlip(void) @@ -3928,9 +3941,6 @@ void G_WriteGhostTic(mobj_t *ghost) } } -// console warning messages -UINT8 demosynced = true; - // Uses ghost data to do consistency checks on your position. // This fixes desynchronising demos when fighting eggman. void G_ConsGhostTic(void) @@ -4017,12 +4027,12 @@ void G_ConsGhostTic(void) } // Re-synchronise - px = (players[0].mo->x>>8)&UINT16_MAX; - py = (players[0].mo->y>>8)&UINT16_MAX; - pz = (players[0].mo->z>>8)&UINT16_MAX; - gx = (oldghost.x>>8)&UINT16_MAX; - gy = (oldghost.y>>8)&UINT16_MAX; - gz = (oldghost.z>>8)&UINT16_MAX; + px = players[0].mo->x>>FRACBITS; + py = players[0].mo->y>>FRACBITS; + pz = players[0].mo->z>>FRACBITS; + gx = oldghost.x>>FRACBITS; + gy = oldghost.y>>FRACBITS; + gz = oldghost.z>>FRACBITS; if (px != gx || py != gy || pz != gz) { @@ -4036,8 +4046,6 @@ void G_ConsGhostTic(void) P_SetThingPosition(players[0].mo); players[0].mo->z = oldghost.z; } - else - demosynced = true; if (*demo_p == DEMOMARKER) { @@ -4105,17 +4113,16 @@ void G_GhostTicker(void) ziptic = READUINT8(g->p); if (ziptic & EZT_COLOR) { - switch(READUINT8(g->p)) + g->color = READUINT8(g->p); + switch(g->color) { default: case GHC_NORMAL: // Go back to skin color g->mo->color = g->oldmo.color; break; - case GHC_SUPER: // Super Sonic - g->mo->color = SKINCOLOR_SUPER4; - break; - case GHC_INVINCIBLE: /// \todo Mario invincibility - g->mo->color = SKINCOLOR_SUPER4; + // Handled below + case GHC_SUPER: + case GHC_INVINCIBLE: break; case GHC_FIREFLOWER: // Fireflower g->mo->color = SKINCOLOR_WHITE; @@ -4130,17 +4137,25 @@ void G_GhostTicker(void) if (g->mo->destscale != g->mo->scale) P_SetScale(g->mo, g->mo->destscale); } - if (ziptic & (EZT_THOK|EZT_SPIN)) + if (ziptic & EZT_THOKMASK) { // Let's only spawn ONE of these per frame, thanks. mobj_t *mobj; INT32 type = -1; if (g->mo->skin) { skin_t *skin = (skin_t *)g->mo->skin; - if (ziptic & EZT_THOK) + switch (ziptic & EZT_THOKMASK) + { + case EZT_THOK: type = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; - else + break; + case EZT_SPIN: type = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; + break; + case EZT_REV: + type = skin->revitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; + break; + } } if (type == MT_GHOST) { @@ -4201,6 +4216,32 @@ void G_GhostTicker(void) g->mo->sprite = READUINT8(g->p); } + // Tick ghost colors (Super and Mario Invincibility flashing) + switch(g->color) + { + case GHC_SUPER: // Super Sonic (P_DoSuperStuff) + // Yousa yellow now! + g->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5; + if (g->mo->skin) + switch (((skin_t*)g->mo->skin)-skins) + { + case 1: // Golden orange supertails. + g->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5; + break; + case 2: // Pink superknux. + g->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5; + break; + default: + break; + } + break; + case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer) + g->mo->color = (UINT8)(leveltime % MAXSKINCOLORS); + break; + default: + break; + } + // Demo ends after ghost data. if (*g->p == DEMOMARKER) { @@ -4483,7 +4524,7 @@ void G_BeginRecording(void) // game data M_Memcpy(demo_p, "PLAY", 4); demo_p += 4; - WRITEUINT8(demo_p,gamemap); + WRITEINT16(demo_p,gamemap); M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; WRITEUINT8(demo_p,demoflags); @@ -4563,6 +4604,10 @@ void G_BeginRecording(void) oldghost.y = player->mo->y; oldghost.z = player->mo->z; oldghost.angle = player->mo->angle; + + // preticker started us gravity flipped + if (player->mo->eflags & MFE_VERTICALFLIP) + ghostext.flags |= EZT_FLIP; } } @@ -4613,7 +4658,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) UINT8 *buffer,*p; UINT8 flags; UINT32 oldtime, newtime, oldscore, newscore; - UINT16 oldrings, newrings; + UINT16 oldrings, newrings, oldversion; size_t bufsize ATTRUNUSED; UINT8 c; UINT16 s ATTRUNUSED; @@ -4636,7 +4681,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 16; // demo checksum I_Assert(!memcmp(p, "PLAY", 4)); p += 4; // PLAY - p++; // gamemap + p += 2; // gamemap p += 16; // map md5 flags = READUINT8(p); // demoflags I_Assert(flags & DF_RECORDATTACK); @@ -4664,8 +4709,15 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) } p += 12; // DEMOHEADER p++; // VERSION p++; // SUBVERSION - if (READUINT16(p) != DEMOVERSION) + oldversion = READUINT16(p); + switch(oldversion) // demoversion { + case DEMOVERSION: // latest always supported + // compatibility available? + case 0x0008: + break; + // too old, cannot support. + default: CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); Z_Free(buffer); return UINT8_MAX; @@ -4677,7 +4729,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) Z_Free(buffer); return UINT8_MAX; } p += 4; // "PLAY" - p++; // gamemap + if (oldversion <= 0x0008) + p++; // gamemap + else + p += 2; // gamemap p += 16; // mapmd5 flags = READUINT8(p); if (!(flags & DF_RECORDATTACK)) @@ -4783,9 +4838,16 @@ void G_DoPlayDemo(char *defdemoname) version = READUINT8(demo_p); subversion = READUINT8(demo_p); - if (DEMOVERSION != READUINT16(demo_p)) + demoversion = READUINT16(demo_p); + switch(demoversion) { - snprintf(msg, 1024, M_GetText("%s is a different replay format and cannot be played.\n"), pdemoname); + case DEMOVERSION: // latest always supported + // compatibility available? + case 0x0008: + break; + // too old, cannot support. + default: + snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); @@ -4807,7 +4869,10 @@ void G_DoPlayDemo(char *defdemoname) return; } demo_p += 4; // "PLAY" - gamemap = READUINT8(demo_p); + if (demoversion <= 0x0008) + gamemap = READUINT8(demo_p); + else + gamemap = READINT16(demo_p); demo_p += 16; // mapmd5 demoflags = READUINT8(demo_p); @@ -4950,7 +5015,7 @@ void G_AddGhost(char *defdemoname) UINT8 flags; UINT8 *buffer,*p; mapthing_t *mthing; - UINT16 count; + UINT16 count, ghostversion; name[16] = '\0'; skin[16] = '\0'; @@ -4996,9 +5061,16 @@ void G_AddGhost(char *defdemoname) } p += 12; // DEMOHEADER p++; // VERSION p++; // SUBVERSION - if (DEMOVERSION != READUINT16(p)) + ghostversion = READUINT16(p); + switch(ghostversion) { - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname); + case DEMOVERSION: // latest always supported + // compatibility available? + case 0x0008: + break; + // too old, cannot support. + default: + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); Z_Free(pdemoname); Z_Free(buffer); return; @@ -5019,7 +5091,10 @@ void G_AddGhost(char *defdemoname) Z_Free(buffer); return; } p += 4; // "PLAY" - p++; // gamemap + if (ghostversion <= 0x0008) + p++; // gamemap + else + p += 2; // gamemap p += 16; // mapmd5 (possibly check for consistency?) flags = READUINT8(p); if (!(flags & DF_GHOST)) @@ -5094,6 +5169,8 @@ void G_AddGhost(char *defdemoname) gh->p = p; ghosts = gh; + + gh->version = ghostversion; mthing = playerstarts[0]; I_Assert(mthing); { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. @@ -5124,20 +5201,24 @@ void G_AddGhost(char *defdemoname) gh->oldmo.z = gh->mo->z; // Set skin + gh->mo->skin = &skins[0]; for (i = 0; i < numskins; i++) if (!stricmp(skins[i].name,skin)) { gh->mo->skin = &skins[i]; break; } + gh->oldmo.skin = gh->mo->skin; // Set color + gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor; for (i = 0; i < MAXSKINCOLORS; i++) if (!stricmp(Color_Names[i],color)) { gh->mo->color = (UINT8)i; break; } + gh->oldmo.color = gh->mo->color; CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname); Z_Free(pdemoname); @@ -5199,9 +5280,16 @@ void G_DoPlayMetal(void) metal_p += 12; // DEMOHEADER metal_p++; // VERSION metal_p++; // SUBVERSION - if (DEMOVERSION != READUINT16(metal_p)) + metalversion = READUINT16(metal_p); + switch(metalversion) { - CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version mismatch.\n")); + case DEMOVERSION: // latest always supported + // compatibility available? + case 0x0008: + break; + // too old, cannot support. + default: + CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n")); Z_Free(metalbuffer); return; } diff --git a/src/g_game.h b/src/g_game.h index af37fc8a..03bbce60 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -137,6 +137,7 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_GhostAddThok(void); void G_GhostAddSpin(void); +void G_GhostAddRev(void); void G_GhostAddColor(ghostcolor_t color); void G_GhostAddFlip(void); void G_GhostAddScale(UINT16 scale); diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 47fab579..e2229ea9 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -183,34 +183,32 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, { v[0].x = v[3].x = (cx*sdupx-(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; v[2].x = v[1].x = (cx*sdupx+gpatch->leftoffset*pdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(cy*sdupy-gpatch->topoffset*pdupy)/vid.height; - v[2].y = v[3].y = 1-(cy*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; } else { v[0].x = v[3].x = (cx*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; v[2].x = v[1].x = (cx*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(cy*sdupy-gpatch->topoffset*pdupy)/vid.height; - v[2].y = v[3].y = 1-(cy*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; } + v[0].y = v[1].y = 1-(cy*sdupy-gpatch->topoffset*pdupy)/vid.height; + v[2].y = v[3].y = 1-(cy*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; + v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; if (option & V_FLIP) { v[0].sow = v[3].sow = gpatch->max_s; v[2].sow = v[1].sow = 0.0f; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = gpatch->max_t; } else { v[0].sow = v[3].sow = 0.0f; v[2].sow = v[1].sow = gpatch->max_s; - v[0].tow = v[1].tow = 0.0f; - v[2].tow = v[3].tow = gpatch->max_t; } + v[0].tow = v[1].tow = 0.0f; + v[2].tow = v[3].tow = gpatch->max_t; + flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest; if (option & V_WRAPX) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 8a2e3a6a..b968fee0 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -881,6 +881,9 @@ static void md2_loadTexture(md2_t *model) HWR_UnlockCachedPatch(grpatch); } +// Don't spam the console, or the OS with fopen requests! +static boolean nomd2s = false; + void HWR_InitMD2(void) { size_t i; @@ -906,12 +909,14 @@ void HWR_InitMD2(void) md2_models[i].skin = -1; md2_models[i].notfound = true; } - // read the md2.dat file + // read the md2.dat file f = fopen("md2.dat", "rt"); + if (!f) { CONS_Printf("%s", M_GetText("Error while loading md2.dat\n")); + nomd2s = true; return; } while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) @@ -966,14 +971,18 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup char name[18], filename[32]; float scale, offset; + if (nomd2s) + return; + CONS_Printf("AddPlayerMD2()...\n"); // read the md2.dat file - f = fopen("md2.dat", "rt"); + if (!f) { CONS_Printf("Error while loading md2.dat\n"); + nomd2s = true; return; } @@ -1009,13 +1018,16 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu char name[18], filename[32]; float scale, offset; - // Read the md2.dat file + if (nomd2s) + return; + // Read the md2.dat file f = fopen("md2.dat", "rt"); if (!f) { CONS_Printf("Error while loading md2.dat\n"); + nomd2s = true; return; } diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 1166f10f..0fb486ea 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -23,9 +23,9 @@ #include "hw_glob.h" -#define MD2_MAX_TRIANGLES 4096 -#define MD2_MAX_VERTICES 2048 -#define MD2_MAX_TEXCOORDS 2048 +#define MD2_MAX_TRIANGLES 8192 +#define MD2_MAX_VERTICES 4096 +#define MD2_MAX_TEXCOORDS 4096 #define MD2_MAX_FRAMES 512 #define MD2_MAX_SKINS 32 #define MD2_MAX_FRAMESIZE (MD2_MAX_VERTICES * 4 + 128) diff --git a/src/info.c b/src/info.c index d0ba598b..01c258e4 100644 --- a/src/info.c +++ b/src/info.c @@ -831,21 +831,23 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_CYBRAKDEMONELECTRICBARRIER_REVIVE3}, // S_CYBRAKDEMONELECTRICBARRIER_REVIVE2 {SPR_NULL, 0, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1 - {SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, sfx_s3k9d, 0, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1 - {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2 - {SPR_TARG, 1 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3 - {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4 - {SPR_TARG, 2 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5 - {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6 - {SPR_TARG, 3 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7 - {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8 - {SPR_TARG, 4 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9 - {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10 - {SPR_TARG, 5 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11 - {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12 - {SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13 + {SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1 + {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2 + {SPR_TARG, 1 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3 + {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4 + {SPR_TARG, 2 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5 + {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6 + {SPR_TARG, 3 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7 + {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8 + {SPR_TARG, 4 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9 + {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10 + {SPR_TARG, 5 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11 + {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12 + {SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13 {SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_Repeat}, 6, S_CYBRAKDEMONTARGETRETICULE2, S_NULL}, // S_CYBRAKDEMONTARGETRETICULE14 + {SPR_HOOP, 0 + FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONTARGETDOT + {SPR_NPLM, 0, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, {SPR_NPLM, 1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2, {SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3, @@ -4770,7 +4772,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_CYBRAKDEMON_TARGET_RETICULE + { // MT_CYBRAKDEMON_TARGET_RETICULE -1, // doomednum S_CYBRAKDEMONTARGETRETICULE1, // spawnstate 1000, // spawnhealth @@ -4797,6 +4799,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_CYBRAKDEMON_TARGET_DOT + -1, // doomednum + S_CYBRAKDEMONTARGETDOT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_BPLD1, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 10*FRACUNIT, // speed + 32*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_CYBRAKDEMON_NAPALM_BOMB_LARGE -1, // doomednum S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, // spawnstate @@ -10463,7 +10492,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // speed 64*FRACUNIT, // radius 64*FRACUNIT, // height - 0, // display offset + 2, // display offset 16, // mass 0, // damage sfx_None, // activesound @@ -13284,7 +13313,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // speed 32*FRACUNIT, // radius 32*FRACUNIT, // height - 1, // display offset + 2, // display offset 16, // mass 0, // damage sfx_None, // activesound diff --git a/src/info.h b/src/info.h index 63fe1a63..bc9b7f8f 100644 --- a/src/info.h +++ b/src/info.h @@ -1353,6 +1353,8 @@ typedef enum state S_CYBRAKDEMONTARGETRETICULE13, S_CYBRAKDEMONTARGETRETICULE14, + S_CYBRAKDEMONTARGETDOT, + S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3, @@ -3567,6 +3569,7 @@ typedef enum mobj_type MT_CYBRAKDEMON_FLAMESHOT, MT_CYBRAKDEMON_FLAMEREST, MT_CYBRAKDEMON_TARGET_RETICULE, + MT_CYBRAKDEMON_TARGET_DOT, MT_CYBRAKDEMON_NAPALM_BOMB_LARGE, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL, MT_CYBRAKDEMON_NAPALM_FLAMES, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index ece3d429..ac801cdd 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -16,6 +16,7 @@ #include "p_setup.h" // So we can have P_SetupLevelSky #include "z_zone.h" #include "r_main.h" +#include "r_things.h" #include "m_random.h" #include "s_sound.h" #include "g_game.h" @@ -724,6 +725,27 @@ static int lib_pHomingAttack(lua_State *L) return 0; } +static int lib_pSuperReady(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + //HUDSAFE + if (!player) + return LUA_ErrInvalid(L, "player_t"); + lua_pushboolean(L, P_SuperReady(player)); + return 1; +} + +static int lib_pDoJump(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + boolean soundandstate = (boolean)lua_opttrueboolean(L, 2); + NOHUD + if (!player) + return LUA_ErrInvalid(L, "player_t"); + P_DoJump(player, soundandstate); + return 0; +} + // P_MAP /////////// @@ -1309,6 +1331,31 @@ static int lib_rPointInSubsector(lua_State *L) return 1; } +// R_THINGS +//////////// + +static int lib_rChar2Frame(lua_State *L) +{ + const char *p = luaL_checkstring(L, 1); + //HUDSAFE + lua_pushinteger(L, R_Char2Frame(*p)); // first character only + return 1; +} + +static int lib_rFrame2Char(lua_State *L) +{ + UINT8 ch = (UINT8)luaL_checkinteger(L, 1); + char c[2] = ""; + //HUDSAFE + + c[0] = R_Frame2Char(ch); + c[1] = 0; + + lua_pushstring(L, c); + lua_pushinteger(L, c[0]); + return 2; +} + // S_SOUND //////////// @@ -1593,6 +1640,8 @@ static luaL_Reg lib[] = { {"P_LookForEnemies",lib_pLookForEnemies}, {"P_NukeEnemies",lib_pNukeEnemies}, {"P_HomingAttack",lib_pHomingAttack}, + {"P_SuperReady",lib_pSuperReady}, + {"P_DoJump",lib_pDoJump}, // p_map {"P_CheckPosition",lib_pCheckPosition}, @@ -1645,6 +1694,10 @@ static luaL_Reg lib[] = { {"R_PointToDist2",lib_rPointToDist2}, {"R_PointInSubsector",lib_rPointInSubsector}, + // r_things (sprite) + {"R_Char2Frame",lib_rChar2Frame}, + {"R_Frame2Char",lib_rFrame2Char}, + // s_sound {"S_StartSound",lib_sStartSound}, {"S_StartSoundAtVolume",lib_sStartSoundAtVolume}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index d153020f..6f185c69 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -79,7 +79,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum) } // Wrapper for COM_AddCommand commands -static void COM_Lua_f(void) +void COM_Lua_f(void) { char *buf, *p; UINT8 i, flags; @@ -90,9 +90,13 @@ static void COM_Lua_f(void) lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command I_Assert(lua_istable(gL, -1)); - lua_getfield(gL, -1, COM_Argv(0)); // push command info table + // use buf temporarily -- must use lowercased string + buf = Z_StrDup(COM_Argv(0)); + strlwr(buf); + lua_getfield(gL, -1, buf); // push command info table I_Assert(lua_istable(gL, -1)); lua_remove(gL, -2); // pop COM_Command + Z_Free(buf); lua_rawgeti(gL, -1, 2); // push flags from command info table if (lua_isboolean(gL, -1)) @@ -158,8 +162,13 @@ static void COM_Lua_f(void) // Wrapper for COM_AddCommand static int lib_comAddCommand(lua_State *L) { - boolean exists = false; - const char *name = luaL_checkstring(L, 1); + int com_return = -1; + const char *luaname = luaL_checkstring(L, 1); + + // must store in all lowercase + char *name = Z_StrDup(luaname); + strlwr(name); + luaL_checktype(L, 2, LUA_TFUNCTION); NOHUD if (lua_gettop(L) >= 3) @@ -177,11 +186,6 @@ static int lib_comAddCommand(lua_State *L) lua_getfield(L, LUA_REGISTRYINDEX, "COM_Command"); I_Assert(lua_istable(L, -1)); - lua_getfield(L, -1, name); - if (!lua_isnil(L, -1)) - exists = true; - lua_pop(L, 1); - lua_createtable(L, 2, 0); lua_pushvalue(L, 2); lua_rawseti(L, -2, 1); @@ -190,14 +194,23 @@ static int lib_comAddCommand(lua_State *L) lua_rawseti(L, -2, 2); lua_setfield(L, -2, name); - // This makes it only add a new command if another - // Lua command by the same name doesn't already exist. - // - // UNFORTUNATELY COM_AddCommand will still cause I_Errors - // if you attempt to override an existing hardcoded command. - // - if (!exists) - COM_AddCommand(name, COM_Lua_f); + // Try to add the Lua command + com_return = COM_AddLuaCommand(name); + + if (com_return < 0) + { // failed to add -- free the lowercased name and return error + Z_Free(name); + return luaL_error(L, "Couldn't add a new console command \"%s\"", luaname); + } + else if (com_return == 1) + { // command existed already -- free our name as the old string will continue to be used + CONS_Printf("Replaced command \"%s\"\n", name); + Z_Free(name); + } + else + { // new command was added -- do NOT free the string as it will forever be used by the console + CONS_Printf("Added command \"%s\"\n", name); + } return 0; } diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 1b4bf1dd..8bd1b49e 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -23,6 +23,8 @@ #include "lua_hook.h" #include "lua_hud.h" // hud_running errors +static UINT8 hooksAvailable[(hook_MAX/8)+1]; + const char *const hookNames[hook_MAX+1] = { "NetVars", "MapChange", @@ -183,6 +185,9 @@ static int lib_addHook(lua_State *L) if (subfield) Z_Free(subfield); + + + hooksAvailable[hook/8] |= 1<<(hook%8); return 0; } @@ -190,6 +195,8 @@ int LUA_HookLib(lua_State *L) { // Create all registry tables enum hook i; + memset(hooksAvailable,0,sizeof(UINT8[(hook_MAX/8)+1])); + lua_newtable(L); for (i = 0; i < hook_MAX; i++) { @@ -225,7 +232,7 @@ int LUA_HookLib(lua_State *L) boolean LUAh_MobjHook(mobj_t *mo, enum hook which) { boolean hooked = false; - if (!gL) + if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) return false; // clear the stack (just in case) @@ -315,7 +322,7 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) // Hook for map change (before load) void LUAh_MapChange(void) { - if (!gL) + if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8)))) return; lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); @@ -337,7 +344,7 @@ void LUAh_MapChange(void) // Hook for map load void LUAh_MapLoad(void) { - if (!gL) + if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8)))) return; lua_pop(gL, -1); @@ -361,7 +368,7 @@ void LUAh_MapLoad(void) // Hook for Got_AddPlayer void LUAh_PlayerJoin(int playernum) { - if (!gL) + if (!gL || !(hooksAvailable[hook_PlayerJoin/8] & (1<<(hook_PlayerJoin%8)))) return; lua_pop(gL, -1); @@ -385,7 +392,7 @@ void LUAh_PlayerJoin(int playernum) // Hook for frame (after mobj and player thinkers) void LUAh_ThinkFrame(void) { - if (!gL) + if (!gL || !(hooksAvailable[hook_ThinkFrame/8] & (1<<(hook_ThinkFrame%8)))) return; lua_pop(gL, -1); @@ -420,7 +427,7 @@ void LUAh_ThinkFrame(void) UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2) { UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL) + if (!gL || !(hooksAvailable[hook_MobjCollide/8] & (1<<(hook_MobjCollide%8)))) return 0; // clear the stack @@ -471,7 +478,7 @@ UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2) UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2) { UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL) + if (!gL || !(hooksAvailable[hook_MobjMoveCollide/8] & (1<<(hook_MobjMoveCollide%8)))) return 0; // clear the stack @@ -522,7 +529,7 @@ UINT8 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2) boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) { boolean hooked = false; - if (!gL) + if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8)))) return false; // clear the stack @@ -551,8 +558,14 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) while (lua_next(gL, 1) != 0) { lua_pushvalue(gL, 2); // special lua_pushvalue(gL, 3); // toucher - LUA_Call(gL, 2); // pops hook function, special, toucher - hooked = true; + if (lua_pcall(gL, 2, 1, 0)) { // pops hook function, special, toucher, pushes 1 return result + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + lua_pop(gL, 1); + continue; + } + if (lua_toboolean(gL, -1)) // if return true, + hooked = true; // override vanilla behavior + lua_pop(gL, 1); // pop return value } lua_pop(gL, -1); @@ -564,7 +577,7 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL) + if (!gL || !(hooksAvailable[hook_ShouldDamage/8] & (1<<(hook_ShouldDamage%8)))) return 0; // clear the stack @@ -619,7 +632,7 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage) { boolean handled = false; - if (!gL) + if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8)))) return false; // clear the stack @@ -669,7 +682,7 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source) { boolean handled = false; - if (!gL) + if (!gL || !(hooksAvailable[hook_MobjDeath/8] & (1<<(hook_MobjDeath%8)))) return false; // clear the stack @@ -717,7 +730,7 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source) boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) { boolean hooked = false; - if (!gL) + if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8)))) return false; // clear the stack @@ -737,8 +750,14 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) while (lua_next(gL, 1)) { lua_pushvalue(gL, 2); // bot lua_pushvalue(gL, 3); // cmd - LUA_Call(gL, 2); - hooked = true; + if (lua_pcall(gL, 2, 1, 0)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + lua_pop(gL, 1); + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); // pop return value } lua_pop(gL, -1); @@ -749,7 +768,7 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) // Hook for B_BuildTailsTiccmd by skin name boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) { - if (!gL || !tails->skin) + if (!gL || !tails->skin || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) return false; // clear the stack @@ -813,7 +832,7 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) // Hook for linedef executors boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo) { - if (!gL) + if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8)))) return false; // clear the stack diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 98f0ba37..176b816e 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -26,6 +26,8 @@ boolean hud_running = false; static UINT8 hud_enabled[(hud_MAX/8)+1]; +static UINT8 hudAvailable; // hud hooks field + // must match enum hud in lua_hud.h static const char *const hud_disable_options[] = { "stagetitle", @@ -399,6 +401,8 @@ static int lib_hudadd(lua_State *L) lua_pushvalue(L, 1); lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1)); + + hudAvailable |= 1< end'."); + lua_settop(L, 2); lua_remove(L, 1); // state is unused. if (!lua_isnil(L, 1)) i = (size_t)(*((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)) - mapthings) + 1; diff --git a/src/lua_script.h b/src/lua_script.h index 343f873d..eaef13d1 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -43,6 +43,9 @@ void LUA_CVarChanged(const char *name); // lua_consolelib.c int Lua_optoption(lua_State *L, int narg, const char *def, const char *const lst[]); +// Console wrapper +void COM_Lua_f(void); + #define LUA_Call(L,a)\ {\ if (lua_pcall(L, a, 0, 0)) {\ diff --git a/src/m_anigif.c b/src/m_anigif.c index fb2eb8f4..c5efe876 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -22,7 +22,7 @@ // GIFs are always little-endian #include "byteptr.h" -consvar_t cv_gif_optimize = {"gif_optimize", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_gif_optimize = {"gif_optimize", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_gif_downscale = {"gif_downscale", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; #ifdef HAVE_ANIGIF @@ -357,7 +357,7 @@ static void GIF_lzw(void) if (gifbwr_bufsize >= 250) break; } - if (scrbuf_pos >= scrbuf_writeend) + if (scrbuf_pos > scrbuf_writeend) { GIF_bwrwrite(giflzw_workingCode); GIF_bwrwrite(GIFLZW_DATAEND); diff --git a/src/m_menu.c b/src/m_menu.c index 30876cbc..887ac5fc 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -365,7 +365,7 @@ static CV_PossibleValue_t map_cons_t[] = { {1,"MIN"}, {NUMMAPS, "MAX"} }; -consvar_t cv_nextmap = {"nextmap", "MAP01", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_nextmap = {"nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}}; consvar_t cv_chooseskin = {"chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -2338,8 +2338,8 @@ void M_Drawer(void) { if (customversionstring[0] != '\0') { - V_DrawThinString(vid.dupx, BASEVIDHEIGHT - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:"); - V_DrawThinString(vid.dupx, BASEVIDHEIGHT - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring); + V_DrawThinString(vid.dupx, vid.height - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:"); + V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring); } else #if VERSION > 0 || SUBVERSION > 0 diff --git a/src/p_enemy.c b/src/p_enemy.c index 560b7d34..e20e3a5c 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2600,70 +2600,26 @@ void A_MonitorPop(mobj_t *actor) { case MT_QUESTIONBOX: // Random! { - mobjtype_t spawnchance[128]; - SINT8 numchoices = 0; - SINT8 target = 0; + mobjtype_t spawnchance[256]; + INT32 numchoices = 0, i = 0; - if (cv_superring.value) - { - for (target += (SINT8)cv_superring.value; numchoices < target;) - spawnchance[numchoices++] = MT_SUPERRINGBOX; - } - if (cv_supersneakers.value) - { - for (target += (SINT8)cv_supersneakers.value; numchoices < target;) - spawnchance[numchoices++] = MT_SNEAKERTV; - } - if (cv_invincibility.value) - { - for (target += (SINT8)cv_invincibility.value; numchoices < target;) - spawnchance[numchoices++] = MT_INV; - } - if (cv_jumpshield.value) - { - for (target += (SINT8)cv_jumpshield.value; numchoices < target;) - spawnchance[numchoices++] = MT_WHITETV; - } - if (cv_watershield.value) - { - for (target += (SINT8)cv_watershield.value; numchoices < target;) - spawnchance[numchoices++] = MT_GREENTV; - } - if (cv_ringshield.value) - { - for (target += (SINT8)cv_ringshield.value; numchoices < target;) - spawnchance[numchoices++] = MT_YELLOWTV; - } - if (cv_forceshield.value) - { - for (target += (SINT8)cv_forceshield.value; numchoices < target;) - spawnchance[numchoices++] = MT_BLUETV; - } - if (cv_bombshield.value) - { - for (target += (SINT8)cv_bombshield.value; numchoices < target;) - spawnchance[numchoices++] = MT_BLACKTV; - } - if (cv_1up.value) - { - for (target += (SINT8)cv_1up.value; numchoices < target;) - spawnchance[numchoices++] = MT_PRUP; - } - if (cv_eggmanbox.value) - { - for (target += (SINT8)cv_eggmanbox.value; numchoices < target;) - spawnchance[numchoices++] = MT_EGGMANBOX; - } - if (cv_teleporters.value) - { - for (target += (SINT8)cv_teleporters.value; numchoices < target;) - spawnchance[numchoices++] = MT_MIXUPBOX; - } - if (cv_recycler.value) - { - for (target += (SINT8)cv_recycler.value; numchoices < target;) - spawnchance[numchoices++] = MT_RECYCLETV; - } +#define QUESTIONBOXCHANCES(type, cvar) \ +for (i = cvar.value; i; --i) spawnchance[numchoices++] = type + + QUESTIONBOXCHANCES(MT_SUPERRINGBOX, cv_superring); + QUESTIONBOXCHANCES(MT_SNEAKERTV, cv_supersneakers); + QUESTIONBOXCHANCES(MT_INV, cv_invincibility); + QUESTIONBOXCHANCES(MT_WHITETV, cv_jumpshield); + QUESTIONBOXCHANCES(MT_GREENTV, cv_watershield); + QUESTIONBOXCHANCES(MT_YELLOWTV, cv_ringshield); + QUESTIONBOXCHANCES(MT_BLUETV, cv_forceshield); + QUESTIONBOXCHANCES(MT_BLACKTV, cv_bombshield); + QUESTIONBOXCHANCES(MT_PRUP, cv_1up); + QUESTIONBOXCHANCES(MT_EGGMANBOX, cv_eggmanbox); + QUESTIONBOXCHANCES(MT_MIXUPBOX, cv_teleporters); + QUESTIONBOXCHANCES(MT_RECYCLETV, cv_recycler); + +#undef QUESTIONBOXCHANCES if (numchoices == 0) { @@ -3020,7 +2976,7 @@ void A_JumpShield(mobj_t *actor) if ((player->powers[pw_shield] & SH_NOSTACK) != SH_JUMP) { - player->powers[pw_shield] = SH_JUMP+(player->powers[pw_shield] & SH_STACK); + player->powers[pw_shield] = SH_JUMP|(player->powers[pw_shield] & SH_STACK); P_SpawnShieldOrb(player); } @@ -3052,7 +3008,7 @@ void A_RingShield(mobj_t *actor) if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT) { - player->powers[pw_shield] = SH_ATTRACT+(player->powers[pw_shield] & SH_STACK); + player->powers[pw_shield] = SH_ATTRACT|(player->powers[pw_shield] & SH_STACK); P_SpawnShieldOrb(player); } @@ -3149,7 +3105,7 @@ void A_SuperSneakers(mobj_t *actor) actor->target->player->powers[pw_sneakers] = sneakertics + 1; - if (P_IsLocalPlayer(player) && (!player->powers[pw_super])) + if (P_IsLocalPlayer(player) && !player->powers[pw_super]) { if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)) S_SpeedMusic(1.4f); @@ -3254,7 +3210,7 @@ void A_BombShield(mobj_t *actor) if ((player->powers[pw_shield] & SH_NOSTACK) != SH_BOMB) { - player->powers[pw_shield] = SH_BOMB+(player->powers[pw_shield] & SH_STACK); + player->powers[pw_shield] = SH_BOMB|(player->powers[pw_shield] & SH_STACK); P_SpawnShieldOrb(player); } @@ -3286,7 +3242,7 @@ void A_WaterShield(mobj_t *actor) if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL) { - player->powers[pw_shield] = SH_ELEMENTAL+(player->powers[pw_shield] & SH_FIREFLOWER); + player->powers[pw_shield] = SH_ELEMENTAL|(player->powers[pw_shield] & SH_STACK); P_SpawnShieldOrb(player); } @@ -9847,14 +9803,18 @@ void A_VileAttack(mobj_t *actor) // Function: A_VileFire // // Description: Kind of like A_CapeChase; keeps this object in front of its tracer, unless its target can't see it. -// Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific). +// Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific). +// Added some functionality to optionally draw a line directly to the enemy doing the targetting. Y'know, to hammer things in a bit. // // var1 = sound to play -// var2 = unused +// var2: +// Lower 16 bits = mobj to spawn (0 doesn't spawn a line at all) +// Upper 16 bits = # to spawn (default is 8) // void A_VileFire(mobj_t *actor) { INT32 locvar1 = var1; + INT32 locvar2 = var2; mobj_t *dest; #ifdef HAVE_BLUA @@ -9870,10 +9830,10 @@ void A_VileFire(mobj_t *actor) if (!P_CheckSight(actor->target, dest)) return; - // keep to same scale and gravity as target ALWAYS - actor->destscale = actor->target->scale; + // keep to same scale and gravity as tracer ALWAYS + actor->destscale = dest->scale; P_SetScale(actor, actor->destscale); - if (actor->target->eflags & MFE_VERTICALFLIP) + if (dest->eflags & MFE_VERTICALFLIP) { actor->eflags |= MFE_VERTICALFLIP; actor->flags2 |= MF2_OBJECTFLIP; @@ -9893,6 +9853,33 @@ void A_VileFire(mobj_t *actor) // Play sound, if one's specified if (locvar1 > 0 && locvar1 < NUMSFX) S_StartSound(actor, (sfxenum_t)locvar1); + + // Now draw the line to the actor's target + if (locvar2 & 0xFFFF) + { + mobjtype_t lineMobj; + UINT16 numLineMobjs; + fixed_t distX; + fixed_t distY; + fixed_t distZ; + UINT16 i; + + lineMobj = (mobjtype_t)(locvar2 & 0xFFFF); + numLineMobjs = (UINT16)(locvar2 >> 16); + if (numLineMobjs == 0) { + numLineMobjs = 8; + } + + // Get distance for each step + distX = (actor->target->x - actor->x) / numLineMobjs; + distY = (actor->target->y - actor->y) / numLineMobjs; + distZ = ((actor->target->z + FixedMul(actor->target->height/2, actor->target->scale)) - (actor->z + FixedMul(actor->height/2, actor->scale))) / numLineMobjs; + + for (i = 1; i <= numLineMobjs; i++) + { + P_SpawnMobj(actor->x + (distX * i), actor->y + (distY * i), actor->z + (distZ * i) + FixedMul(actor->height/2, actor->scale), lineMobj); + } + } } // Function: A_BrakChase diff --git a/src/p_fab.c b/src/p_fab.c index 134e2c39..77abcccc 100644 --- a/src/p_fab.c +++ b/src/p_fab.c @@ -91,6 +91,7 @@ static void P_SetTranslucencies(void) R_SetTrans(S_CYBRAKDEMONFLAMESHOT_FLY1, S_CYBRAKDEMONFLAMESHOT_DIE, tr_trans50); // Flame R_SetTrans(S_CYBRAKDEMONFLAMEREST, 0, tr_trans50); // Flame R_SetTrans(S_CYBRAKDEMONTARGETRETICULE1, S_CYBRAKDEMONTARGETRETICULE14, tr_trans50); // Target + R_SetTrans(S_CYBRAKDEMONTARGETDOT, S_CYBRAKDEMONTARGETDOT, tr_trans50); // Target R_SetTrans(S_FOG1, S_FOG14, tr_trans50); diff --git a/src/p_inter.c b/src/p_inter.c index 75a72834..149c16b0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2404,6 +2404,8 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou { if (!(inflictor->flags & MF_FIRE)) P_GivePlayerRings(player, 1); + if (inflictor->flags2 & MF2_BOUNCERING) + inflictor->fuse = 1; return false; } @@ -2489,6 +2491,8 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj { if (!(inflictor->flags & MF_FIRE)) P_GivePlayerRings(target->player, 1); + if (inflictor->flags2 & MF2_BOUNCERING) + inflictor->fuse = 1; return false; } @@ -2636,7 +2640,10 @@ void P_RemoveShield(player_t *player) player->powers[pw_shield] = SH_NONE; // Reset fireflower if (!player->powers[pw_super]) + { player->mo->color = player->skincolor; + G_GhostAddColor(GHC_NORMAL); + } } else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) // Give them what's coming to them! { diff --git a/src/p_mobj.c b/src/p_mobj.c index dd45e3fe..98e0c9f8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6565,179 +6565,27 @@ void P_MobjThinker(mobj_t *mobj) if ((mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) { mobjtype_t spawnchance[64]; - INT32 i = 0; - INT32 oldi = 0; - INT32 increment = 0; - INT32 numchoices = 0; + INT32 numchoices = 0, i = 0; - //if (cv_superring.value) - { - oldi = i; +// This define should make it a lot easier to organize and change monitor weights +#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ +for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 0; - else //weak box - increment = 0; + // Type SRM WRM + SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers + SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility + SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield + SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield + SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield + SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield + SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield + SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters + SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler + SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up + // ====================================== + // Total 16 32 - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_SUPERRINGBOX; - numchoices++; - } - } - //if (cv_supersneakers.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 0; - else //weak box - increment = 10; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_SNEAKERTV; - numchoices++; - } - } - //if (cv_invincibility.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 4; - else //weak box - increment = 0; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_INV; - numchoices++; - } - } - //if (cv_jumpshield.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 6; - else //weak box - increment = 8; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_WHITETV; - numchoices++; - } - } - //if (cv_watershield.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 6; - else //weak box - increment = 8; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_GREENTV; - numchoices++; - } - } - //if (cv_ringshield.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 4; - else //weak box - increment = 0; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_YELLOWTV; - numchoices++; - } - } - //if (cv_forceshield.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 6; - else //weak box - increment = 3; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_BLUETV; - numchoices++; - } - } - //if (cv_bombshield.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 4; - else //weak box - increment = 0; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_BLACKTV; - numchoices++; - } - } - - //if (cv_teleporters.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 0; - else //weak box - increment = 1; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_MIXUPBOX; - numchoices++; - } - } - - //if (cv_recycler.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 0; - else //weak box - increment = 1; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_RECYCLETV; - numchoices++; - } - } - - //if (cv_1up.value) - { - oldi = i; - - if (mobj->flags2 & MF2_STRONGBOX) //strong box - increment = 2; - else //weak box - increment = 1; - - for (; i < oldi + increment; i++) - { - spawnchance[i] = MT_PRUP; - numchoices++; - } - } +#undef SETMONITORCHANCES i = P_RandomKey(numchoices); // Gotta love those random numbers! newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); @@ -8342,9 +8190,14 @@ void P_SpawnMapThing(mapthing_t *mthing) } } - if (ultimatemode && !G_IsSpecialStage(gamemap) - && (i == MT_SUPERRINGBOX || i == MT_GREENTV || i == MT_YELLOWTV || i == MT_BLUETV || i == MT_BLACKTV || i == MT_WHITETV)) - return; // No rings/shields in Ultimate mode + if (ultimatemode) + { + if (i == MT_PITYTV || i == MT_GREENTV || i == MT_YELLOWTV || i == MT_BLUETV || i == MT_BLACKTV || i == MT_WHITETV) + return; // No shields in Ultimate mode + + if (i == MT_SUPERRINGBOX && !G_IsSpecialStage(gamemap)) + return; // No rings in Ultimate mode (except special stages) + } if (i == MT_EMMY && (gametype != GT_COOP || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++))) return; // you already got this token, or there are too many, or the gametype's not right @@ -8853,27 +8706,36 @@ ML_NOCLIMB : Direction not controllable mobj->flags2 |= MF2_STANDONME; } - if (mthing->type != mobjinfo[MT_AXIS].doomednum && + if (mobj->flags & MF_MONITOR) + { + // flag for strong/weak random boxes + if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum || + mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum || + mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum || + mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum || + mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum || + mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum) + mobj->flags |= MF_AMBUSH; + } + + else if (mthing->type != mobjinfo[MT_AXIS].doomednum && mthing->type != mobjinfo[MT_AXISTRANSFER].doomednum && mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum && mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum && - mthing->type != mobjinfo[MT_STARPOST].doomednum && - mthing->type != mobjinfo[MT_GRAVITYBOX].doomednum && - mthing->type != mobjinfo[MT_EGGMANBOX].doomednum) + mthing->type != mobjinfo[MT_STARPOST].doomednum) mobj->flags |= MF_AMBUSH; } if (mthing->options & MTF_OBJECTSPECIAL) { // flag for strong/weak random boxes - if (mthing->type == mobjinfo[MT_QUESTIONBOX].doomednum || mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || + if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum || mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum || mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum || mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum || - mthing->type == mobjinfo[MT_RECYCLETV].doomednum || - mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum || - mthing->type == mobjinfo[MT_PRUP].doomednum) - mobj->flags2 |= MF2_STRONGBOX; + mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum || + mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum) + mobj->flags2 |= MF2_STRONGBOX; // Requires you to be in bonus time to activate if (mobj->flags & MF_NIGHTSITEM) diff --git a/src/p_saveg.c b/src/p_saveg.c index baa04211..462e68af 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1336,7 +1336,7 @@ static void P_NetArchiveThinkers(void) if ((mobj->x != mobj->spawnpoint->x << FRACBITS) || (mobj->y != mobj->spawnpoint->y << FRACBITS) || - (mobj->angle != (angle_t)(ANGLE_45 * (mobj->spawnpoint->angle/45)))) + (mobj->angle != FixedAngle(mobj->spawnpoint->angle*FRACUNIT))) diff |= MD_POS; if (mobj->info->doomednum != mobj->spawnpoint->type) diff --git a/src/p_user.c b/src/p_user.c index 322f2cd1..8b793e81 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1135,8 +1135,16 @@ void P_RestoreMusic(player_t *player) S_ChangeMusic(mus_supers, true); else if (player->powers[pw_invulnerability] > 1) S_ChangeMusic((mariomode) ? mus_minvnc : mus_invinc, false); - else if (player->powers[pw_sneakers] > 1) - S_ChangeMusic(mus_shoes, true); + else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super]) + { + if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC) + { + S_SpeedMusic(1.4f); + S_ChangeMusic(mapmusic, true); + } + else + S_ChangeMusic(mus_shoes, true); + } else S_ChangeMusic(mapmusic, true); } @@ -1537,8 +1545,6 @@ static void P_SpawnSpinMobj(player_t *player, mobjtype_t type) } P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do - if (demorecording) - G_GhostAddSpin(); } // @@ -3207,10 +3213,18 @@ static void P_DoSuperStuff(player_t *player) player->mo->health--; } - if (player->skin == 2) // Pink superknux. + switch (player->skin) + { + case 1: // Golden orange supertails. + player->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5; + break; + case 2: // Pink superknux. player->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5; - else // Yousa yellow now! + break; + default: // Yousa yellow now! player->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5; + break; + } G_GhostAddColor(GHC_SUPER); // Ran out of rings while super! @@ -3485,6 +3499,8 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd) // Now spawn the color thok circle. P_SpawnSpinMobj(player, player->revitem); + if (demorecording) + G_GhostAddRev(); } } // If not moving up or down, and travelling faster than a speed of four while not holding @@ -4578,12 +4594,9 @@ static void P_3dMovement(player_t *player) { movepushside >>= 2; - //Lower speed if over "max" flight speed and greatly reduce movepushslide. + // Reduce movepushslide even more if over "max" flight speed if (player->powers[pw_tailsfly] && player->speed > topspeed) - { - player->speed = topspeed - 1; - movepushside /= 4; - } + movepushside >>= 2; } // Allow a bit of movement while spinning @@ -6525,6 +6538,10 @@ static void P_MovePlayer(player_t *player) if (player->pflags & PF_GLIDING) { fixed_t leeway; + fixed_t glidespeed = player->actionspd; + + if (player->powers[pw_super]) + glidespeed *= 2; if (player->mo->eflags & MFE_VERTICALFLIP) { @@ -6542,7 +6559,7 @@ static void P_MovePlayer(player_t *player) if (player->skidtime) // ground gliding { - fixed_t speed = FixedMul(player->actionspd, FRACUNIT - (FRACUNIT>>2)); + fixed_t speed = FixedMul(glidespeed, FRACUNIT - (FRACUNIT>>2)); if (player->mo->eflags & MFE_UNDERWATER) speed >>= 1; speed = FixedMul(speed - player->glidetime*FRACUNIT, player->mo->scale); @@ -6551,9 +6568,9 @@ static void P_MovePlayer(player_t *player) P_InstaThrust(player->mo, player->mo->angle-leeway, speed); } else if (player->mo->eflags & MFE_UNDERWATER) - P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul((player->actionspd>>1) + player->glidetime*750, player->mo->scale)); + P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul((glidespeed>>1) + player->glidetime*750, player->mo->scale)); else - P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul(player->actionspd + player->glidetime*1500, player->mo->scale)); + P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul(glidespeed + player->glidetime*1500, player->mo->scale)); player->glidetime++; @@ -6568,6 +6585,7 @@ static void P_MovePlayer(player_t *player) } else { + player->pflags |= PF_THOKKED; player->mo->momx >>= 1; player->mo->momy >>= 1; P_SetPlayerMobjState(player->mo, S_PLAY_FALL1); @@ -6744,7 +6762,11 @@ static void P_MovePlayer(player_t *player) // Show the "THOK!" graphic when spinning quickly across the ground. (even applies to non-spinners, in the case of zoom tubes) if (player->pflags & PF_SPINNING && player->speed > FixedMul(15<mo->scale) && !(player->pflags & PF_JUMPED)) + { P_SpawnSpinMobj(player, player->spinitem); + if (demorecording) + G_GhostAddSpin(); + } //////////////////////////// @@ -7481,11 +7503,8 @@ boolean P_LookForEnemies(player_t *player) continue; // not a mobj thinker mo = (mobj_t *)think; - if (!(mo->flags & MF_ENEMY || mo->flags & MF_BOSS || mo->flags & MF_MONITOR - || mo->flags & MF_SPRING)) - { + if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING))) continue; // not a valid enemy - } if (mo->health <= 0) // dead continue; @@ -7496,14 +7515,14 @@ boolean P_LookForEnemies(player_t *player) if (mo->flags2 & MF2_FRET) continue; - if ((mo->flags & MF_ENEMY || mo->flags & MF_BOSS) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus) + if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus) continue; if (mo->type == MT_DETON) // Don't be STUPID, Sonic! continue; if (((mo->z > player->mo->z+FixedMul(MAXSTEPMOVE, player->mo->scale)) && !(player->mo->eflags & MFE_VERTICALFLIP)) - || ((mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale)) && (player->mo->eflags & MFE_VERTICALFLIP))) // Reverse gravity check - Flame. + || ((mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale)) && (player->mo->eflags & MFE_VERTICALFLIP))) // Reverse gravity check - Flame. continue; // Don't home upwards! if (P_AproxDistance(P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y), @@ -7572,7 +7591,7 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target if (dist < 1) dist = 1; - if (source->type == MT_DETON && enemy->player) // For Deton Chase + if (source->type == MT_DETON && enemy->player) // For Deton Chase (Unused) { fixed_t ns = FixedDiv(FixedMul(enemy->player->normalspeed, enemy->scale), FixedDiv(20*FRACUNIT,17*FRACUNIT)); source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns); diff --git a/src/r_draw.c b/src/r_draw.c index 11dffb6b..cd219c15 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -376,10 +376,10 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U // Super colors, from lightest to darkest! case SKINCOLOR_SUPER1: // Super White - for (i = 0; i < 14; i++) + for (i = 0; i < 10; i++) dest_colormap[starttranscolor + i] = 120; // True white - for (; i < SKIN_RAMP_LENGTH; i++) - dest_colormap[starttranscolor + i] = 112; // Golden shine + for (; i < SKIN_RAMP_LENGTH; i++) // White-yellow fade + dest_colormap[starttranscolor + i] = (UINT8)(96 + (i-10)); break; case SKINCOLOR_SUPER2: @@ -422,6 +422,43 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U dest_colormap[starttranscolor + 15] = 155; break; + // Super Tails + case SKINCOLOR_TSUPER1: + for (i = 0; i < 10; i++) // white + dest_colormap[starttranscolor + i] = 120; + for (; i < SKIN_RAMP_LENGTH; i++) // orange + dest_colormap[starttranscolor + i] = (UINT8)(80 + (i-10)); + break; + + case SKINCOLOR_TSUPER2: + for (i = 0; i < 4; i++) // white + dest_colormap[starttranscolor + i] = 120; + for (; i < SKIN_RAMP_LENGTH; i++) // orange + dest_colormap[starttranscolor + i] = (UINT8)(80 + ((i-4)>>1)); + break; + + case SKINCOLOR_TSUPER3: + dest_colormap[starttranscolor] = 120; // pure white + dest_colormap[starttranscolor+1] = 120; + for (i = 2; i < SKIN_RAMP_LENGTH; i++) // orange + dest_colormap[starttranscolor + i] = (UINT8)(80 + ((i-2)>>1)); + break; + + case SKINCOLOR_TSUPER4: + dest_colormap[starttranscolor] = 120; // pure white + for (i = 1; i < 9; i++) // orange + dest_colormap[starttranscolor + i] = (UINT8)(80 + (i-1)); + for (; i < SKIN_RAMP_LENGTH; i++) // gold + dest_colormap[starttranscolor + i] = (UINT8)(115 + (5*(i-9)/7)); + break; + + case SKINCOLOR_TSUPER5: + for (i = 0; i < 8; i++) // orange + dest_colormap[starttranscolor + i] = (UINT8)(80 + i); + for (; i < SKIN_RAMP_LENGTH; i++) // gold + dest_colormap[starttranscolor + i] = (UINT8)(115 + (5*(i-8)/8)); + break; + // Super Knuckles case SKINCOLOR_KSUPER1: for (i = 0; i < SKIN_RAMP_LENGTH; i++) diff --git a/src/r_things.c b/src/r_things.c index f440527c..c0f33daf 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -92,6 +92,8 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch UINT8 rotation, UINT8 flipped) { + char cn = R_Frame2Char(frame); // for debugging + INT32 r; lumpnum_t lumppat = wad; lumppat <<= 16; @@ -107,10 +109,10 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch { // the lump should be used for all rotations if (sprtemp[frame].rotate == 0) - CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, 'A'+frame); + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn); if (sprtemp[frame].rotate == 1) - CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, 'A'+frame); + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); sprtemp[frame].rotate = 0; for (r = 0; r < 8; r++) @@ -124,7 +126,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch // the lump is only used for one rotation if (sprtemp[frame].rotate == 0) - CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, 'A'+frame); + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn); sprtemp[frame].rotate = 1; @@ -132,7 +134,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch rotation--; if (sprtemp[frame].lumppat[rotation] != LUMPERROR) - CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c:%c has two lumps mapped to it\n", spritename, 'A'+frame, '1'+rotation); + CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, '1'+rotation); // lumppat & lumpid are the same for original Doom, but different // when using sprites in pwad : the lumppat points the new graphics @@ -189,7 +191,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, { if (memcmp(lumpinfo[l].name,sprname,4)==0) { - frame = (UINT8)(lumpinfo[l].name[4] - 'A'); + frame = R_Char2Frame(lumpinfo[l].name[4]); rotation = (UINT8)(lumpinfo[l].name[5] - '0'); if (frame >= 64 || rotation > 8) // Give an actual NAME error -_-... @@ -225,7 +227,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, if (lumpinfo[l].name[6]) { - frame = (UINT8)(lumpinfo[l].name[6] - 'A'); + frame = R_Char2Frame(lumpinfo[l].name[6]); rotation = (UINT8)(lumpinfo[l].name[7] - '0'); R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1); } @@ -277,8 +279,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, { case 0xff: // no rotations were found for that frame at all - I_Error("R_AddSingleSpriteDef: No patches found " - "for %s frame %c", sprname, frame+'A'); + I_Error("R_AddSingleSpriteDef: No patches found for %s frame %c", sprname, R_Frame2Char(frame)); break; case 0: @@ -291,9 +292,8 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, // we test the patch lump, or the id lump whatever // if it was not loaded the two are LUMPERROR if (sprtemp[frame].lumppat[rotation] == LUMPERROR) - I_Error("R_AddSingleSpriteDef: Sprite %s frame %c " - "is missing rotations", - sprname, frame+'A'); + I_Error("R_AddSingleSpriteDef: Sprite %s frame %c is missing rotations", + sprname, R_Frame2Char(frame)); break; } } diff --git a/src/r_things.h b/src/r_things.h index 8c5c7819..226b8e47 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -191,4 +191,39 @@ void R_InitDrawNodes(void); char *GetPlayerFacePic(INT32 skinnum); +// Functions to go from sprite character ID to frame number +// for 2.1 compatibility this still uses the old 'A' + frame code +// The use of symbols tends to be painful for wad editors though +// So the future version of this tries to avoid using symbols +// as much as possible while also defining all 64 slots in a sane manner +// 2.1: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ]] +// Future: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz!@ ]] +FUNCMATH FUNCINLINE static ATTRINLINE char R_Frame2Char(UINT8 frame) +{ +#if 1 // 2.1 compat + return 'A' + frame; +#else + if (frame < 26) return 'A' + frame; + if (frame < 36) return '0' + (frame - 26); + if (frame < 62) return 'a' + (frame - 36); + if (frame == 62) return '!'; + if (frame == 63) return '@'; + return '\xFF'; +#endif +} + +FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn) +{ +#if 1 // 2.1 compat + return cn - 'A'; +#else + if (cn >= 'A' && cn <= 'Z') return cn - 'A'; + if (cn >= '0' && cn <= '9') return (cn - '0') + 26; + if (cn >= 'a' && cn <= 'z') return (cn - 'a') + 36; + if (cn == '!') return 62; + if (cn == '@') return 63; + return 255; +#endif +} + #endif //__R_THINGS__ diff --git a/src/st_stuff.c b/src/st_stuff.c index 780101d1..4bba8eb5 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1833,11 +1833,12 @@ static void ST_overlayDrawer(void) { ST_drawFirstPersonHUD(); } + } #ifdef HAVE_BLUA + if (!(netgame || multiplayer) || !hu_showscores) LUAh_GameHUD(stplyr); #endif - } #if 0 // Pope XVI if (!(netgame || multiplayer) && !modifiedgame && gamemap == 11 && ALL7EMERALDS(emeralds) diff --git a/src/y_inter.c b/src/y_inter.c index cd2201de..35ecf62a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -57,8 +57,8 @@ typedef union { struct { - char passed1[13]; // KNUCKLES GOT - char passed2[16]; // THROUGH THE ACT + char passed1[14]; // KNUCKLES GOT / CRAWLA HONCHO + char passed2[16]; // THROUGH THE ACT / PASSED THE ACT INT32 passedx1; INT32 passedx2; @@ -998,43 +998,40 @@ void Y_StartIntermission(void) usetile = false; // set up the "got through act" message according to skin name - if (strlen(skins[players[consoleplayer].skin].realname) <= 8) + // too long so just show "YOU GOT THROUGH THE ACT" + if (strlen(skins[players[consoleplayer].skin].realname) > 13) { - snprintf(data.coop.passed1, - sizeof data.coop.passed1, "%s GOT", + strcpy(data.coop.passed1, "YOU GOT"); + strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT"); + } + // long enough that "X GOT" won't fit so use "X PASSED THE ACT" + else if (strlen(skins[players[consoleplayer].skin].realname) > 8) + { + strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname); + strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "PASSED ACT" : "PASSED THE ACT"); + } + // length is okay for normal use + else + { + snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s GOT", skins[players[consoleplayer].skin].realname); - data.coop.passed1[sizeof data.coop.passed1 - 1] = '\0'; - if (mapheaderinfo[gamemap-1]->actnum) - { - strcpy(data.coop.passed2, "THROUGH ACT"); - data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2; - data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2; - } - else - { - strcpy(data.coop.passed2, "THROUGH THE ACT"); - data.coop.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed1))/2; - data.coop.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed2))/2; - } - // The above value is not precalculated because it needs only be computed once - // at the start of intermission, and precalculating it would preclude mods - // changing the font to one of a slightly different width. + strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT"); + } + + // set X positions + if (mapheaderinfo[gamemap-1]->actnum) + { + data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2; + data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2; } else { - strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname); - data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2; - if (mapheaderinfo[gamemap-1]->actnum) - { - strcpy(data.coop.passed2, "PASSED ACT"); - data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2; - } - else - { - strcpy(data.coop.passed2, "PASSED THE ACT"); - data.coop.passedx2 = 62 + (240 - V_LevelNameWidth(data.coop.passed2))/2; - } + data.coop.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed1))/2; + data.coop.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed2))/2; } + // The above value is not precalculated because it needs only be computed once + // at the start of intermission, and precalculating it would preclude mods + // changing the font to one of a slightly different width. break; }