SRB2 2.1.7 release

This commit is contained in:
Alam Ed Arias 2014-04-14 01:14:58 -04:00
parent 2bd6573f5f
commit 02a3b0776c
36 changed files with 729 additions and 502 deletions

View file

@ -391,6 +391,39 @@ void COM_AddCommand(const char *name, com_func_t func)
com_commands = cmd; 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. /** Tests if a command exists.
* *
* \param com_name Name to test for. * \param com_name Name to test for.
@ -558,7 +591,7 @@ static void COM_CEchoFlags_f(void)
HU_SetCEchoFlags(atoi(arg)); HU_SetCEchoFlags(atoi(arg));
} }
else else
CONS_Printf(M_GetText("cechoflags <flags>: set CEcho flags, prepend with 0x to use hexadecimal")); CONS_Printf(M_GetText("cechoflags <flags>: set CEcho flags, prepend with 0x to use hexadecimal\n"));
} }
/** Sets the duration for CECHO commands to stay on the screen /** 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) if (var->PossibleValue)
{ {
INT32 v = atoi(valstr); 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 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) if (!var->PossibleValue[i].strvalue)
I_Error("Bounded cvar \"%s\" without maximum!\n", var->name); I_Error("Bounded cvar \"%s\" without maximum!\n", var->name);
#endif #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; v = var->PossibleValue[0].value;
valstr = var->PossibleValue[0].strvalue; valstr = var->PossibleValue[0].strvalue;
override = true; override = true;
overrideval = v; 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; v = var->PossibleValue[i].value;
valstr = var->PossibleValue[i].strvalue; valstr = var->PossibleValue[i].strvalue;
override = true; override = true;
overrideval = v; overrideval = v;
} }
if (v == INT32_MIN)
goto badinput;
} }
else else
{ {
@ -1052,48 +1090,32 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
for (i = 0; var->PossibleValue[i].strvalue; i++) for (i = 0; var->PossibleValue[i].strvalue; i++)
if (!stricmp(var->PossibleValue[i].strvalue, valstr)) if (!stricmp(var->PossibleValue[i].strvalue, valstr))
goto found; goto found;
if (!v) if (v != INT32_MIN)
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)
{ {
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")) if (overrideval != -1)
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)
{ {
for (i = 0; var->PossibleValue[i].strvalue; i++) for (i = 0; var->PossibleValue[i].strvalue; i++)
if (hopevalue == var->PossibleValue[i].value) if (overrideval == var->PossibleValue[i].value)
goto found; goto found;
} }
} }
// ...or not. // ...or not.
if (var != &cv_nextmap) // Suppress errors for cv_nextmap goto badinput;
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;
found: found:
var->value = var->PossibleValue[i].value; var->value = var->PossibleValue[i].value;
var->string = var->PossibleValue[i].strvalue; var->string = var->PossibleValue[i].strvalue;
@ -1141,6 +1163,18 @@ finish:
#endif #endif
if (var->flags & CV_CALL && !stealth) if (var->flags & CV_CALL && !stealth)
var->func(); 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);
} }
// //

View file

@ -23,6 +23,7 @@
typedef void (*com_func_t)(void); typedef void (*com_func_t)(void);
void COM_AddCommand(const char *name, com_func_t func); void COM_AddCommand(const char *name, com_func_t func);
int COM_AddLuaCommand(const char *name);
size_t COM_Argc(void); size_t COM_Argc(void);
const char *COM_Argv(size_t arg); // if argv > argc, returns empty string const char *COM_Argv(size_t arg); // if argv > argc, returns empty string

View file

@ -1086,15 +1086,14 @@ void D_SRB2Main(void)
#endif #endif
D_CleanFile(); D_CleanFile();
#if 1 // md5s last updated 3/22/14 #if 1 // md5s last updated 4/13/14
// Check MD5s of autoloaded files // Check MD5s of autoloaded files
W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad
W_VerifyFileMD5(1, "a894044b555dfcc71865cee16a996e88"); // zones.dta W_VerifyFileMD5(1, "e956466eff2c79f7b1cdefad24761bce"); // zones.dta
W_VerifyFileMD5(2, "4c410c1de6e0440cc5b2858dcca80c3e"); // player.dta W_VerifyFileMD5(2, "95a4cdbed287323dd361243f357a5fd2"); // player.dta
W_VerifyFileMD5(3, "85901ad4bf94637e5753d2ac2c03ea26"); // rings.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 // 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. // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
#endif #endif

View file

@ -134,6 +134,7 @@ static void Command_Skynum_f(void);
static void Command_ExitLevel_f(void); static void Command_ExitLevel_f(void);
static void Command_Showmap_f(void); static void Command_Showmap_f(void);
static void Command_Mapmd5_f(void);
static void Command_Teamchange_f(void); static void Command_Teamchange_f(void);
static void Command_Teamchange2_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_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_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_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 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("retry", Command_Retry_f);
COM_AddCommand("exitlevel", Command_ExitLevel_f); COM_AddCommand("exitlevel", Command_ExitLevel_f);
COM_AddCommand("showmap", Command_Showmap_f); COM_AddCommand("showmap", Command_Showmap_f);
COM_AddCommand("mapmd5", Command_Mapmd5_f);
COM_AddCommand("addfile", Command_Addfile); COM_AddCommand("addfile", Command_Addfile);
COM_AddCommand("listwad", Command_ListWADS_f); COM_AddCommand("listwad", Command_ListWADS_f);
@ -643,7 +644,6 @@ void D_RegisterClientCommands(void)
#ifdef SEENAMES #ifdef SEENAMES
CV_RegisterVar(&cv_seenames); CV_RegisterVar(&cv_seenames);
#endif #endif
CV_RegisterVar(&cv_realnames);
CV_RegisterVar(&cv_rollingdemos); CV_RegisterVar(&cv_rollingdemos);
CV_RegisterVar(&cv_netstat); 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")); 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) static void Command_ExitLevel_f(void)
{ {
if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug) if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug)

View file

@ -105,7 +105,7 @@ extern consvar_t cv_overtime;
extern consvar_t cv_startinglives; extern consvar_t cv_startinglives;
// for F_finale.c // for F_finale.c
extern consvar_t cv_realnames, cv_rollingdemos; extern consvar_t cv_rollingdemos;
extern consvar_t cv_resetmusic; extern consvar_t cv_resetmusic;

View file

@ -60,6 +60,8 @@
#include "md5.h" #include "md5.h"
#include "filesrch.h" #include "filesrch.h"
#include <errno.h>
static void SendFile(INT32 node, const char *filename, UINT8 fileid); static void SendFile(INT32 node, const char *filename, UINT8 fileid);
// sender structure // sender structure
@ -652,7 +654,7 @@ void Got_Filetxpak(void)
{ {
if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n"); if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb"); 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); CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
fileneeded[filenum].currentsize = 0; fileneeded[filenum].currentsize = 0;
fileneeded[filenum].status = FS_DOWNLOADING; 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 // we can receive packet in the wrong order, anyway all os support gaped file
fseek(fileneeded[filenum].phandle,pos,SEEK_SET); fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1) 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; fileneeded[filenum].currentsize += size;
// finished? // finished?

View file

@ -71,8 +71,6 @@ static powertype_t get_power(const char *word);
#endif #endif
boolean deh_loaded = false; 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 int dbg_line;
static boolean gamedataadded = false; static boolean gamedataadded = false;
@ -3285,12 +3283,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
} }
DEH_WriteUndoline(word, word2, UNDO_HEADER); 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")) /* else if (fastcmp(word, "ANIMTEX"))
{ {
readAnimTex(f, i); readAnimTex(f, i);
@ -4451,6 +4443,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_CYBRAKDEMONTARGETRETICULE13", "S_CYBRAKDEMONTARGETRETICULE13",
"S_CYBRAKDEMONTARGETRETICULE14", "S_CYBRAKDEMONTARGETRETICULE14",
"S_CYBRAKDEMONTARGETDOT",
"S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1", "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1",
"S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2", "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2",
"S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3", "S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3",
@ -6648,6 +6642,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_CYBRAKDEMON_FLAMESHOT", "MT_CYBRAKDEMON_FLAMESHOT",
"MT_CYBRAKDEMON_FLAMEREST", "MT_CYBRAKDEMON_FLAMEREST",
"MT_CYBRAKDEMON_TARGET_RETICULE", "MT_CYBRAKDEMON_TARGET_RETICULE",
"MT_CYBRAKDEMON_TARGET_DOT",
"MT_CYBRAKDEMON_NAPALM_BOMB_LARGE", "MT_CYBRAKDEMON_NAPALM_BOMB_LARGE",
"MT_CYBRAKDEMON_NAPALM_BOMB_SMALL", "MT_CYBRAKDEMON_NAPALM_BOMB_SMALL",
"MT_CYBRAKDEMON_NAPALM_FLAMES", "MT_CYBRAKDEMON_NAPALM_FLAMES",
@ -7301,12 +7296,12 @@ static const char *const POWERS_LIST[] = {
// Weapon ammunition // Weapon ammunition
"INFINITYRING", "INFINITYRING",
"BOUNCERING",
"RAILRING",
"AUTOMATICRING", "AUTOMATICRING",
"EXPLOSIONRING", "BOUNCERING",
"SCATTERRING", "SCATTERRING",
"GRENADERING", "GRENADERING",
"EXPLOSIONRING",
"RAILRING",
// Power Stones // Power Stones
"EMERALDS", // stored like global 'emeralds' variable "EMERALDS", // stored like global 'emeralds' variable
@ -7441,6 +7436,7 @@ struct {
{"TOL_MATCH",TOL_MATCH}, {"TOL_MATCH",TOL_MATCH},
{"TOL_TAG",TOL_TAG}, {"TOL_TAG",TOL_TAG},
{"TOL_CTF",TOL_CTF}, {"TOL_CTF",TOL_CTF},
{"TOL_CUSTOM",TOL_CUSTOM},
{"TOL_2D",TOL_2D}, {"TOL_2D",TOL_2D},
{"TOL_MARIO",TOL_MARIO}, {"TOL_MARIO",TOL_MARIO},
{"TOL_NIGHTS",TOL_NIGHTS}, {"TOL_NIGHTS",TOL_NIGHTS},
@ -7926,8 +7922,9 @@ static fixed_t find_const(const char **rword)
free(word); free(word);
return r; return r;
} }
if (*word >= 'A' && !*(word+1)) { // Turn a single A-z symbol into numbers, like sprite frames. if (!*(word+1) && // Turn a single A-z symbol into numbers, like sprite frames.
r = *word-'A'; (*word >= 'A' && *word <= 'Z') || (*word >= 'a' && *word <= 'z')) {
r = R_Char2Frame(*word);
free(word); free(word);
return r; return r;
} }

View file

@ -47,8 +47,7 @@ const char *LUA_GetActionName(void *action);
void LUA_SetActionByName(void *state, const char *actiontocompare); void LUA_SetActionByName(void *state, const char *actiontocompare);
#endif #endif
extern boolean deh_loaded, modcredits; extern boolean deh_loaded;
extern char modcreditname[32];
#define MAXRECURSION 30 #define MAXRECURSION 30
extern const char *superactions[MAXRECURSION]; extern const char *superactions[MAXRECURSION];

View file

@ -144,8 +144,8 @@ extern FILE *logstream;
#define VERSIONSTRING "Trunk" #define VERSIONSTRING "Trunk"
#else #else
#define VERSION 201 // Game version #define VERSION 201 // Game version
#define SUBVERSION 6 // more precise version number #define SUBVERSION 7 // more precise version number
#define VERSIONSTRING "v2.1.6" #define VERSIONSTRING "v2.1.7"
#endif #endif
// Modification options // 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. // 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. // 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". // 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_SUPER4,
SKINCOLOR_SUPER5, SKINCOLOR_SUPER5,
// Super Tails
SKINCOLOR_TSUPER1,
SKINCOLOR_TSUPER2,
SKINCOLOR_TSUPER3,
SKINCOLOR_TSUPER4,
SKINCOLOR_TSUPER5,
// Super Knuckles // Super Knuckles
SKINCOLOR_KSUPER1, SKINCOLOR_KSUPER1,
SKINCOLOR_KSUPER2, SKINCOLOR_KSUPER2,

View file

@ -991,7 +991,7 @@ static const char *credits[] = {
"\1Texture Artists", "\1Texture Artists",
"Ryan \"Blaze Hedgehog\" Bloom", "Ryan \"Blaze Hedgehog\" Bloom",
"Buddy \"KinkaJoy\" Fischer", "Buddy \"KinkaJoy\" Fischer",
"Pedro \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"Jarrett \"JEV3\" Voight", "Jarrett \"JEV3\" Voight",
"", "",
"\1Music and Sound", "\1Music and Sound",
@ -1002,7 +1002,7 @@ static const char *credits[] = {
"David \"Bulmybag\" Bulmer", "David \"Bulmybag\" Bulmer",
"Paul \"Boinciel\" Clempson", "Paul \"Boinciel\" Clempson",
"Cyan Helkaraxe", "Cyan Helkaraxe",
"Pedro \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"\"Monster\" Iestyn Jealous", "\"Monster\" Iestyn Jealous",
"Jarel \"Arrow\" Jones", "Jarel \"Arrow\" Jones",
"Stefan \"Stuf\" Rimalia", "Stefan \"Stuf\" Rimalia",
@ -1020,7 +1020,7 @@ static const char *credits[] = {
"Ben \"Mystic\" Geyer", "Ben \"Mystic\" Geyer",
"Nathan \"Jazz\" Giroux", "Nathan \"Jazz\" Giroux",
"Dan \"Blitzzo\" Hagerstrand", "Dan \"Blitzzo\" Hagerstrand",
"Pedro \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"Erik \"Torgo\" Nielsen", "Erik \"Torgo\" Nielsen",
"Wessel \"Spherallic\" Smit", "Wessel \"Spherallic\" Smit",
@ -1046,7 +1046,9 @@ static const char *credits[] = {
"Alex \"MistaED\" Fuller", "Alex \"MistaED\" Fuller",
"FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak
"Randy Heit (<!>)", // For his MSPaint <!> sprite that we nicked "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. >_> <_< >_>) "Abigail \"Raspberry\" Fox", // (Inuyasha's girlfriend. >_> <_< >_>)
#endif
"", "",
"\1Thank you", "\1Thank you",
"\1for playing!", "\1for playing!",

View file

@ -234,13 +234,16 @@ static UINT8 *demobuffer = NULL;
static UINT8 *demo_p, *demotime_p; static UINT8 *demo_p, *demotime_p;
static UINT8 *demoend; static UINT8 *demoend;
static UINT8 demoflags; static UINT8 demoflags;
static UINT16 demoversion;
boolean singledemo; // quit after playing a demo from cmdline boolean singledemo; // quit after playing a demo from cmdline
boolean demo_start; // don't start playing demo right away boolean demo_start; // don't start playing demo right away
static boolean demosynced = true; // console warning message
boolean metalrecording; // recording as metal sonic boolean metalrecording; // recording as metal sonic
mobj_t *metalplayback; mobj_t *metalplayback;
static UINT8 *metalbuffer = NULL; static UINT8 *metalbuffer = NULL;
static UINT8 *metal_p; static UINT8 *metal_p;
static UINT16 metalversion;
boolean metal_start; boolean metal_start;
// extra data stuff (events registered this frame while recording) // extra data stuff (events registered this frame while recording)
@ -262,7 +265,8 @@ static struct {
// There is no conflict here. // There is no conflict here.
typedef struct demoghost { typedef struct demoghost {
UINT8 checksum[16]; UINT8 checksum[16];
UINT8 *buffer, *p; UINT8 *buffer, *p, color;
UINT16 version;
mobj_t oldmo, *mo; mobj_t oldmo, *mo;
struct demoghost *next; struct demoghost *next;
} demoghost; } demoghost;
@ -3577,7 +3581,7 @@ char *G_BuildMapTitle(INT32 mapnum)
// DEMO RECORDING // DEMO RECORDING
// //
#define DEMOVERSION 0x0008 #define DEMOVERSION 0x0009
#define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" #define DEMOHEADER "\xF0" "SRB2Replay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too! #define DF_GHOST 0x01 // This demo contains ghost data too!
@ -3608,6 +3612,8 @@ static ticcmd_t oldcmd;
// GZT_EXTRA flags // GZT_EXTRA flags
#define EZT_THOK 0x01 // Spawned a thok object #define EZT_THOK 0x01 // Spawned a thok object
#define EZT_SPIN 0x02 // Because one type of thok object apparently wasn't enough #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_COLOR 0x04 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.)
#define EZT_FLIP 0x08 // Reversed gravity #define EZT_FLIP 0x08 // Reversed gravity
#define EZT_SCALE 0x10 // Changed size #define EZT_SCALE 0x10 // Changed size
@ -3725,14 +3731,21 @@ void G_GhostAddThok(void)
{ {
if (!demorecording || !(demoflags & DF_GHOST)) if (!demorecording || !(demoflags & DF_GHOST))
return; return;
ghostext.flags |= EZT_THOK; ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_THOK;
} }
void G_GhostAddSpin(void) void G_GhostAddSpin(void)
{ {
if (!demorecording || !(demoflags & DF_GHOST)) if (!demorecording || !(demoflags & DF_GHOST))
return; 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) 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. // Uses ghost data to do consistency checks on your position.
// This fixes desynchronising demos when fighting eggman. // This fixes desynchronising demos when fighting eggman.
void G_ConsGhostTic(void) void G_ConsGhostTic(void)
@ -4017,12 +4027,12 @@ void G_ConsGhostTic(void)
} }
// Re-synchronise // Re-synchronise
px = (players[0].mo->x>>8)&UINT16_MAX; px = players[0].mo->x>>FRACBITS;
py = (players[0].mo->y>>8)&UINT16_MAX; py = players[0].mo->y>>FRACBITS;
pz = (players[0].mo->z>>8)&UINT16_MAX; pz = players[0].mo->z>>FRACBITS;
gx = (oldghost.x>>8)&UINT16_MAX; gx = oldghost.x>>FRACBITS;
gy = (oldghost.y>>8)&UINT16_MAX; gy = oldghost.y>>FRACBITS;
gz = (oldghost.z>>8)&UINT16_MAX; gz = oldghost.z>>FRACBITS;
if (px != gx || py != gy || pz != gz) if (px != gx || py != gy || pz != gz)
{ {
@ -4036,8 +4046,6 @@ void G_ConsGhostTic(void)
P_SetThingPosition(players[0].mo); P_SetThingPosition(players[0].mo);
players[0].mo->z = oldghost.z; players[0].mo->z = oldghost.z;
} }
else
demosynced = true;
if (*demo_p == DEMOMARKER) if (*demo_p == DEMOMARKER)
{ {
@ -4105,17 +4113,16 @@ void G_GhostTicker(void)
ziptic = READUINT8(g->p); ziptic = READUINT8(g->p);
if (ziptic & EZT_COLOR) if (ziptic & EZT_COLOR)
{ {
switch(READUINT8(g->p)) g->color = READUINT8(g->p);
switch(g->color)
{ {
default: default:
case GHC_NORMAL: // Go back to skin color case GHC_NORMAL: // Go back to skin color
g->mo->color = g->oldmo.color; g->mo->color = g->oldmo.color;
break; break;
case GHC_SUPER: // Super Sonic // Handled below
g->mo->color = SKINCOLOR_SUPER4; case GHC_SUPER:
break; case GHC_INVINCIBLE:
case GHC_INVINCIBLE: /// \todo Mario invincibility
g->mo->color = SKINCOLOR_SUPER4;
break; break;
case GHC_FIREFLOWER: // Fireflower case GHC_FIREFLOWER: // Fireflower
g->mo->color = SKINCOLOR_WHITE; g->mo->color = SKINCOLOR_WHITE;
@ -4130,17 +4137,25 @@ void G_GhostTicker(void)
if (g->mo->destscale != g->mo->scale) if (g->mo->destscale != g->mo->scale)
P_SetScale(g->mo, g->mo->destscale); 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. { // Let's only spawn ONE of these per frame, thanks.
mobj_t *mobj; mobj_t *mobj;
INT32 type = -1; INT32 type = -1;
if (g->mo->skin) if (g->mo->skin)
{ {
skin_t *skin = (skin_t *)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; 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; 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) if (type == MT_GHOST)
{ {
@ -4201,6 +4216,32 @@ void G_GhostTicker(void)
g->mo->sprite = READUINT8(g->p); 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. // Demo ends after ghost data.
if (*g->p == DEMOMARKER) if (*g->p == DEMOMARKER)
{ {
@ -4483,7 +4524,7 @@ void G_BeginRecording(void)
// game data // game data
M_Memcpy(demo_p, "PLAY", 4); demo_p += 4; 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; M_Memcpy(demo_p, mapmd5, 16); demo_p += 16;
WRITEUINT8(demo_p,demoflags); WRITEUINT8(demo_p,demoflags);
@ -4563,6 +4604,10 @@ void G_BeginRecording(void)
oldghost.y = player->mo->y; oldghost.y = player->mo->y;
oldghost.z = player->mo->z; oldghost.z = player->mo->z;
oldghost.angle = player->mo->angle; 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 *buffer,*p;
UINT8 flags; UINT8 flags;
UINT32 oldtime, newtime, oldscore, newscore; UINT32 oldtime, newtime, oldscore, newscore;
UINT16 oldrings, newrings; UINT16 oldrings, newrings, oldversion;
size_t bufsize ATTRUNUSED; size_t bufsize ATTRUNUSED;
UINT8 c; UINT8 c;
UINT16 s ATTRUNUSED; UINT16 s ATTRUNUSED;
@ -4636,7 +4681,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p += 16; // demo checksum p += 16; // demo checksum
I_Assert(!memcmp(p, "PLAY", 4)); I_Assert(!memcmp(p, "PLAY", 4));
p += 4; // PLAY p += 4; // PLAY
p++; // gamemap p += 2; // gamemap
p += 16; // map md5 p += 16; // map md5
flags = READUINT8(p); // demoflags flags = READUINT8(p); // demoflags
I_Assert(flags & DF_RECORDATTACK); I_Assert(flags & DF_RECORDATTACK);
@ -4664,8 +4709,15 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
} p += 12; // DEMOHEADER } p += 12; // DEMOHEADER
p++; // VERSION p++; // VERSION
p++; // SUBVERSION 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); CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname);
Z_Free(buffer); Z_Free(buffer);
return UINT8_MAX; return UINT8_MAX;
@ -4677,7 +4729,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
Z_Free(buffer); Z_Free(buffer);
return UINT8_MAX; return UINT8_MAX;
} p += 4; // "PLAY" } p += 4; // "PLAY"
p++; // gamemap if (oldversion <= 0x0008)
p++; // gamemap
else
p += 2; // gamemap
p += 16; // mapmd5 p += 16; // mapmd5
flags = READUINT8(p); flags = READUINT8(p);
if (!(flags & DF_RECORDATTACK)) if (!(flags & DF_RECORDATTACK))
@ -4783,9 +4838,16 @@ void G_DoPlayDemo(char *defdemoname)
version = READUINT8(demo_p); version = READUINT8(demo_p);
subversion = 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); CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING); M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname); Z_Free(pdemoname);
@ -4807,7 +4869,10 @@ void G_DoPlayDemo(char *defdemoname)
return; return;
} }
demo_p += 4; // "PLAY" demo_p += 4; // "PLAY"
gamemap = READUINT8(demo_p); if (demoversion <= 0x0008)
gamemap = READUINT8(demo_p);
else
gamemap = READINT16(demo_p);
demo_p += 16; // mapmd5 demo_p += 16; // mapmd5
demoflags = READUINT8(demo_p); demoflags = READUINT8(demo_p);
@ -4950,7 +5015,7 @@ void G_AddGhost(char *defdemoname)
UINT8 flags; UINT8 flags;
UINT8 *buffer,*p; UINT8 *buffer,*p;
mapthing_t *mthing; mapthing_t *mthing;
UINT16 count; UINT16 count, ghostversion;
name[16] = '\0'; name[16] = '\0';
skin[16] = '\0'; skin[16] = '\0';
@ -4996,9 +5061,16 @@ void G_AddGhost(char *defdemoname)
} p += 12; // DEMOHEADER } p += 12; // DEMOHEADER
p++; // VERSION p++; // VERSION
p++; // SUBVERSION 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(pdemoname);
Z_Free(buffer); Z_Free(buffer);
return; return;
@ -5019,7 +5091,10 @@ void G_AddGhost(char *defdemoname)
Z_Free(buffer); Z_Free(buffer);
return; return;
} p += 4; // "PLAY" } p += 4; // "PLAY"
p++; // gamemap if (ghostversion <= 0x0008)
p++; // gamemap
else
p += 2; // gamemap
p += 16; // mapmd5 (possibly check for consistency?) p += 16; // mapmd5 (possibly check for consistency?)
flags = READUINT8(p); flags = READUINT8(p);
if (!(flags & DF_GHOST)) if (!(flags & DF_GHOST))
@ -5094,6 +5169,8 @@ void G_AddGhost(char *defdemoname)
gh->p = p; gh->p = p;
ghosts = gh; ghosts = gh;
gh->version = ghostversion;
mthing = playerstarts[0]; mthing = playerstarts[0];
I_Assert(mthing); 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. { // 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; gh->oldmo.z = gh->mo->z;
// Set skin // Set skin
gh->mo->skin = &skins[0];
for (i = 0; i < numskins; i++) for (i = 0; i < numskins; i++)
if (!stricmp(skins[i].name,skin)) if (!stricmp(skins[i].name,skin))
{ {
gh->mo->skin = &skins[i]; gh->mo->skin = &skins[i];
break; break;
} }
gh->oldmo.skin = gh->mo->skin;
// Set color // Set color
gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor;
for (i = 0; i < MAXSKINCOLORS; i++) for (i = 0; i < MAXSKINCOLORS; i++)
if (!stricmp(Color_Names[i],color)) if (!stricmp(Color_Names[i],color))
{ {
gh->mo->color = (UINT8)i; gh->mo->color = (UINT8)i;
break; break;
} }
gh->oldmo.color = gh->mo->color;
CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname); CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname);
Z_Free(pdemoname); Z_Free(pdemoname);
@ -5199,9 +5280,16 @@ void G_DoPlayMetal(void)
metal_p += 12; // DEMOHEADER metal_p += 12; // DEMOHEADER
metal_p++; // VERSION metal_p++; // VERSION
metal_p++; // SUBVERSION 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); Z_Free(metalbuffer);
return; return;
} }

View file

@ -137,6 +137,7 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum);
void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum); void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum);
void G_GhostAddThok(void); void G_GhostAddThok(void);
void G_GhostAddSpin(void); void G_GhostAddSpin(void);
void G_GhostAddRev(void);
void G_GhostAddColor(ghostcolor_t color); void G_GhostAddColor(ghostcolor_t color);
void G_GhostAddFlip(void); void G_GhostAddFlip(void);
void G_GhostAddScale(UINT16 scale); void G_GhostAddScale(UINT16 scale);

View file

@ -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[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[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 else
{ {
v[0].x = v[3].x = (cx*sdupx-gpatch->leftoffset*pdupx)/vid.width - 1; 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[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; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
if (option & V_FLIP) if (option & V_FLIP)
{ {
v[0].sow = v[3].sow = gpatch->max_s; v[0].sow = v[3].sow = gpatch->max_s;
v[2].sow = v[1].sow = 0.0f; 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 else
{ {
v[0].sow = v[3].sow = 0.0f; v[0].sow = v[3].sow = 0.0f;
v[2].sow = v[1].sow = gpatch->max_s; 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; flags = BLENDMODE|PF_Clip|PF_NoZClip|PF_NoDepthTest;
if (option & V_WRAPX) if (option & V_WRAPX)

View file

@ -881,6 +881,9 @@ static void md2_loadTexture(md2_t *model)
HWR_UnlockCachedPatch(grpatch); HWR_UnlockCachedPatch(grpatch);
} }
// Don't spam the console, or the OS with fopen requests!
static boolean nomd2s = false;
void HWR_InitMD2(void) void HWR_InitMD2(void)
{ {
size_t i; size_t i;
@ -906,12 +909,14 @@ void HWR_InitMD2(void)
md2_models[i].skin = -1; md2_models[i].skin = -1;
md2_models[i].notfound = true; md2_models[i].notfound = true;
} }
// read the md2.dat file
// read the md2.dat file
f = fopen("md2.dat", "rt"); f = fopen("md2.dat", "rt");
if (!f) if (!f)
{ {
CONS_Printf("%s", M_GetText("Error while loading md2.dat\n")); CONS_Printf("%s", M_GetText("Error while loading md2.dat\n"));
nomd2s = true;
return; return;
} }
while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) 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]; char name[18], filename[32];
float scale, offset; float scale, offset;
if (nomd2s)
return;
CONS_Printf("AddPlayerMD2()...\n"); CONS_Printf("AddPlayerMD2()...\n");
// read the md2.dat file // read the md2.dat file
f = fopen("md2.dat", "rt"); f = fopen("md2.dat", "rt");
if (!f) if (!f)
{ {
CONS_Printf("Error while loading md2.dat\n"); CONS_Printf("Error while loading md2.dat\n");
nomd2s = true;
return; return;
} }
@ -1009,13 +1018,16 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu
char name[18], filename[32]; char name[18], filename[32];
float scale, offset; float scale, offset;
// Read the md2.dat file if (nomd2s)
return;
// Read the md2.dat file
f = fopen("md2.dat", "rt"); f = fopen("md2.dat", "rt");
if (!f) if (!f)
{ {
CONS_Printf("Error while loading md2.dat\n"); CONS_Printf("Error while loading md2.dat\n");
nomd2s = true;
return; return;
} }

View file

@ -23,9 +23,9 @@
#include "hw_glob.h" #include "hw_glob.h"
#define MD2_MAX_TRIANGLES 4096 #define MD2_MAX_TRIANGLES 8192
#define MD2_MAX_VERTICES 2048 #define MD2_MAX_VERTICES 4096
#define MD2_MAX_TEXCOORDS 2048 #define MD2_MAX_TEXCOORDS 4096
#define MD2_MAX_FRAMES 512 #define MD2_MAX_FRAMES 512
#define MD2_MAX_SKINS 32 #define MD2_MAX_SKINS 32
#define MD2_MAX_FRAMESIZE (MD2_MAX_VERTICES * 4 + 128) #define MD2_MAX_FRAMESIZE (MD2_MAX_VERTICES * 4 + 128)

View file

@ -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, 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_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, 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, 0, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2 {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, 0, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3 {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, 0, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4 {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, 0, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5 {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, 0, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6 {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, 0, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7 {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, 0, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8 {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, 0, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9 {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, 0, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10 {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, 0, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11 {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, 0, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12 {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, 0, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13 {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_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, 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, 1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2,
{SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3, {SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3,
@ -4770,7 +4772,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_CYBRAKDEMON_TARGET_RETICULE { // MT_CYBRAKDEMON_TARGET_RETICULE
-1, // doomednum -1, // doomednum
S_CYBRAKDEMONTARGETRETICULE1, // spawnstate S_CYBRAKDEMONTARGETRETICULE1, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
@ -4797,6 +4799,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate 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 { // MT_CYBRAKDEMON_NAPALM_BOMB_LARGE
-1, // doomednum -1, // doomednum
S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, // spawnstate S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, // spawnstate
@ -10463,7 +10492,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8, // speed 8, // speed
64*FRACUNIT, // radius 64*FRACUNIT, // radius
64*FRACUNIT, // height 64*FRACUNIT, // height
0, // display offset 2, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
@ -13284,7 +13313,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8, // speed 8, // speed
32*FRACUNIT, // radius 32*FRACUNIT, // radius
32*FRACUNIT, // height 32*FRACUNIT, // height
1, // display offset 2, // display offset
16, // mass 16, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound

View file

@ -1353,6 +1353,8 @@ typedef enum state
S_CYBRAKDEMONTARGETRETICULE13, S_CYBRAKDEMONTARGETRETICULE13,
S_CYBRAKDEMONTARGETRETICULE14, S_CYBRAKDEMONTARGETRETICULE14,
S_CYBRAKDEMONTARGETDOT,
S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1,
S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2,
S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3,
@ -3567,6 +3569,7 @@ typedef enum mobj_type
MT_CYBRAKDEMON_FLAMESHOT, MT_CYBRAKDEMON_FLAMESHOT,
MT_CYBRAKDEMON_FLAMEREST, MT_CYBRAKDEMON_FLAMEREST,
MT_CYBRAKDEMON_TARGET_RETICULE, MT_CYBRAKDEMON_TARGET_RETICULE,
MT_CYBRAKDEMON_TARGET_DOT,
MT_CYBRAKDEMON_NAPALM_BOMB_LARGE, MT_CYBRAKDEMON_NAPALM_BOMB_LARGE,
MT_CYBRAKDEMON_NAPALM_BOMB_SMALL, MT_CYBRAKDEMON_NAPALM_BOMB_SMALL,
MT_CYBRAKDEMON_NAPALM_FLAMES, MT_CYBRAKDEMON_NAPALM_FLAMES,

View file

@ -16,6 +16,7 @@
#include "p_setup.h" // So we can have P_SetupLevelSky #include "p_setup.h" // So we can have P_SetupLevelSky
#include "z_zone.h" #include "z_zone.h"
#include "r_main.h" #include "r_main.h"
#include "r_things.h"
#include "m_random.h" #include "m_random.h"
#include "s_sound.h" #include "s_sound.h"
#include "g_game.h" #include "g_game.h"
@ -724,6 +725,27 @@ static int lib_pHomingAttack(lua_State *L)
return 0; 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 // P_MAP
/////////// ///////////
@ -1309,6 +1331,31 @@ static int lib_rPointInSubsector(lua_State *L)
return 1; 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 // S_SOUND
//////////// ////////////
@ -1593,6 +1640,8 @@ static luaL_Reg lib[] = {
{"P_LookForEnemies",lib_pLookForEnemies}, {"P_LookForEnemies",lib_pLookForEnemies},
{"P_NukeEnemies",lib_pNukeEnemies}, {"P_NukeEnemies",lib_pNukeEnemies},
{"P_HomingAttack",lib_pHomingAttack}, {"P_HomingAttack",lib_pHomingAttack},
{"P_SuperReady",lib_pSuperReady},
{"P_DoJump",lib_pDoJump},
// p_map // p_map
{"P_CheckPosition",lib_pCheckPosition}, {"P_CheckPosition",lib_pCheckPosition},
@ -1645,6 +1694,10 @@ static luaL_Reg lib[] = {
{"R_PointToDist2",lib_rPointToDist2}, {"R_PointToDist2",lib_rPointToDist2},
{"R_PointInSubsector",lib_rPointInSubsector}, {"R_PointInSubsector",lib_rPointInSubsector},
// r_things (sprite)
{"R_Char2Frame",lib_rChar2Frame},
{"R_Frame2Char",lib_rFrame2Char},
// s_sound // s_sound
{"S_StartSound",lib_sStartSound}, {"S_StartSound",lib_sStartSound},
{"S_StartSoundAtVolume",lib_sStartSoundAtVolume}, {"S_StartSoundAtVolume",lib_sStartSoundAtVolume},

View file

@ -79,7 +79,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum)
} }
// Wrapper for COM_AddCommand commands // Wrapper for COM_AddCommand commands
static void COM_Lua_f(void) void COM_Lua_f(void)
{ {
char *buf, *p; char *buf, *p;
UINT8 i, flags; UINT8 i, flags;
@ -90,9 +90,13 @@ static void COM_Lua_f(void)
lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command
I_Assert(lua_istable(gL, -1)); 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)); I_Assert(lua_istable(gL, -1));
lua_remove(gL, -2); // pop COM_Command lua_remove(gL, -2); // pop COM_Command
Z_Free(buf);
lua_rawgeti(gL, -1, 2); // push flags from command info table lua_rawgeti(gL, -1, 2); // push flags from command info table
if (lua_isboolean(gL, -1)) if (lua_isboolean(gL, -1))
@ -158,8 +162,13 @@ static void COM_Lua_f(void)
// Wrapper for COM_AddCommand // Wrapper for COM_AddCommand
static int lib_comAddCommand(lua_State *L) static int lib_comAddCommand(lua_State *L)
{ {
boolean exists = false; int com_return = -1;
const char *name = luaL_checkstring(L, 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); luaL_checktype(L, 2, LUA_TFUNCTION);
NOHUD NOHUD
if (lua_gettop(L) >= 3) if (lua_gettop(L) >= 3)
@ -177,11 +186,6 @@ static int lib_comAddCommand(lua_State *L)
lua_getfield(L, LUA_REGISTRYINDEX, "COM_Command"); lua_getfield(L, LUA_REGISTRYINDEX, "COM_Command");
I_Assert(lua_istable(L, -1)); 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_createtable(L, 2, 0);
lua_pushvalue(L, 2); lua_pushvalue(L, 2);
lua_rawseti(L, -2, 1); lua_rawseti(L, -2, 1);
@ -190,14 +194,23 @@ static int lib_comAddCommand(lua_State *L)
lua_rawseti(L, -2, 2); lua_rawseti(L, -2, 2);
lua_setfield(L, -2, name); lua_setfield(L, -2, name);
// This makes it only add a new command if another // Try to add the Lua command
// Lua command by the same name doesn't already exist. com_return = COM_AddLuaCommand(name);
//
// UNFORTUNATELY COM_AddCommand will still cause I_Errors if (com_return < 0)
// if you attempt to override an existing hardcoded command. { // failed to add -- free the lowercased name and return error
// Z_Free(name);
if (!exists) return luaL_error(L, "Couldn't add a new console command \"%s\"", luaname);
COM_AddCommand(name, COM_Lua_f); }
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; return 0;
} }

View file

@ -23,6 +23,8 @@
#include "lua_hook.h" #include "lua_hook.h"
#include "lua_hud.h" // hud_running errors #include "lua_hud.h" // hud_running errors
static UINT8 hooksAvailable[(hook_MAX/8)+1];
const char *const hookNames[hook_MAX+1] = { const char *const hookNames[hook_MAX+1] = {
"NetVars", "NetVars",
"MapChange", "MapChange",
@ -183,6 +185,9 @@ static int lib_addHook(lua_State *L)
if (subfield) if (subfield)
Z_Free(subfield); Z_Free(subfield);
hooksAvailable[hook/8] |= 1<<(hook%8);
return 0; return 0;
} }
@ -190,6 +195,8 @@ int LUA_HookLib(lua_State *L)
{ {
// Create all registry tables // Create all registry tables
enum hook i; enum hook i;
memset(hooksAvailable,0,sizeof(UINT8[(hook_MAX/8)+1]));
lua_newtable(L); lua_newtable(L);
for (i = 0; i < hook_MAX; i++) 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 LUAh_MobjHook(mobj_t *mo, enum hook which)
{ {
boolean hooked = false; boolean hooked = false;
if (!gL) if (!gL || !(hooksAvailable[which/8] & (1<<(which%8))))
return false; return false;
// clear the stack (just in case) // 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) // Hook for map change (before load)
void LUAh_MapChange(void) void LUAh_MapChange(void)
{ {
if (!gL) if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8))))
return; return;
lua_getfield(gL, LUA_REGISTRYINDEX, "hook"); lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
@ -337,7 +344,7 @@ void LUAh_MapChange(void)
// Hook for map load // Hook for map load
void LUAh_MapLoad(void) void LUAh_MapLoad(void)
{ {
if (!gL) if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8))))
return; return;
lua_pop(gL, -1); lua_pop(gL, -1);
@ -361,7 +368,7 @@ void LUAh_MapLoad(void)
// Hook for Got_AddPlayer // Hook for Got_AddPlayer
void LUAh_PlayerJoin(int playernum) void LUAh_PlayerJoin(int playernum)
{ {
if (!gL) if (!gL || !(hooksAvailable[hook_PlayerJoin/8] & (1<<(hook_PlayerJoin%8))))
return; return;
lua_pop(gL, -1); lua_pop(gL, -1);
@ -385,7 +392,7 @@ void LUAh_PlayerJoin(int playernum)
// Hook for frame (after mobj and player thinkers) // Hook for frame (after mobj and player thinkers)
void LUAh_ThinkFrame(void) void LUAh_ThinkFrame(void)
{ {
if (!gL) if (!gL || !(hooksAvailable[hook_ThinkFrame/8] & (1<<(hook_ThinkFrame%8))))
return; return;
lua_pop(gL, -1); lua_pop(gL, -1);
@ -420,7 +427,7 @@ void LUAh_ThinkFrame(void)
UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2) UINT8 LUAh_MobjCollide(mobj_t *thing1, mobj_t *thing2)
{ {
UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. 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; return 0;
// clear the stack // 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 LUAh_MobjMoveCollide(mobj_t *thing1, mobj_t *thing2)
{ {
UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. 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; return 0;
// clear the stack // 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 LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
{ {
boolean hooked = false; boolean hooked = false;
if (!gL) if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8))))
return false; return false;
// clear the stack // clear the stack
@ -551,8 +558,14 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
while (lua_next(gL, 1) != 0) { while (lua_next(gL, 1) != 0) {
lua_pushvalue(gL, 2); // special lua_pushvalue(gL, 2); // special
lua_pushvalue(gL, 3); // toucher lua_pushvalue(gL, 3); // toucher
LUA_Call(gL, 2); // pops hook function, special, toucher if (lua_pcall(gL, 2, 1, 0)) { // pops hook function, special, toucher, pushes 1 return result
hooked = true; 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); 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 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage)
{ {
UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. 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; return 0;
// clear the stack // 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 LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage)
{ {
boolean handled = false; boolean handled = false;
if (!gL) if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8))))
return false; return false;
// clear the stack // 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 LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
{ {
boolean handled = false; boolean handled = false;
if (!gL) if (!gL || !(hooksAvailable[hook_MobjDeath/8] & (1<<(hook_MobjDeath%8))))
return false; return false;
// clear the stack // 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 LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd)
{ {
boolean hooked = false; boolean hooked = false;
if (!gL) if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8))))
return false; return false;
// clear the stack // clear the stack
@ -737,8 +750,14 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd)
while (lua_next(gL, 1)) { while (lua_next(gL, 1)) {
lua_pushvalue(gL, 2); // bot lua_pushvalue(gL, 2); // bot
lua_pushvalue(gL, 3); // cmd lua_pushvalue(gL, 3); // cmd
LUA_Call(gL, 2); if (lua_pcall(gL, 2, 1, 0)) {
hooked = true; 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); lua_pop(gL, -1);
@ -749,7 +768,7 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd)
// Hook for B_BuildTailsTiccmd by skin name // Hook for B_BuildTailsTiccmd by skin name
boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) 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; return false;
// clear the stack // clear the stack
@ -813,7 +832,7 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
// Hook for linedef executors // Hook for linedef executors
boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo) boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo)
{ {
if (!gL) if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8))))
return false; return false;
// clear the stack // clear the stack

View file

@ -26,6 +26,8 @@
boolean hud_running = false; boolean hud_running = false;
static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hud_enabled[(hud_MAX/8)+1];
static UINT8 hudAvailable; // hud hooks field
// must match enum hud in lua_hud.h // must match enum hud in lua_hud.h
static const char *const hud_disable_options[] = { static const char *const hud_disable_options[] = {
"stagetitle", "stagetitle",
@ -399,6 +401,8 @@ static int lib_hudadd(lua_State *L)
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1)); lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1));
hudAvailable |= 1<<field;
return 0; return 0;
} }
@ -472,7 +476,7 @@ boolean LUA_HudEnabled(enum hud option)
// Hook for HUD rendering // Hook for HUD rendering
void LUAh_GameHUD(player_t *stplyr) void LUAh_GameHUD(player_t *stplyr)
{ {
if (!gL) if (!gL || !(hudAvailable & (1<<hudhook_game)))
return; return;
hud_running = true; hud_running = true;
@ -502,7 +506,7 @@ void LUAh_GameHUD(player_t *stplyr)
void LUAh_ScoresHUD(void) void LUAh_ScoresHUD(void)
{ {
if (!gL) if (!gL || !(hudAvailable & (1<<hudhook_scores)))
return; return;
hud_running = true; hud_running = true;

View file

@ -729,6 +729,9 @@ static int mapthing_set(lua_State *L)
static int lib_iterateMapthings(lua_State *L) static int lib_iterateMapthings(lua_State *L)
{ {
size_t i = 0; size_t i = 0;
if (lua_gettop(L) < 2)
return luaL_error(L, "Don't call mapthings.iterate() directly, use it as 'for mapthing in mapthings.iterate do <block> end'.");
lua_settop(L, 2);
lua_remove(L, 1); // state is unused. lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1)) if (!lua_isnil(L, 1))
i = (size_t)(*((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)) - mapthings) + 1; i = (size_t)(*((mapthing_t **)luaL_checkudata(L, 1, META_MAPTHING)) - mapthings) + 1;

View file

@ -43,6 +43,9 @@ void LUA_CVarChanged(const char *name); // lua_consolelib.c
int Lua_optoption(lua_State *L, int narg, int Lua_optoption(lua_State *L, int narg,
const char *def, const char *const lst[]); const char *def, const char *const lst[]);
// Console wrapper
void COM_Lua_f(void);
#define LUA_Call(L,a)\ #define LUA_Call(L,a)\
{\ {\
if (lua_pcall(L, a, 0, 0)) {\ if (lua_pcall(L, a, 0, 0)) {\

View file

@ -22,7 +22,7 @@
// GIFs are always little-endian // GIFs are always little-endian
#include "byteptr.h" #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}; consvar_t cv_gif_downscale = {"gif_downscale", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#ifdef HAVE_ANIGIF #ifdef HAVE_ANIGIF
@ -357,7 +357,7 @@ static void GIF_lzw(void)
if (gifbwr_bufsize >= 250) if (gifbwr_bufsize >= 250)
break; break;
} }
if (scrbuf_pos >= scrbuf_writeend) if (scrbuf_pos > scrbuf_writeend)
{ {
GIF_bwrwrite(giflzw_workingCode); GIF_bwrwrite(giflzw_workingCode);
GIF_bwrwrite(GIFLZW_DATAEND); GIF_bwrwrite(GIFLZW_DATAEND);

View file

@ -365,7 +365,7 @@ static CV_PossibleValue_t map_cons_t[] = {
{1,"MIN"}, {1,"MIN"},
{NUMMAPS, "MAX"} {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}}; 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}; 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') if (customversionstring[0] != '\0')
{ {
V_DrawThinString(vid.dupx, BASEVIDHEIGHT - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:"); V_DrawThinString(vid.dupx, vid.height - 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 - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring);
} }
else else
#if VERSION > 0 || SUBVERSION > 0 #if VERSION > 0 || SUBVERSION > 0

View file

@ -2600,70 +2600,26 @@ void A_MonitorPop(mobj_t *actor)
{ {
case MT_QUESTIONBOX: // Random! case MT_QUESTIONBOX: // Random!
{ {
mobjtype_t spawnchance[128]; mobjtype_t spawnchance[256];
SINT8 numchoices = 0; INT32 numchoices = 0, i = 0;
SINT8 target = 0;
if (cv_superring.value) #define QUESTIONBOXCHANCES(type, cvar) \
{ for (i = cvar.value; i; --i) spawnchance[numchoices++] = type
for (target += (SINT8)cv_superring.value; numchoices < target;)
spawnchance[numchoices++] = MT_SUPERRINGBOX; QUESTIONBOXCHANCES(MT_SUPERRINGBOX, cv_superring);
} QUESTIONBOXCHANCES(MT_SNEAKERTV, cv_supersneakers);
if (cv_supersneakers.value) QUESTIONBOXCHANCES(MT_INV, cv_invincibility);
{ QUESTIONBOXCHANCES(MT_WHITETV, cv_jumpshield);
for (target += (SINT8)cv_supersneakers.value; numchoices < target;) QUESTIONBOXCHANCES(MT_GREENTV, cv_watershield);
spawnchance[numchoices++] = MT_SNEAKERTV; QUESTIONBOXCHANCES(MT_YELLOWTV, cv_ringshield);
} QUESTIONBOXCHANCES(MT_BLUETV, cv_forceshield);
if (cv_invincibility.value) QUESTIONBOXCHANCES(MT_BLACKTV, cv_bombshield);
{ QUESTIONBOXCHANCES(MT_PRUP, cv_1up);
for (target += (SINT8)cv_invincibility.value; numchoices < target;) QUESTIONBOXCHANCES(MT_EGGMANBOX, cv_eggmanbox);
spawnchance[numchoices++] = MT_INV; QUESTIONBOXCHANCES(MT_MIXUPBOX, cv_teleporters);
} QUESTIONBOXCHANCES(MT_RECYCLETV, cv_recycler);
if (cv_jumpshield.value)
{ #undef QUESTIONBOXCHANCES
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;
}
if (numchoices == 0) if (numchoices == 0)
{ {
@ -3020,7 +2976,7 @@ void A_JumpShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_JUMP) 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); P_SpawnShieldOrb(player);
} }
@ -3052,7 +3008,7 @@ void A_RingShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT) 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); P_SpawnShieldOrb(player);
} }
@ -3149,7 +3105,7 @@ void A_SuperSneakers(mobj_t *actor)
actor->target->player->powers[pw_sneakers] = sneakertics + 1; 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)) if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
S_SpeedMusic(1.4f); S_SpeedMusic(1.4f);
@ -3254,7 +3210,7 @@ void A_BombShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_BOMB) 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); P_SpawnShieldOrb(player);
} }
@ -3286,7 +3242,7 @@ void A_WaterShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL) 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); P_SpawnShieldOrb(player);
} }
@ -9847,14 +9803,18 @@ void A_VileAttack(mobj_t *actor)
// Function: A_VileFire // Function: A_VileFire
// //
// Description: Kind of like A_CapeChase; keeps this object in front of its tracer, unless its target can't see it. // 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 // 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) void A_VileFire(mobj_t *actor)
{ {
INT32 locvar1 = var1; INT32 locvar1 = var1;
INT32 locvar2 = var2;
mobj_t *dest; mobj_t *dest;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
@ -9870,10 +9830,10 @@ void A_VileFire(mobj_t *actor)
if (!P_CheckSight(actor->target, dest)) if (!P_CheckSight(actor->target, dest))
return; return;
// keep to same scale and gravity as target ALWAYS // keep to same scale and gravity as tracer ALWAYS
actor->destscale = actor->target->scale; actor->destscale = dest->scale;
P_SetScale(actor, actor->destscale); P_SetScale(actor, actor->destscale);
if (actor->target->eflags & MFE_VERTICALFLIP) if (dest->eflags & MFE_VERTICALFLIP)
{ {
actor->eflags |= MFE_VERTICALFLIP; actor->eflags |= MFE_VERTICALFLIP;
actor->flags2 |= MF2_OBJECTFLIP; actor->flags2 |= MF2_OBJECTFLIP;
@ -9893,6 +9853,33 @@ void A_VileFire(mobj_t *actor)
// Play sound, if one's specified // Play sound, if one's specified
if (locvar1 > 0 && locvar1 < NUMSFX) if (locvar1 > 0 && locvar1 < NUMSFX)
S_StartSound(actor, (sfxenum_t)locvar1); 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 // Function: A_BrakChase

View file

@ -91,6 +91,7 @@ static void P_SetTranslucencies(void)
R_SetTrans(S_CYBRAKDEMONFLAMESHOT_FLY1, S_CYBRAKDEMONFLAMESHOT_DIE, tr_trans50); // Flame R_SetTrans(S_CYBRAKDEMONFLAMESHOT_FLY1, S_CYBRAKDEMONFLAMESHOT_DIE, tr_trans50); // Flame
R_SetTrans(S_CYBRAKDEMONFLAMEREST, 0, tr_trans50); // Flame R_SetTrans(S_CYBRAKDEMONFLAMEREST, 0, tr_trans50); // Flame
R_SetTrans(S_CYBRAKDEMONTARGETRETICULE1, S_CYBRAKDEMONTARGETRETICULE14, tr_trans50); // Target 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); R_SetTrans(S_FOG1, S_FOG14, tr_trans50);

View file

@ -2404,6 +2404,8 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
{ {
if (!(inflictor->flags & MF_FIRE)) if (!(inflictor->flags & MF_FIRE))
P_GivePlayerRings(player, 1); P_GivePlayerRings(player, 1);
if (inflictor->flags2 & MF2_BOUNCERING)
inflictor->fuse = 1;
return false; return false;
} }
@ -2489,6 +2491,8 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
{ {
if (!(inflictor->flags & MF_FIRE)) if (!(inflictor->flags & MF_FIRE))
P_GivePlayerRings(target->player, 1); P_GivePlayerRings(target->player, 1);
if (inflictor->flags2 & MF2_BOUNCERING)
inflictor->fuse = 1;
return false; return false;
} }
@ -2636,7 +2640,10 @@ void P_RemoveShield(player_t *player)
player->powers[pw_shield] = SH_NONE; player->powers[pw_shield] = SH_NONE;
// Reset fireflower // Reset fireflower
if (!player->powers[pw_super]) if (!player->powers[pw_super])
{
player->mo->color = player->skincolor; 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! else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) // Give them what's coming to them!
{ {

View file

@ -6565,179 +6565,27 @@ void P_MobjThinker(mobj_t *mobj)
if ((mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) if ((mobj->flags & MF_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX)
{ {
mobjtype_t spawnchance[64]; mobjtype_t spawnchance[64];
INT32 i = 0; INT32 numchoices = 0, i = 0;
INT32 oldi = 0;
INT32 increment = 0;
INT32 numchoices = 0;
//if (cv_superring.value) // This define should make it a lot easier to organize and change monitor weights
{ #define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \
oldi = i; for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type
if (mobj->flags2 & MF2_STRONGBOX) //strong box // Type SRM WRM
increment = 0; SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers
else //weak box SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility
increment = 0; 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++) #undef SETMONITORCHANCES
{
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++;
}
}
i = P_RandomKey(numchoices); // Gotta love those random numbers! i = P_RandomKey(numchoices); // Gotta love those random numbers!
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); 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) if (ultimatemode)
&& (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 (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++))) 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 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; 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_AXISTRANSFER].doomednum &&
mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum && mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum &&
mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum && mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum &&
mthing->type != mobjinfo[MT_STARPOST].doomednum && mthing->type != mobjinfo[MT_STARPOST].doomednum)
mthing->type != mobjinfo[MT_GRAVITYBOX].doomednum &&
mthing->type != mobjinfo[MT_EGGMANBOX].doomednum)
mobj->flags |= MF_AMBUSH; mobj->flags |= MF_AMBUSH;
} }
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
{ {
// flag for strong/weak random boxes // 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_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum ||
mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].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_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum ||
mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum ||
mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum || mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum)
mthing->type == mobjinfo[MT_PRUP].doomednum) mobj->flags2 |= MF2_STRONGBOX;
mobj->flags2 |= MF2_STRONGBOX;
// Requires you to be in bonus time to activate // Requires you to be in bonus time to activate
if (mobj->flags & MF_NIGHTSITEM) if (mobj->flags & MF_NIGHTSITEM)

View file

@ -1336,7 +1336,7 @@ static void P_NetArchiveThinkers(void)
if ((mobj->x != mobj->spawnpoint->x << FRACBITS) || if ((mobj->x != mobj->spawnpoint->x << FRACBITS) ||
(mobj->y != mobj->spawnpoint->y << 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; diff |= MD_POS;
if (mobj->info->doomednum != mobj->spawnpoint->type) if (mobj->info->doomednum != mobj->spawnpoint->type)

View file

@ -1135,8 +1135,16 @@ void P_RestoreMusic(player_t *player)
S_ChangeMusic(mus_supers, true); S_ChangeMusic(mus_supers, true);
else if (player->powers[pw_invulnerability] > 1) else if (player->powers[pw_invulnerability] > 1)
S_ChangeMusic((mariomode) ? mus_minvnc : mus_invinc, false); S_ChangeMusic((mariomode) ? mus_minvnc : mus_invinc, false);
else if (player->powers[pw_sneakers] > 1) else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super])
S_ChangeMusic(mus_shoes, true); {
if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
{
S_SpeedMusic(1.4f);
S_ChangeMusic(mapmusic, true);
}
else
S_ChangeMusic(mus_shoes, true);
}
else else
S_ChangeMusic(mapmusic, true); 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 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--; 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; 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; player->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5;
break;
}
G_GhostAddColor(GHC_SUPER); G_GhostAddColor(GHC_SUPER);
// Ran out of rings while 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. // Now spawn the color thok circle.
P_SpawnSpinMobj(player, player->revitem); 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 // 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; 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) if (player->powers[pw_tailsfly] && player->speed > topspeed)
{ movepushside >>= 2;
player->speed = topspeed - 1;
movepushside /= 4;
}
} }
// Allow a bit of movement while spinning // Allow a bit of movement while spinning
@ -6525,6 +6538,10 @@ static void P_MovePlayer(player_t *player)
if (player->pflags & PF_GLIDING) if (player->pflags & PF_GLIDING)
{ {
fixed_t leeway; fixed_t leeway;
fixed_t glidespeed = player->actionspd;
if (player->powers[pw_super])
glidespeed *= 2;
if (player->mo->eflags & MFE_VERTICALFLIP) if (player->mo->eflags & MFE_VERTICALFLIP)
{ {
@ -6542,7 +6559,7 @@ static void P_MovePlayer(player_t *player)
if (player->skidtime) // ground gliding 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) if (player->mo->eflags & MFE_UNDERWATER)
speed >>= 1; speed >>= 1;
speed = FixedMul(speed - player->glidetime*FRACUNIT, player->mo->scale); 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); P_InstaThrust(player->mo, player->mo->angle-leeway, speed);
} }
else if (player->mo->eflags & MFE_UNDERWATER) 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 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++; player->glidetime++;
@ -6568,6 +6585,7 @@ static void P_MovePlayer(player_t *player)
} }
else else
{ {
player->pflags |= PF_THOKKED;
player->mo->momx >>= 1; player->mo->momx >>= 1;
player->mo->momy >>= 1; player->mo->momy >>= 1;
P_SetPlayerMobjState(player->mo, S_PLAY_FALL1); 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) // 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<<FRACBITS, player->mo->scale) && !(player->pflags & PF_JUMPED)) if (player->pflags & PF_SPINNING && player->speed > FixedMul(15<<FRACBITS, player->mo->scale) && !(player->pflags & PF_JUMPED))
{
P_SpawnSpinMobj(player, player->spinitem); P_SpawnSpinMobj(player, player->spinitem);
if (demorecording)
G_GhostAddSpin();
}
//////////////////////////// ////////////////////////////
@ -7481,11 +7503,8 @@ boolean P_LookForEnemies(player_t *player)
continue; // not a mobj thinker continue; // not a mobj thinker
mo = (mobj_t *)think; mo = (mobj_t *)think;
if (!(mo->flags & MF_ENEMY || mo->flags & MF_BOSS || mo->flags & MF_MONITOR if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)))
|| mo->flags & MF_SPRING))
{
continue; // not a valid enemy continue; // not a valid enemy
}
if (mo->health <= 0) // dead if (mo->health <= 0) // dead
continue; continue;
@ -7496,14 +7515,14 @@ boolean P_LookForEnemies(player_t *player)
if (mo->flags2 & MF2_FRET) if (mo->flags2 & MF2_FRET)
continue; 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; continue;
if (mo->type == MT_DETON) // Don't be STUPID, Sonic! if (mo->type == MT_DETON) // Don't be STUPID, Sonic!
continue; continue;
if (((mo->z > player->mo->z+FixedMul(MAXSTEPMOVE, player->mo->scale)) && !(player->mo->eflags & MFE_VERTICALFLIP)) 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! continue; // Don't home upwards!
if (P_AproxDistance(P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y), 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) if (dist < 1)
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)); 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); source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);

View file

@ -376,10 +376,10 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
// Super colors, from lightest to darkest! // Super colors, from lightest to darkest!
case SKINCOLOR_SUPER1: case SKINCOLOR_SUPER1:
// Super White // Super White
for (i = 0; i < 14; i++) for (i = 0; i < 10; i++)
dest_colormap[starttranscolor + i] = 120; // True white dest_colormap[starttranscolor + i] = 120; // True white
for (; i < SKIN_RAMP_LENGTH; i++) for (; i < SKIN_RAMP_LENGTH; i++) // White-yellow fade
dest_colormap[starttranscolor + i] = 112; // Golden shine dest_colormap[starttranscolor + i] = (UINT8)(96 + (i-10));
break; break;
case SKINCOLOR_SUPER2: case SKINCOLOR_SUPER2:
@ -422,6 +422,43 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
dest_colormap[starttranscolor + 15] = 155; dest_colormap[starttranscolor + 15] = 155;
break; 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 // Super Knuckles
case SKINCOLOR_KSUPER1: case SKINCOLOR_KSUPER1:
for (i = 0; i < SKIN_RAMP_LENGTH; i++) for (i = 0; i < SKIN_RAMP_LENGTH; i++)

View file

@ -92,6 +92,8 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
UINT8 rotation, UINT8 rotation,
UINT8 flipped) UINT8 flipped)
{ {
char cn = R_Frame2Char(frame); // for debugging
INT32 r; INT32 r;
lumpnum_t lumppat = wad; lumpnum_t lumppat = wad;
lumppat <<= 16; lumppat <<= 16;
@ -107,10 +109,10 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
{ {
// the lump should be used for all rotations // the lump should be used for all rotations
if (sprtemp[frame].rotate == 0) 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) 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; sprtemp[frame].rotate = 0;
for (r = 0; r < 8; r++) 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 // the lump is only used for one rotation
if (sprtemp[frame].rotate == 0) 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; sprtemp[frame].rotate = 1;
@ -132,7 +134,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
rotation--; rotation--;
if (sprtemp[frame].lumppat[rotation] != LUMPERROR) 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 // lumppat & lumpid are the same for original Doom, but different
// when using sprites in pwad : the lumppat points the new graphics // 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) 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'); rotation = (UINT8)(lumpinfo[l].name[5] - '0');
if (frame >= 64 || rotation > 8) // Give an actual NAME error -_-... 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]) 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'); rotation = (UINT8)(lumpinfo[l].name[7] - '0');
R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1); R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1);
} }
@ -277,8 +279,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
{ {
case 0xff: case 0xff:
// no rotations were found for that frame at all // no rotations were found for that frame at all
I_Error("R_AddSingleSpriteDef: No patches found " I_Error("R_AddSingleSpriteDef: No patches found for %s frame %c", sprname, R_Frame2Char(frame));
"for %s frame %c", sprname, frame+'A');
break; break;
case 0: 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 // we test the patch lump, or the id lump whatever
// if it was not loaded the two are LUMPERROR // if it was not loaded the two are LUMPERROR
if (sprtemp[frame].lumppat[rotation] == LUMPERROR) if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
I_Error("R_AddSingleSpriteDef: Sprite %s frame %c " I_Error("R_AddSingleSpriteDef: Sprite %s frame %c is missing rotations",
"is missing rotations", sprname, R_Frame2Char(frame));
sprname, frame+'A');
break; break;
} }
} }

View file

@ -191,4 +191,39 @@ void R_InitDrawNodes(void);
char *GetPlayerFacePic(INT32 skinnum); 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__ #endif //__R_THINGS__

View file

@ -1833,11 +1833,12 @@ static void ST_overlayDrawer(void)
{ {
ST_drawFirstPersonHUD(); ST_drawFirstPersonHUD();
} }
}
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (!(netgame || multiplayer) || !hu_showscores)
LUAh_GameHUD(stplyr); LUAh_GameHUD(stplyr);
#endif #endif
}
#if 0 // Pope XVI #if 0 // Pope XVI
if (!(netgame || multiplayer) && !modifiedgame && gamemap == 11 && ALL7EMERALDS(emeralds) if (!(netgame || multiplayer) && !modifiedgame && gamemap == 11 && ALL7EMERALDS(emeralds)

View file

@ -57,8 +57,8 @@ typedef union
{ {
struct struct
{ {
char passed1[13]; // KNUCKLES GOT char passed1[14]; // KNUCKLES GOT / CRAWLA HONCHO
char passed2[16]; // THROUGH THE ACT char passed2[16]; // THROUGH THE ACT / PASSED THE ACT
INT32 passedx1; INT32 passedx1;
INT32 passedx2; INT32 passedx2;
@ -998,43 +998,40 @@ void Y_StartIntermission(void)
usetile = false; usetile = false;
// set up the "got through act" message according to skin name // 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, strcpy(data.coop.passed1, "YOU GOT");
sizeof data.coop.passed1, "%s 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); skins[players[consoleplayer].skin].realname);
data.coop.passed1[sizeof data.coop.passed1 - 1] = '\0'; strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT");
if (mapheaderinfo[gamemap-1]->actnum) }
{
strcpy(data.coop.passed2, "THROUGH ACT"); // set X positions
data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2; if (mapheaderinfo[gamemap-1]->actnum)
data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2; {
} data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2;
else data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2;
{
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.
} }
else else
{ {
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname); data.coop.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed1))/2;
data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2; data.coop.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed2))/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;
}
} }
// 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; break;
} }