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;
}
/** Adds a console command for Lua.
* No I_Errors allowed; return a negative code instead.
*
* \param name Name of the command.
*/
int COM_AddLuaCommand(const char *name)
{
xcommand_t *cmd;
// fail if the command is a variable name
if (CV_StringValue(name)[0] != '\0')
return -1;
// command already exists
for (cmd = com_commands; cmd; cmd = cmd->next)
{
if (!stricmp(name, cmd->name)) //case insensitive now that we have lower and uppercase!
{
// replace the built in command.
cmd->function = COM_Lua_f;
return 1;
}
}
// Add a new command.
cmd = ZZ_Alloc(sizeof *cmd);
cmd->name = name;
cmd->function = COM_Lua_f;
cmd->next = com_commands;
com_commands = cmd;
return 0;
}
/** Tests if a command exists.
*
* \param com_name Name to test for.
@ -558,7 +591,7 @@ static void COM_CEchoFlags_f(void)
HU_SetCEchoFlags(atoi(arg));
}
else
CONS_Printf(M_GetText("cechoflags <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
@ -1017,6 +1050,8 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
if (var->PossibleValue)
{
INT32 v = atoi(valstr);
if (!v && valstr[0] != '0')
v = INT32_MIN; // Invalid integer trigger
if (var->PossibleValue[0].strvalue && !stricmp(var->PossibleValue[0].strvalue, "MIN")) // bounded cvar
{
@ -1029,20 +1064,23 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
if (!var->PossibleValue[i].strvalue)
I_Error("Bounded cvar \"%s\" without maximum!\n", var->name);
#endif
if (v < var->PossibleValue[0].value || !stricmp(valstr, "MIN"))
if ((v != INT32_MIN && v < var->PossibleValue[0].value) || !stricmp(valstr, "MIN"))
{
v = var->PossibleValue[0].value;
valstr = var->PossibleValue[0].strvalue;
override = true;
overrideval = v;
}
if (v > var->PossibleValue[i].value || !stricmp(valstr, "MAX"))
else if ((v != INT32_MIN && v > var->PossibleValue[i].value) || !stricmp(valstr, "MAX"))
{
v = var->PossibleValue[i].value;
valstr = var->PossibleValue[i].strvalue;
override = true;
overrideval = v;
}
if (v == INT32_MIN)
goto badinput;
}
else
{
@ -1052,48 +1090,32 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
for (i = 0; var->PossibleValue[i].strvalue; i++)
if (!stricmp(var->PossibleValue[i].strvalue, valstr))
goto found;
if (!v)
if (strcmp(valstr, "0"))
goto error;
// check INT32 now
for (i = 0; var->PossibleValue[i].strvalue; i++)
if (v == var->PossibleValue[i].value)
goto found;
error:
// not found
// But wait, there's hope!
if (var->PossibleValue == CV_OnOff
|| var->PossibleValue == CV_YesNo)
if (v != INT32_MIN)
{
INT32 hopevalue = -1;
// check INT32 now
for (i = 0; var->PossibleValue[i].strvalue; i++)
if (v == var->PossibleValue[i].value)
goto found;
}
// Not found ... but wait, there's hope!
if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo)
{
overrideval = -1;
if (!stricmp(valstr, "on") || !stricmp(valstr, "yes"))
overrideval = 1;
else if (!stricmp(valstr, "off") || !stricmp(valstr, "no"))
overrideval = 0;
if (!stricmp(valstr, "on"))
hopevalue = 1;
else if (!stricmp(valstr, "off"))
hopevalue = 0;
else if (!stricmp(valstr, "yes"))
hopevalue = 1;
else if (!stricmp(valstr, "no"))
hopevalue = 0;
if (hopevalue != -1)
if (overrideval != -1)
{
for (i = 0; var->PossibleValue[i].strvalue; i++)
if (hopevalue == var->PossibleValue[i].value)
if (overrideval == var->PossibleValue[i].value)
goto found;
}
}
// ...or not.
if (var != &cv_nextmap) // Suppress errors for cv_nextmap
CONS_Printf(M_GetText("\"%s\" is not a possible value for \"%s\"\n"), valstr, var->name);
if (var->defaultvalue == valstr)
I_Error("Variable %s default value \"%s\" is not a possible value\n",
var->name, var->defaultvalue);
return;
goto badinput;
found:
var->value = var->PossibleValue[i].value;
var->string = var->PossibleValue[i].strvalue;
@ -1141,6 +1163,18 @@ finish:
#endif
if (var->flags & CV_CALL && !stealth)
var->func();
return;
// landing point for possiblevalue failures
badinput:
if (var != &cv_nextmap) // Suppress errors for cv_nextmap
CONS_Printf(M_GetText("\"%s\" is not a possible value for \"%s\"\n"), valstr, var->name);
// default value not valid... ?!
if (var->defaultvalue == valstr)
I_Error("Variable %s default value \"%s\" is not a possible value\n", var->name, var->defaultvalue);
}
//

View file

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

View file

@ -1086,15 +1086,14 @@ void D_SRB2Main(void)
#endif
D_CleanFile();
#if 1 // md5s last updated 3/22/14
#if 1 // md5s last updated 4/13/14
// Check MD5s of autoloaded files
W_VerifyFileMD5(0, "ac309fb3c7d4b5b685e2cd26beccf0e8"); // srb2.srb/srb2.wad
W_VerifyFileMD5(1, "a894044b555dfcc71865cee16a996e88"); // zones.dta
W_VerifyFileMD5(2, "4c410c1de6e0440cc5b2858dcca80c3e"); // player.dta
W_VerifyFileMD5(1, "e956466eff2c79f7b1cdefad24761bce"); // zones.dta
W_VerifyFileMD5(2, "95a4cdbed287323dd361243f357a5fd2"); // player.dta
W_VerifyFileMD5(3, "85901ad4bf94637e5753d2ac2c03ea26"); // rings.dta
W_VerifyFileMD5(4, "386ab4ffc8c9fb0fa62f788a16e5c218"); // patch.dta
W_VerifyFileMD5(4, "1f37fe7bcc608a23eadb0e2c2d7c7124"); // patch.dta
// don't check music.dta because people like to modify it, and it doesn't matter if they do
// ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
#endif

View file

@ -134,6 +134,7 @@ static void Command_Skynum_f(void);
static void Command_ExitLevel_f(void);
static void Command_Showmap_f(void);
static void Command_Mapmd5_f(void);
static void Command_Teamchange_f(void);
static void Command_Teamchange2_f(void);
@ -330,7 +331,6 @@ consvar_t cv_itemfinder = {"itemfinder", "Off", CV_CALL, CV_OnOff, ItemFinder_On
consvar_t cv_match_scoring = {"matchscoring", "Normal", CV_NETVAR|CV_CHEAT, match_scoring_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_realnames = {"realnames", "Off", CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_timetic = {"timerres", "Normal", 0, timetic_cons_t, NULL, CV_SAVE, NULL, NULL, 0, 0, NULL}; // use tics in display
@ -431,6 +431,7 @@ void D_RegisterServerCommands(void)
COM_AddCommand("retry", Command_Retry_f);
COM_AddCommand("exitlevel", Command_ExitLevel_f);
COM_AddCommand("showmap", Command_Showmap_f);
COM_AddCommand("mapmd5", Command_Mapmd5_f);
COM_AddCommand("addfile", Command_Addfile);
COM_AddCommand("listwad", Command_ListWADS_f);
@ -643,7 +644,6 @@ void D_RegisterClientCommands(void)
#ifdef SEENAMES
CV_RegisterVar(&cv_seenames);
#endif
CV_RegisterVar(&cv_realnames);
CV_RegisterVar(&cv_rollingdemos);
CV_RegisterVar(&cv_netstat);
@ -3866,6 +3866,20 @@ static void Command_Showmap_f(void)
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
}
static void Command_Mapmd5_f(void)
{
if (gamestate == GS_LEVEL)
{
INT32 i;
char md5tmp[33];
for (i = 0; i < 16; ++i)
sprintf(&md5tmp[i*2], "%02x", mapmd5[i]);
CONS_Printf("%s: %s\n", G_BuildMapName(gamemap), md5tmp);
}
else
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
}
static void Command_ExitLevel_f(void)
{
if (!(netgame || (multiplayer && gametype != GT_COOP)) && !cv_debug)

View file

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

View file

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

View file

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

View file

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

View file

@ -144,8 +144,8 @@ extern FILE *logstream;
#define VERSIONSTRING "Trunk"
#else
#define VERSION 201 // Game version
#define SUBVERSION 6 // more precise version number
#define VERSIONSTRING "v2.1.6"
#define SUBVERSION 7 // more precise version number
#define VERSIONSTRING "v2.1.7"
#endif
// Modification options
@ -201,7 +201,7 @@ extern FILE *logstream;
// it's only for detection of the version the player is using so the MS can alert them of an update.
// Only set it higher, not lower, obviously.
// Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
#define MODVERSION 11
#define MODVERSION 12
@ -259,6 +259,13 @@ typedef enum
SKINCOLOR_SUPER4,
SKINCOLOR_SUPER5,
// Super Tails
SKINCOLOR_TSUPER1,
SKINCOLOR_TSUPER2,
SKINCOLOR_TSUPER3,
SKINCOLOR_TSUPER4,
SKINCOLOR_TSUPER5,
// Super Knuckles
SKINCOLOR_KSUPER1,
SKINCOLOR_KSUPER2,

View file

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

View file

@ -234,13 +234,16 @@ static UINT8 *demobuffer = NULL;
static UINT8 *demo_p, *demotime_p;
static UINT8 *demoend;
static UINT8 demoflags;
static UINT16 demoversion;
boolean singledemo; // quit after playing a demo from cmdline
boolean demo_start; // don't start playing demo right away
static boolean demosynced = true; // console warning message
boolean metalrecording; // recording as metal sonic
mobj_t *metalplayback;
static UINT8 *metalbuffer = NULL;
static UINT8 *metal_p;
static UINT16 metalversion;
boolean metal_start;
// extra data stuff (events registered this frame while recording)
@ -262,7 +265,8 @@ static struct {
// There is no conflict here.
typedef struct demoghost {
UINT8 checksum[16];
UINT8 *buffer, *p;
UINT8 *buffer, *p, color;
UINT16 version;
mobj_t oldmo, *mo;
struct demoghost *next;
} demoghost;
@ -3577,7 +3581,7 @@ char *G_BuildMapTitle(INT32 mapnum)
// DEMO RECORDING
//
#define DEMOVERSION 0x0008
#define DEMOVERSION 0x0009
#define DEMOHEADER "\xF0" "SRB2Replay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too!
@ -3608,6 +3612,8 @@ static ticcmd_t oldcmd;
// GZT_EXTRA flags
#define EZT_THOK 0x01 // Spawned a thok object
#define EZT_SPIN 0x02 // Because one type of thok object apparently wasn't enough
#define EZT_REV 0x03 // And two types wasn't enough either yet
#define EZT_THOKMASK 0x03
#define EZT_COLOR 0x04 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.)
#define EZT_FLIP 0x08 // Reversed gravity
#define EZT_SCALE 0x10 // Changed size
@ -3725,14 +3731,21 @@ void G_GhostAddThok(void)
{
if (!demorecording || !(demoflags & DF_GHOST))
return;
ghostext.flags |= EZT_THOK;
ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_THOK;
}
void G_GhostAddSpin(void)
{
if (!demorecording || !(demoflags & DF_GHOST))
return;
ghostext.flags |= EZT_SPIN;
ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_SPIN;
}
void G_GhostAddRev(void)
{
if (!demorecording || !(demoflags & DF_GHOST))
return;
ghostext.flags = (ghostext.flags & ~EZT_THOKMASK) | EZT_REV;
}
void G_GhostAddFlip(void)
@ -3928,9 +3941,6 @@ void G_WriteGhostTic(mobj_t *ghost)
}
}
// console warning messages
UINT8 demosynced = true;
// Uses ghost data to do consistency checks on your position.
// This fixes desynchronising demos when fighting eggman.
void G_ConsGhostTic(void)
@ -4017,12 +4027,12 @@ void G_ConsGhostTic(void)
}
// Re-synchronise
px = (players[0].mo->x>>8)&UINT16_MAX;
py = (players[0].mo->y>>8)&UINT16_MAX;
pz = (players[0].mo->z>>8)&UINT16_MAX;
gx = (oldghost.x>>8)&UINT16_MAX;
gy = (oldghost.y>>8)&UINT16_MAX;
gz = (oldghost.z>>8)&UINT16_MAX;
px = players[0].mo->x>>FRACBITS;
py = players[0].mo->y>>FRACBITS;
pz = players[0].mo->z>>FRACBITS;
gx = oldghost.x>>FRACBITS;
gy = oldghost.y>>FRACBITS;
gz = oldghost.z>>FRACBITS;
if (px != gx || py != gy || pz != gz)
{
@ -4036,8 +4046,6 @@ void G_ConsGhostTic(void)
P_SetThingPosition(players[0].mo);
players[0].mo->z = oldghost.z;
}
else
demosynced = true;
if (*demo_p == DEMOMARKER)
{
@ -4105,17 +4113,16 @@ void G_GhostTicker(void)
ziptic = READUINT8(g->p);
if (ziptic & EZT_COLOR)
{
switch(READUINT8(g->p))
g->color = READUINT8(g->p);
switch(g->color)
{
default:
case GHC_NORMAL: // Go back to skin color
g->mo->color = g->oldmo.color;
break;
case GHC_SUPER: // Super Sonic
g->mo->color = SKINCOLOR_SUPER4;
break;
case GHC_INVINCIBLE: /// \todo Mario invincibility
g->mo->color = SKINCOLOR_SUPER4;
// Handled below
case GHC_SUPER:
case GHC_INVINCIBLE:
break;
case GHC_FIREFLOWER: // Fireflower
g->mo->color = SKINCOLOR_WHITE;
@ -4130,17 +4137,25 @@ void G_GhostTicker(void)
if (g->mo->destscale != g->mo->scale)
P_SetScale(g->mo, g->mo->destscale);
}
if (ziptic & (EZT_THOK|EZT_SPIN))
if (ziptic & EZT_THOKMASK)
{ // Let's only spawn ONE of these per frame, thanks.
mobj_t *mobj;
INT32 type = -1;
if (g->mo->skin)
{
skin_t *skin = (skin_t *)g->mo->skin;
if (ziptic & EZT_THOK)
switch (ziptic & EZT_THOKMASK)
{
case EZT_THOK:
type = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem;
else
break;
case EZT_SPIN:
type = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem;
break;
case EZT_REV:
type = skin->revitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem;
break;
}
}
if (type == MT_GHOST)
{
@ -4201,6 +4216,32 @@ void G_GhostTicker(void)
g->mo->sprite = READUINT8(g->p);
}
// Tick ghost colors (Super and Mario Invincibility flashing)
switch(g->color)
{
case GHC_SUPER: // Super Sonic (P_DoSuperStuff)
// Yousa yellow now!
g->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5;
if (g->mo->skin)
switch (((skin_t*)g->mo->skin)-skins)
{
case 1: // Golden orange supertails.
g->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5;
break;
case 2: // Pink superknux.
g->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5;
break;
default:
break;
}
break;
case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer)
g->mo->color = (UINT8)(leveltime % MAXSKINCOLORS);
break;
default:
break;
}
// Demo ends after ghost data.
if (*g->p == DEMOMARKER)
{
@ -4483,7 +4524,7 @@ void G_BeginRecording(void)
// game data
M_Memcpy(demo_p, "PLAY", 4); demo_p += 4;
WRITEUINT8(demo_p,gamemap);
WRITEINT16(demo_p,gamemap);
M_Memcpy(demo_p, mapmd5, 16); demo_p += 16;
WRITEUINT8(demo_p,demoflags);
@ -4563,6 +4604,10 @@ void G_BeginRecording(void)
oldghost.y = player->mo->y;
oldghost.z = player->mo->z;
oldghost.angle = player->mo->angle;
// preticker started us gravity flipped
if (player->mo->eflags & MFE_VERTICALFLIP)
ghostext.flags |= EZT_FLIP;
}
}
@ -4613,7 +4658,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
UINT8 *buffer,*p;
UINT8 flags;
UINT32 oldtime, newtime, oldscore, newscore;
UINT16 oldrings, newrings;
UINT16 oldrings, newrings, oldversion;
size_t bufsize ATTRUNUSED;
UINT8 c;
UINT16 s ATTRUNUSED;
@ -4636,7 +4681,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p += 16; // demo checksum
I_Assert(!memcmp(p, "PLAY", 4));
p += 4; // PLAY
p++; // gamemap
p += 2; // gamemap
p += 16; // map md5
flags = READUINT8(p); // demoflags
I_Assert(flags & DF_RECORDATTACK);
@ -4664,8 +4709,15 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
} p += 12; // DEMOHEADER
p++; // VERSION
p++; // SUBVERSION
if (READUINT16(p) != DEMOVERSION)
oldversion = READUINT16(p);
switch(oldversion) // demoversion
{
case DEMOVERSION: // latest always supported
// compatibility available?
case 0x0008:
break;
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname);
Z_Free(buffer);
return UINT8_MAX;
@ -4677,7 +4729,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
Z_Free(buffer);
return UINT8_MAX;
} p += 4; // "PLAY"
p++; // gamemap
if (oldversion <= 0x0008)
p++; // gamemap
else
p += 2; // gamemap
p += 16; // mapmd5
flags = READUINT8(p);
if (!(flags & DF_RECORDATTACK))
@ -4783,9 +4838,16 @@ void G_DoPlayDemo(char *defdemoname)
version = READUINT8(demo_p);
subversion = READUINT8(demo_p);
if (DEMOVERSION != READUINT16(demo_p))
demoversion = READUINT16(demo_p);
switch(demoversion)
{
snprintf(msg, 1024, M_GetText("%s is a different replay format and cannot be played.\n"), pdemoname);
case DEMOVERSION: // latest always supported
// compatibility available?
case 0x0008:
break;
// too old, cannot support.
default:
snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
@ -4807,7 +4869,10 @@ void G_DoPlayDemo(char *defdemoname)
return;
}
demo_p += 4; // "PLAY"
gamemap = READUINT8(demo_p);
if (demoversion <= 0x0008)
gamemap = READUINT8(demo_p);
else
gamemap = READINT16(demo_p);
demo_p += 16; // mapmd5
demoflags = READUINT8(demo_p);
@ -4950,7 +5015,7 @@ void G_AddGhost(char *defdemoname)
UINT8 flags;
UINT8 *buffer,*p;
mapthing_t *mthing;
UINT16 count;
UINT16 count, ghostversion;
name[16] = '\0';
skin[16] = '\0';
@ -4996,9 +5061,16 @@ void G_AddGhost(char *defdemoname)
} p += 12; // DEMOHEADER
p++; // VERSION
p++; // SUBVERSION
if (DEMOVERSION != READUINT16(p))
ghostversion = READUINT16(p);
switch(ghostversion)
{
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo format unacceptable.\n"), pdemoname);
case DEMOVERSION: // latest always supported
// compatibility available?
case 0x0008:
break;
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
return;
@ -5019,7 +5091,10 @@ void G_AddGhost(char *defdemoname)
Z_Free(buffer);
return;
} p += 4; // "PLAY"
p++; // gamemap
if (ghostversion <= 0x0008)
p++; // gamemap
else
p += 2; // gamemap
p += 16; // mapmd5 (possibly check for consistency?)
flags = READUINT8(p);
if (!(flags & DF_GHOST))
@ -5094,6 +5169,8 @@ void G_AddGhost(char *defdemoname)
gh->p = p;
ghosts = gh;
gh->version = ghostversion;
mthing = playerstarts[0];
I_Assert(mthing);
{ // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling.
@ -5124,20 +5201,24 @@ void G_AddGhost(char *defdemoname)
gh->oldmo.z = gh->mo->z;
// Set skin
gh->mo->skin = &skins[0];
for (i = 0; i < numskins; i++)
if (!stricmp(skins[i].name,skin))
{
gh->mo->skin = &skins[i];
break;
}
gh->oldmo.skin = gh->mo->skin;
// Set color
gh->mo->color = ((skin_t*)gh->mo->skin)->prefcolor;
for (i = 0; i < MAXSKINCOLORS; i++)
if (!stricmp(Color_Names[i],color))
{
gh->mo->color = (UINT8)i;
break;
}
gh->oldmo.color = gh->mo->color;
CONS_Printf(M_GetText("Added ghost %s from %s\n"), name, pdemoname);
Z_Free(pdemoname);
@ -5199,9 +5280,16 @@ void G_DoPlayMetal(void)
metal_p += 12; // DEMOHEADER
metal_p++; // VERSION
metal_p++; // SUBVERSION
if (DEMOVERSION != READUINT16(metal_p))
metalversion = READUINT16(metal_p);
switch(metalversion)
{
CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version mismatch.\n"));
case DEMOVERSION: // latest always supported
// compatibility available?
case 0x0008:
break;
// too old, cannot support.
default:
CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n"));
Z_Free(metalbuffer);
return;
}

View file

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

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

View file

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

View file

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

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, TICRATE, {A_PlaySound}, sfx_s3k79, 0, S_NULL}, // S_CYBRAKDEMONELECTRICBARRIER_INIT1
{SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, sfx_s3k9d, 0, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2
{SPR_TARG, 1 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4
{SPR_TARG, 2 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6
{SPR_TARG, 3 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8
{SPR_TARG, 4 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10
{SPR_TARG, 5 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12
{SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, 0, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13
{SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, sfx_s3k9d, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE2}, // S_CYBRAKDEMONTARGETRETICULE1
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE3}, // S_CYBRAKDEMONTARGETRETICULE2
{SPR_TARG, 1 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE4}, // S_CYBRAKDEMONTARGETRETICULE3
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE5}, // S_CYBRAKDEMONTARGETRETICULE4
{SPR_TARG, 2 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE6}, // S_CYBRAKDEMONTARGETRETICULE5
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE7}, // S_CYBRAKDEMONTARGETRETICULE6
{SPR_TARG, 3 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE8}, // S_CYBRAKDEMONTARGETRETICULE7
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE9}, // S_CYBRAKDEMONTARGETRETICULE8
{SPR_TARG, 4 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE10}, // S_CYBRAKDEMONTARGETRETICULE9
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE11}, // S_CYBRAKDEMONTARGETRETICULE10
{SPR_TARG, 5 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE12}, // S_CYBRAKDEMONTARGETRETICULE11
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE13}, // S_CYBRAKDEMONTARGETRETICULE12
{SPR_TARG, 0 + FF_FULLBRIGHT, 1, {A_VileFire}, 0, MT_CYBRAKDEMON_TARGET_DOT, S_CYBRAKDEMONTARGETRETICULE14}, // S_CYBRAKDEMONTARGETRETICULE13
{SPR_TARG, 6 + FF_FULLBRIGHT, 1, {A_Repeat}, 6, S_CYBRAKDEMONTARGETRETICULE2, S_NULL}, // S_CYBRAKDEMONTARGETRETICULE14
{SPR_HOOP, 0 + FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_CYBRAKDEMONTARGETDOT
{SPR_NPLM, 0, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1,
{SPR_NPLM, 1, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY2,
{SPR_NPLM, 2, 2, {NULL}, 0, 0, S_CYBRAKDEMONNAPALMBOMBLARGE_FLY4}, //S_CYBRAKDEMONNAPALMBOMBLARGE_FLY3,
@ -4770,7 +4772,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_CYBRAKDEMON_TARGET_RETICULE
{ // MT_CYBRAKDEMON_TARGET_RETICULE
-1, // doomednum
S_CYBRAKDEMONTARGETRETICULE1, // spawnstate
1000, // spawnhealth
@ -4797,6 +4799,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_CYBRAKDEMON_TARGET_DOT
-1, // doomednum
S_CYBRAKDEMONTARGETDOT, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_BPLD1, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
10*FRACUNIT, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate
},
{ // MT_CYBRAKDEMON_NAPALM_BOMB_LARGE
-1, // doomednum
S_CYBRAKDEMONNAPALMBOMBLARGE_FLY1, // spawnstate
@ -10463,7 +10492,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8, // speed
64*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound
@ -13284,7 +13313,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
8, // speed
32*FRACUNIT, // radius
32*FRACUNIT, // height
1, // display offset
2, // display offset
16, // mass
0, // damage
sfx_None, // activesound

View file

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

View file

@ -16,6 +16,7 @@
#include "p_setup.h" // So we can have P_SetupLevelSky
#include "z_zone.h"
#include "r_main.h"
#include "r_things.h"
#include "m_random.h"
#include "s_sound.h"
#include "g_game.h"
@ -724,6 +725,27 @@ static int lib_pHomingAttack(lua_State *L)
return 0;
}
static int lib_pSuperReady(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, P_SuperReady(player));
return 1;
}
static int lib_pDoJump(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean soundandstate = (boolean)lua_opttrueboolean(L, 2);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
P_DoJump(player, soundandstate);
return 0;
}
// P_MAP
///////////
@ -1309,6 +1331,31 @@ static int lib_rPointInSubsector(lua_State *L)
return 1;
}
// R_THINGS
////////////
static int lib_rChar2Frame(lua_State *L)
{
const char *p = luaL_checkstring(L, 1);
//HUDSAFE
lua_pushinteger(L, R_Char2Frame(*p)); // first character only
return 1;
}
static int lib_rFrame2Char(lua_State *L)
{
UINT8 ch = (UINT8)luaL_checkinteger(L, 1);
char c[2] = "";
//HUDSAFE
c[0] = R_Frame2Char(ch);
c[1] = 0;
lua_pushstring(L, c);
lua_pushinteger(L, c[0]);
return 2;
}
// S_SOUND
////////////
@ -1593,6 +1640,8 @@ static luaL_Reg lib[] = {
{"P_LookForEnemies",lib_pLookForEnemies},
{"P_NukeEnemies",lib_pNukeEnemies},
{"P_HomingAttack",lib_pHomingAttack},
{"P_SuperReady",lib_pSuperReady},
{"P_DoJump",lib_pDoJump},
// p_map
{"P_CheckPosition",lib_pCheckPosition},
@ -1645,6 +1694,10 @@ static luaL_Reg lib[] = {
{"R_PointToDist2",lib_rPointToDist2},
{"R_PointInSubsector",lib_rPointInSubsector},
// r_things (sprite)
{"R_Char2Frame",lib_rChar2Frame},
{"R_Frame2Char",lib_rFrame2Char},
// s_sound
{"S_StartSound",lib_sStartSound},
{"S_StartSoundAtVolume",lib_sStartSoundAtVolume},

View file

@ -79,7 +79,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum)
}
// Wrapper for COM_AddCommand commands
static void COM_Lua_f(void)
void COM_Lua_f(void)
{
char *buf, *p;
UINT8 i, flags;
@ -90,9 +90,13 @@ static void COM_Lua_f(void)
lua_getfield(gL, LUA_REGISTRYINDEX, "COM_Command"); // push COM_Command
I_Assert(lua_istable(gL, -1));
lua_getfield(gL, -1, COM_Argv(0)); // push command info table
// use buf temporarily -- must use lowercased string
buf = Z_StrDup(COM_Argv(0));
strlwr(buf);
lua_getfield(gL, -1, buf); // push command info table
I_Assert(lua_istable(gL, -1));
lua_remove(gL, -2); // pop COM_Command
Z_Free(buf);
lua_rawgeti(gL, -1, 2); // push flags from command info table
if (lua_isboolean(gL, -1))
@ -158,8 +162,13 @@ static void COM_Lua_f(void)
// Wrapper for COM_AddCommand
static int lib_comAddCommand(lua_State *L)
{
boolean exists = false;
const char *name = luaL_checkstring(L, 1);
int com_return = -1;
const char *luaname = luaL_checkstring(L, 1);
// must store in all lowercase
char *name = Z_StrDup(luaname);
strlwr(name);
luaL_checktype(L, 2, LUA_TFUNCTION);
NOHUD
if (lua_gettop(L) >= 3)
@ -177,11 +186,6 @@ static int lib_comAddCommand(lua_State *L)
lua_getfield(L, LUA_REGISTRYINDEX, "COM_Command");
I_Assert(lua_istable(L, -1));
lua_getfield(L, -1, name);
if (!lua_isnil(L, -1))
exists = true;
lua_pop(L, 1);
lua_createtable(L, 2, 0);
lua_pushvalue(L, 2);
lua_rawseti(L, -2, 1);
@ -190,14 +194,23 @@ static int lib_comAddCommand(lua_State *L)
lua_rawseti(L, -2, 2);
lua_setfield(L, -2, name);
// This makes it only add a new command if another
// Lua command by the same name doesn't already exist.
//
// UNFORTUNATELY COM_AddCommand will still cause I_Errors
// if you attempt to override an existing hardcoded command.
//
if (!exists)
COM_AddCommand(name, COM_Lua_f);
// Try to add the Lua command
com_return = COM_AddLuaCommand(name);
if (com_return < 0)
{ // failed to add -- free the lowercased name and return error
Z_Free(name);
return luaL_error(L, "Couldn't add a new console command \"%s\"", luaname);
}
else if (com_return == 1)
{ // command existed already -- free our name as the old string will continue to be used
CONS_Printf("Replaced command \"%s\"\n", name);
Z_Free(name);
}
else
{ // new command was added -- do NOT free the string as it will forever be used by the console
CONS_Printf("Added command \"%s\"\n", name);
}
return 0;
}

View file

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

View file

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

View file

@ -729,6 +729,9 @@ static int mapthing_set(lua_State *L)
static int lib_iterateMapthings(lua_State *L)
{
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.
if (!lua_isnil(L, 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,
const char *def, const char *const lst[]);
// Console wrapper
void COM_Lua_f(void);
#define LUA_Call(L,a)\
{\
if (lua_pcall(L, a, 0, 0)) {\

View file

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

View file

@ -365,7 +365,7 @@ static CV_PossibleValue_t map_cons_t[] = {
{1,"MIN"},
{NUMMAPS, "MAX"}
};
consvar_t cv_nextmap = {"nextmap", "MAP01", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_nextmap = {"nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}};
consvar_t cv_chooseskin = {"chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange, 0, NULL, NULL, 0, 0, NULL};
@ -2338,8 +2338,8 @@ void M_Drawer(void)
{
if (customversionstring[0] != '\0')
{
V_DrawThinString(vid.dupx, BASEVIDHEIGHT - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:");
V_DrawThinString(vid.dupx, BASEVIDHEIGHT - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring);
V_DrawThinString(vid.dupx, vid.height - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:");
V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring);
}
else
#if VERSION > 0 || SUBVERSION > 0

View file

@ -2600,70 +2600,26 @@ void A_MonitorPop(mobj_t *actor)
{
case MT_QUESTIONBOX: // Random!
{
mobjtype_t spawnchance[128];
SINT8 numchoices = 0;
SINT8 target = 0;
mobjtype_t spawnchance[256];
INT32 numchoices = 0, i = 0;
if (cv_superring.value)
{
for (target += (SINT8)cv_superring.value; numchoices < target;)
spawnchance[numchoices++] = MT_SUPERRINGBOX;
}
if (cv_supersneakers.value)
{
for (target += (SINT8)cv_supersneakers.value; numchoices < target;)
spawnchance[numchoices++] = MT_SNEAKERTV;
}
if (cv_invincibility.value)
{
for (target += (SINT8)cv_invincibility.value; numchoices < target;)
spawnchance[numchoices++] = MT_INV;
}
if (cv_jumpshield.value)
{
for (target += (SINT8)cv_jumpshield.value; numchoices < target;)
spawnchance[numchoices++] = MT_WHITETV;
}
if (cv_watershield.value)
{
for (target += (SINT8)cv_watershield.value; numchoices < target;)
spawnchance[numchoices++] = MT_GREENTV;
}
if (cv_ringshield.value)
{
for (target += (SINT8)cv_ringshield.value; numchoices < target;)
spawnchance[numchoices++] = MT_YELLOWTV;
}
if (cv_forceshield.value)
{
for (target += (SINT8)cv_forceshield.value; numchoices < target;)
spawnchance[numchoices++] = MT_BLUETV;
}
if (cv_bombshield.value)
{
for (target += (SINT8)cv_bombshield.value; numchoices < target;)
spawnchance[numchoices++] = MT_BLACKTV;
}
if (cv_1up.value)
{
for (target += (SINT8)cv_1up.value; numchoices < target;)
spawnchance[numchoices++] = MT_PRUP;
}
if (cv_eggmanbox.value)
{
for (target += (SINT8)cv_eggmanbox.value; numchoices < target;)
spawnchance[numchoices++] = MT_EGGMANBOX;
}
if (cv_teleporters.value)
{
for (target += (SINT8)cv_teleporters.value; numchoices < target;)
spawnchance[numchoices++] = MT_MIXUPBOX;
}
if (cv_recycler.value)
{
for (target += (SINT8)cv_recycler.value; numchoices < target;)
spawnchance[numchoices++] = MT_RECYCLETV;
}
#define QUESTIONBOXCHANCES(type, cvar) \
for (i = cvar.value; i; --i) spawnchance[numchoices++] = type
QUESTIONBOXCHANCES(MT_SUPERRINGBOX, cv_superring);
QUESTIONBOXCHANCES(MT_SNEAKERTV, cv_supersneakers);
QUESTIONBOXCHANCES(MT_INV, cv_invincibility);
QUESTIONBOXCHANCES(MT_WHITETV, cv_jumpshield);
QUESTIONBOXCHANCES(MT_GREENTV, cv_watershield);
QUESTIONBOXCHANCES(MT_YELLOWTV, cv_ringshield);
QUESTIONBOXCHANCES(MT_BLUETV, cv_forceshield);
QUESTIONBOXCHANCES(MT_BLACKTV, cv_bombshield);
QUESTIONBOXCHANCES(MT_PRUP, cv_1up);
QUESTIONBOXCHANCES(MT_EGGMANBOX, cv_eggmanbox);
QUESTIONBOXCHANCES(MT_MIXUPBOX, cv_teleporters);
QUESTIONBOXCHANCES(MT_RECYCLETV, cv_recycler);
#undef QUESTIONBOXCHANCES
if (numchoices == 0)
{
@ -3020,7 +2976,7 @@ void A_JumpShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_JUMP)
{
player->powers[pw_shield] = SH_JUMP+(player->powers[pw_shield] & SH_STACK);
player->powers[pw_shield] = SH_JUMP|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
@ -3052,7 +3008,7 @@ void A_RingShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT)
{
player->powers[pw_shield] = SH_ATTRACT+(player->powers[pw_shield] & SH_STACK);
player->powers[pw_shield] = SH_ATTRACT|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
@ -3149,7 +3105,7 @@ void A_SuperSneakers(mobj_t *actor)
actor->target->player->powers[pw_sneakers] = sneakertics + 1;
if (P_IsLocalPlayer(player) && (!player->powers[pw_super]))
if (P_IsLocalPlayer(player) && !player->powers[pw_super])
{
if (S_SpeedMusic(0.0f) && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
S_SpeedMusic(1.4f);
@ -3254,7 +3210,7 @@ void A_BombShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_BOMB)
{
player->powers[pw_shield] = SH_BOMB+(player->powers[pw_shield] & SH_STACK);
player->powers[pw_shield] = SH_BOMB|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
@ -3286,7 +3242,7 @@ void A_WaterShield(mobj_t *actor)
if ((player->powers[pw_shield] & SH_NOSTACK) != SH_ELEMENTAL)
{
player->powers[pw_shield] = SH_ELEMENTAL+(player->powers[pw_shield] & SH_FIREFLOWER);
player->powers[pw_shield] = SH_ELEMENTAL|(player->powers[pw_shield] & SH_STACK);
P_SpawnShieldOrb(player);
}
@ -9847,14 +9803,18 @@ void A_VileAttack(mobj_t *actor)
// Function: A_VileFire
//
// Description: Kind of like A_CapeChase; keeps this object in front of its tracer, unless its target can't see it.
// Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific).
// Originally used by Archviles to keep their hellfire pillars on top of the player, hence the name (although it was just "A_Fire" there; added "Vile" to make it more specific).
// Added some functionality to optionally draw a line directly to the enemy doing the targetting. Y'know, to hammer things in a bit.
//
// var1 = sound to play
// var2 = unused
// var2:
// Lower 16 bits = mobj to spawn (0 doesn't spawn a line at all)
// Upper 16 bits = # to spawn (default is 8)
//
void A_VileFire(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
mobj_t *dest;
#ifdef HAVE_BLUA
@ -9870,10 +9830,10 @@ void A_VileFire(mobj_t *actor)
if (!P_CheckSight(actor->target, dest))
return;
// keep to same scale and gravity as target ALWAYS
actor->destscale = actor->target->scale;
// keep to same scale and gravity as tracer ALWAYS
actor->destscale = dest->scale;
P_SetScale(actor, actor->destscale);
if (actor->target->eflags & MFE_VERTICALFLIP)
if (dest->eflags & MFE_VERTICALFLIP)
{
actor->eflags |= MFE_VERTICALFLIP;
actor->flags2 |= MF2_OBJECTFLIP;
@ -9893,6 +9853,33 @@ void A_VileFire(mobj_t *actor)
// Play sound, if one's specified
if (locvar1 > 0 && locvar1 < NUMSFX)
S_StartSound(actor, (sfxenum_t)locvar1);
// Now draw the line to the actor's target
if (locvar2 & 0xFFFF)
{
mobjtype_t lineMobj;
UINT16 numLineMobjs;
fixed_t distX;
fixed_t distY;
fixed_t distZ;
UINT16 i;
lineMobj = (mobjtype_t)(locvar2 & 0xFFFF);
numLineMobjs = (UINT16)(locvar2 >> 16);
if (numLineMobjs == 0) {
numLineMobjs = 8;
}
// Get distance for each step
distX = (actor->target->x - actor->x) / numLineMobjs;
distY = (actor->target->y - actor->y) / numLineMobjs;
distZ = ((actor->target->z + FixedMul(actor->target->height/2, actor->target->scale)) - (actor->z + FixedMul(actor->height/2, actor->scale))) / numLineMobjs;
for (i = 1; i <= numLineMobjs; i++)
{
P_SpawnMobj(actor->x + (distX * i), actor->y + (distY * i), actor->z + (distZ * i) + FixedMul(actor->height/2, actor->scale), lineMobj);
}
}
}
// Function: A_BrakChase

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_CYBRAKDEMONFLAMEREST, 0, tr_trans50); // Flame
R_SetTrans(S_CYBRAKDEMONTARGETRETICULE1, S_CYBRAKDEMONTARGETRETICULE14, tr_trans50); // Target
R_SetTrans(S_CYBRAKDEMONTARGETDOT, S_CYBRAKDEMONTARGETDOT, tr_trans50); // Target
R_SetTrans(S_FOG1, S_FOG14, tr_trans50);

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

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)
{
mobjtype_t spawnchance[64];
INT32 i = 0;
INT32 oldi = 0;
INT32 increment = 0;
INT32 numchoices = 0;
INT32 numchoices = 0, i = 0;
//if (cv_superring.value)
{
oldi = i;
// This define should make it a lot easier to organize and change monitor weights
#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \
for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 0;
else //weak box
increment = 0;
// Type SRM WRM
SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers
SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility
SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield
SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield
SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield
SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield
SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield
SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters
SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler
SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up
// ======================================
// Total 16 32
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_SUPERRINGBOX;
numchoices++;
}
}
//if (cv_supersneakers.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 0;
else //weak box
increment = 10;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_SNEAKERTV;
numchoices++;
}
}
//if (cv_invincibility.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 4;
else //weak box
increment = 0;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_INV;
numchoices++;
}
}
//if (cv_jumpshield.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 6;
else //weak box
increment = 8;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_WHITETV;
numchoices++;
}
}
//if (cv_watershield.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 6;
else //weak box
increment = 8;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_GREENTV;
numchoices++;
}
}
//if (cv_ringshield.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 4;
else //weak box
increment = 0;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_YELLOWTV;
numchoices++;
}
}
//if (cv_forceshield.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 6;
else //weak box
increment = 3;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_BLUETV;
numchoices++;
}
}
//if (cv_bombshield.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 4;
else //weak box
increment = 0;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_BLACKTV;
numchoices++;
}
}
//if (cv_teleporters.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 0;
else //weak box
increment = 1;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_MIXUPBOX;
numchoices++;
}
}
//if (cv_recycler.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 0;
else //weak box
increment = 1;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_RECYCLETV;
numchoices++;
}
}
//if (cv_1up.value)
{
oldi = i;
if (mobj->flags2 & MF2_STRONGBOX) //strong box
increment = 2;
else //weak box
increment = 1;
for (; i < oldi + increment; i++)
{
spawnchance[i] = MT_PRUP;
numchoices++;
}
}
#undef SETMONITORCHANCES
i = P_RandomKey(numchoices); // Gotta love those random numbers!
newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]);
@ -8342,9 +8190,14 @@ void P_SpawnMapThing(mapthing_t *mthing)
}
}
if (ultimatemode && !G_IsSpecialStage(gamemap)
&& (i == MT_SUPERRINGBOX || i == MT_GREENTV || i == MT_YELLOWTV || i == MT_BLUETV || i == MT_BLACKTV || i == MT_WHITETV))
return; // No rings/shields in Ultimate mode
if (ultimatemode)
{
if (i == MT_PITYTV || i == MT_GREENTV || i == MT_YELLOWTV || i == MT_BLUETV || i == MT_BLACKTV || i == MT_WHITETV)
return; // No shields in Ultimate mode
if (i == MT_SUPERRINGBOX && !G_IsSpecialStage(gamemap))
return; // No rings in Ultimate mode (except special stages)
}
if (i == MT_EMMY && (gametype != GT_COOP || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++)))
return; // you already got this token, or there are too many, or the gametype's not right
@ -8853,27 +8706,36 @@ ML_NOCLIMB : Direction not controllable
mobj->flags2 |= MF2_STANDONME;
}
if (mthing->type != mobjinfo[MT_AXIS].doomednum &&
if (mobj->flags & MF_MONITOR)
{
// flag for strong/weak random boxes
if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum ||
mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum ||
mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum ||
mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum ||
mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum ||
mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum)
mobj->flags |= MF_AMBUSH;
}
else if (mthing->type != mobjinfo[MT_AXIS].doomednum &&
mthing->type != mobjinfo[MT_AXISTRANSFER].doomednum &&
mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum &&
mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum &&
mthing->type != mobjinfo[MT_STARPOST].doomednum &&
mthing->type != mobjinfo[MT_GRAVITYBOX].doomednum &&
mthing->type != mobjinfo[MT_EGGMANBOX].doomednum)
mthing->type != mobjinfo[MT_STARPOST].doomednum)
mobj->flags |= MF_AMBUSH;
}
if (mthing->options & MTF_OBJECTSPECIAL)
{
// flag for strong/weak random boxes
if (mthing->type == mobjinfo[MT_QUESTIONBOX].doomednum || mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum ||
if (mthing->type == mobjinfo[MT_SUPERRINGBOX].doomednum || mthing->type == mobjinfo[MT_PRUP].doomednum ||
mthing->type == mobjinfo[MT_SNEAKERTV].doomednum || mthing->type == mobjinfo[MT_INV].doomednum ||
mthing->type == mobjinfo[MT_WHITETV].doomednum || mthing->type == mobjinfo[MT_GREENTV].doomednum ||
mthing->type == mobjinfo[MT_YELLOWTV].doomednum || mthing->type == mobjinfo[MT_BLUETV].doomednum ||
mthing->type == mobjinfo[MT_RECYCLETV].doomednum ||
mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum ||
mthing->type == mobjinfo[MT_PRUP].doomednum)
mobj->flags2 |= MF2_STRONGBOX;
mthing->type == mobjinfo[MT_BLACKTV].doomednum || mthing->type == mobjinfo[MT_PITYTV].doomednum ||
mthing->type == mobjinfo[MT_RECYCLETV].doomednum || mthing->type == mobjinfo[MT_MIXUPBOX].doomednum)
mobj->flags2 |= MF2_STRONGBOX;
// Requires you to be in bonus time to activate
if (mobj->flags & MF_NIGHTSITEM)

View file

@ -1336,7 +1336,7 @@ static void P_NetArchiveThinkers(void)
if ((mobj->x != mobj->spawnpoint->x << FRACBITS) ||
(mobj->y != mobj->spawnpoint->y << FRACBITS) ||
(mobj->angle != (angle_t)(ANGLE_45 * (mobj->spawnpoint->angle/45))))
(mobj->angle != FixedAngle(mobj->spawnpoint->angle*FRACUNIT)))
diff |= MD_POS;
if (mobj->info->doomednum != mobj->spawnpoint->type)

View file

@ -1135,8 +1135,16 @@ void P_RestoreMusic(player_t *player)
S_ChangeMusic(mus_supers, true);
else if (player->powers[pw_invulnerability] > 1)
S_ChangeMusic((mariomode) ? mus_minvnc : mus_invinc, false);
else if (player->powers[pw_sneakers] > 1)
S_ChangeMusic(mus_shoes, true);
else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super])
{
if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
{
S_SpeedMusic(1.4f);
S_ChangeMusic(mapmusic, true);
}
else
S_ChangeMusic(mus_shoes, true);
}
else
S_ChangeMusic(mapmusic, true);
}
@ -1537,8 +1545,6 @@ static void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
}
P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do
if (demorecording)
G_GhostAddSpin();
}
//
@ -3207,10 +3213,18 @@ static void P_DoSuperStuff(player_t *player)
player->mo->health--;
}
if (player->skin == 2) // Pink superknux.
switch (player->skin)
{
case 1: // Golden orange supertails.
player->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5;
break;
case 2: // Pink superknux.
player->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5;
else // Yousa yellow now!
break;
default: // Yousa yellow now!
player->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5;
break;
}
G_GhostAddColor(GHC_SUPER);
// Ran out of rings while super!
@ -3485,6 +3499,8 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
// Now spawn the color thok circle.
P_SpawnSpinMobj(player, player->revitem);
if (demorecording)
G_GhostAddRev();
}
}
// If not moving up or down, and travelling faster than a speed of four while not holding
@ -4578,12 +4594,9 @@ static void P_3dMovement(player_t *player)
{
movepushside >>= 2;
//Lower speed if over "max" flight speed and greatly reduce movepushslide.
// Reduce movepushslide even more if over "max" flight speed
if (player->powers[pw_tailsfly] && player->speed > topspeed)
{
player->speed = topspeed - 1;
movepushside /= 4;
}
movepushside >>= 2;
}
// Allow a bit of movement while spinning
@ -6525,6 +6538,10 @@ static void P_MovePlayer(player_t *player)
if (player->pflags & PF_GLIDING)
{
fixed_t leeway;
fixed_t glidespeed = player->actionspd;
if (player->powers[pw_super])
glidespeed *= 2;
if (player->mo->eflags & MFE_VERTICALFLIP)
{
@ -6542,7 +6559,7 @@ static void P_MovePlayer(player_t *player)
if (player->skidtime) // ground gliding
{
fixed_t speed = FixedMul(player->actionspd, FRACUNIT - (FRACUNIT>>2));
fixed_t speed = FixedMul(glidespeed, FRACUNIT - (FRACUNIT>>2));
if (player->mo->eflags & MFE_UNDERWATER)
speed >>= 1;
speed = FixedMul(speed - player->glidetime*FRACUNIT, player->mo->scale);
@ -6551,9 +6568,9 @@ static void P_MovePlayer(player_t *player)
P_InstaThrust(player->mo, player->mo->angle-leeway, speed);
}
else if (player->mo->eflags & MFE_UNDERWATER)
P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul((player->actionspd>>1) + player->glidetime*750, player->mo->scale));
P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul((glidespeed>>1) + player->glidetime*750, player->mo->scale));
else
P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul(player->actionspd + player->glidetime*1500, player->mo->scale));
P_InstaThrust(player->mo, player->mo->angle-leeway, FixedMul(glidespeed + player->glidetime*1500, player->mo->scale));
player->glidetime++;
@ -6568,6 +6585,7 @@ static void P_MovePlayer(player_t *player)
}
else
{
player->pflags |= PF_THOKKED;
player->mo->momx >>= 1;
player->mo->momy >>= 1;
P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
@ -6744,7 +6762,11 @@ static void P_MovePlayer(player_t *player)
// Show the "THOK!" graphic when spinning quickly across the ground. (even applies to non-spinners, in the case of zoom tubes)
if (player->pflags & PF_SPINNING && player->speed > FixedMul(15<<FRACBITS, player->mo->scale) && !(player->pflags & PF_JUMPED))
{
P_SpawnSpinMobj(player, player->spinitem);
if (demorecording)
G_GhostAddSpin();
}
////////////////////////////
@ -7481,11 +7503,8 @@ boolean P_LookForEnemies(player_t *player)
continue; // not a mobj thinker
mo = (mobj_t *)think;
if (!(mo->flags & MF_ENEMY || mo->flags & MF_BOSS || mo->flags & MF_MONITOR
|| mo->flags & MF_SPRING))
{
if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)))
continue; // not a valid enemy
}
if (mo->health <= 0) // dead
continue;
@ -7496,14 +7515,14 @@ boolean P_LookForEnemies(player_t *player)
if (mo->flags2 & MF2_FRET)
continue;
if ((mo->flags & MF_ENEMY || mo->flags & MF_BOSS) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus)
if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus)
continue;
if (mo->type == MT_DETON) // Don't be STUPID, Sonic!
continue;
if (((mo->z > player->mo->z+FixedMul(MAXSTEPMOVE, player->mo->scale)) && !(player->mo->eflags & MFE_VERTICALFLIP))
|| ((mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale)) && (player->mo->eflags & MFE_VERTICALFLIP))) // Reverse gravity check - Flame.
|| ((mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale)) && (player->mo->eflags & MFE_VERTICALFLIP))) // Reverse gravity check - Flame.
continue; // Don't home upwards!
if (P_AproxDistance(P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y),
@ -7572,7 +7591,7 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
if (dist < 1)
dist = 1;
if (source->type == MT_DETON && enemy->player) // For Deton Chase
if (source->type == MT_DETON && enemy->player) // For Deton Chase (Unused)
{
fixed_t ns = FixedDiv(FixedMul(enemy->player->normalspeed, enemy->scale), FixedDiv(20*FRACUNIT,17*FRACUNIT));
source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);

View file

@ -376,10 +376,10 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
// Super colors, from lightest to darkest!
case SKINCOLOR_SUPER1:
// Super White
for (i = 0; i < 14; i++)
for (i = 0; i < 10; i++)
dest_colormap[starttranscolor + i] = 120; // True white
for (; i < SKIN_RAMP_LENGTH; i++)
dest_colormap[starttranscolor + i] = 112; // Golden shine
for (; i < SKIN_RAMP_LENGTH; i++) // White-yellow fade
dest_colormap[starttranscolor + i] = (UINT8)(96 + (i-10));
break;
case SKINCOLOR_SUPER2:
@ -422,6 +422,43 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
dest_colormap[starttranscolor + 15] = 155;
break;
// Super Tails
case SKINCOLOR_TSUPER1:
for (i = 0; i < 10; i++) // white
dest_colormap[starttranscolor + i] = 120;
for (; i < SKIN_RAMP_LENGTH; i++) // orange
dest_colormap[starttranscolor + i] = (UINT8)(80 + (i-10));
break;
case SKINCOLOR_TSUPER2:
for (i = 0; i < 4; i++) // white
dest_colormap[starttranscolor + i] = 120;
for (; i < SKIN_RAMP_LENGTH; i++) // orange
dest_colormap[starttranscolor + i] = (UINT8)(80 + ((i-4)>>1));
break;
case SKINCOLOR_TSUPER3:
dest_colormap[starttranscolor] = 120; // pure white
dest_colormap[starttranscolor+1] = 120;
for (i = 2; i < SKIN_RAMP_LENGTH; i++) // orange
dest_colormap[starttranscolor + i] = (UINT8)(80 + ((i-2)>>1));
break;
case SKINCOLOR_TSUPER4:
dest_colormap[starttranscolor] = 120; // pure white
for (i = 1; i < 9; i++) // orange
dest_colormap[starttranscolor + i] = (UINT8)(80 + (i-1));
for (; i < SKIN_RAMP_LENGTH; i++) // gold
dest_colormap[starttranscolor + i] = (UINT8)(115 + (5*(i-9)/7));
break;
case SKINCOLOR_TSUPER5:
for (i = 0; i < 8; i++) // orange
dest_colormap[starttranscolor + i] = (UINT8)(80 + i);
for (; i < SKIN_RAMP_LENGTH; i++) // gold
dest_colormap[starttranscolor + i] = (UINT8)(115 + (5*(i-8)/8));
break;
// Super Knuckles
case SKINCOLOR_KSUPER1:
for (i = 0; i < SKIN_RAMP_LENGTH; i++)

View file

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

View file

@ -191,4 +191,39 @@ void R_InitDrawNodes(void);
char *GetPlayerFacePic(INT32 skinnum);
// Functions to go from sprite character ID to frame number
// for 2.1 compatibility this still uses the old 'A' + frame code
// The use of symbols tends to be painful for wad editors though
// So the future version of this tries to avoid using symbols
// as much as possible while also defining all 64 slots in a sane manner
// 2.1: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ]]
// Future: [[ ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz!@ ]]
FUNCMATH FUNCINLINE static ATTRINLINE char R_Frame2Char(UINT8 frame)
{
#if 1 // 2.1 compat
return 'A' + frame;
#else
if (frame < 26) return 'A' + frame;
if (frame < 36) return '0' + (frame - 26);
if (frame < 62) return 'a' + (frame - 36);
if (frame == 62) return '!';
if (frame == 63) return '@';
return '\xFF';
#endif
}
FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn)
{
#if 1 // 2.1 compat
return cn - 'A';
#else
if (cn >= 'A' && cn <= 'Z') return cn - 'A';
if (cn >= '0' && cn <= '9') return (cn - '0') + 26;
if (cn >= 'a' && cn <= 'z') return (cn - 'a') + 36;
if (cn == '!') return 62;
if (cn == '@') return 63;
return 255;
#endif
}
#endif //__R_THINGS__

View file

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

View file

@ -57,8 +57,8 @@ typedef union
{
struct
{
char passed1[13]; // KNUCKLES GOT
char passed2[16]; // THROUGH THE ACT
char passed1[14]; // KNUCKLES GOT / CRAWLA HONCHO
char passed2[16]; // THROUGH THE ACT / PASSED THE ACT
INT32 passedx1;
INT32 passedx2;
@ -998,43 +998,40 @@ void Y_StartIntermission(void)
usetile = false;
// set up the "got through act" message according to skin name
if (strlen(skins[players[consoleplayer].skin].realname) <= 8)
// too long so just show "YOU GOT THROUGH THE ACT"
if (strlen(skins[players[consoleplayer].skin].realname) > 13)
{
snprintf(data.coop.passed1,
sizeof data.coop.passed1, "%s GOT",
strcpy(data.coop.passed1, "YOU GOT");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT");
}
// long enough that "X GOT" won't fit so use "X PASSED THE ACT"
else if (strlen(skins[players[consoleplayer].skin].realname) > 8)
{
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "PASSED ACT" : "PASSED THE ACT");
}
// length is okay for normal use
else
{
snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s GOT",
skins[players[consoleplayer].skin].realname);
data.coop.passed1[sizeof data.coop.passed1 - 1] = '\0';
if (mapheaderinfo[gamemap-1]->actnum)
{
strcpy(data.coop.passed2, "THROUGH ACT");
data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2;
data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2;
}
else
{
strcpy(data.coop.passed2, "THROUGH THE ACT");
data.coop.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed1))/2;
data.coop.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed2))/2;
}
// The above value is not precalculated because it needs only be computed once
// at the start of intermission, and precalculating it would preclude mods
// changing the font to one of a slightly different width.
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "THROUGH ACT" : "THROUGH THE ACT");
}
// set X positions
if (mapheaderinfo[gamemap-1]->actnum)
{
data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2;
data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2;
}
else
{
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname);
data.coop.passedx1 = 62 + (176 - V_LevelNameWidth(data.coop.passed1))/2;
if (mapheaderinfo[gamemap-1]->actnum)
{
strcpy(data.coop.passed2, "PASSED ACT");
data.coop.passedx2 = 62 + (176 - V_LevelNameWidth(data.coop.passed2))/2;
}
else
{
strcpy(data.coop.passed2, "PASSED THE ACT");
data.coop.passedx2 = 62 + (240 - V_LevelNameWidth(data.coop.passed2))/2;
}
data.coop.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed1))/2;
data.coop.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.coop.passed2))/2;
}
// The above value is not precalculated because it needs only be computed once
// at the start of intermission, and precalculating it would preclude mods
// changing the font to one of a slightly different width.
break;
}