Merge remote-tracking branch 'origin/master' into rotsprite_i

This commit is contained in:
Jaime Passos 2019-09-02 23:36:30 -03:00
commit 1fca5a749e
32 changed files with 831 additions and 810 deletions

View file

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
# DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string. # DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string.
# Version change is fine. # Version change is fine.
project(SRB2 project(SRB2
VERSION 2.1.24 VERSION 2.1.25
LANGUAGES C) LANGUAGES C)
if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})

View file

@ -1,4 +1,4 @@
version: 2.1.24.{branch}-{build} version: 2.1.25.{branch}-{build}
os: MinGW os: MinGW
environment: environment:

View file

@ -24,12 +24,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define APNG_H #define APNG_H
#ifndef _MSC_VER #ifndef _MSC_VER
#ifndef _WII
#ifndef _LARGEFILE64_SOURCE #ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE
#endif #endif
#endif #endif
#endif
#ifndef _LFS64_LARGEFILE #ifndef _LFS64_LARGEFILE
#define _LFS64_LARGEFILE #define _LFS64_LARGEFILE

View file

@ -1666,7 +1666,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (joyaxis_default) if (joyaxis_default)
{ {
#if !defined (_WII) && !defined (WMINPUT)
if (!stricmp(v->name, "joyaxis_turn")) if (!stricmp(v->name, "joyaxis_turn"))
{ {
if (joyaxis_count > 6) return false; if (joyaxis_count > 6) return false;
@ -1676,7 +1675,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "X-Axis")) joyaxis_count++; if (!stricmp(valstr, "X-Axis")) joyaxis_count++;
else joyaxis_default = false; else joyaxis_default = false;
} }
#if !defined (PSP)
if (!stricmp(v->name, "joyaxis_move")) if (!stricmp(v->name, "joyaxis_move"))
{ {
if (joyaxis_count > 6) return false; if (joyaxis_count > 6) return false;
@ -1685,8 +1683,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "Y-Axis")) joyaxis_count++; if (!stricmp(valstr, "Y-Axis")) joyaxis_count++;
else joyaxis_default = false; else joyaxis_default = false;
} }
#endif
#if !defined (_arch_dreamcast) && !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis_side")) if (!stricmp(v->name, "joyaxis_side"))
{ {
if (joyaxis_count > 6) return false; if (joyaxis_count > 6) return false;
@ -1695,8 +1691,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "Z-Axis")) joyaxis_count++; if (!stricmp(valstr, "Z-Axis")) joyaxis_count++;
else joyaxis_default = false; else joyaxis_default = false;
} }
#endif
#if !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis_look")) if (!stricmp(v->name, "joyaxis_look"))
{ {
if (joyaxis_count > 6) return false; if (joyaxis_count > 6) return false;
@ -1705,7 +1699,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "None")) joyaxis_count++; if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false; else joyaxis_default = false;
} }
#endif
if (!stricmp(v->name, "joyaxis_fire") if (!stricmp(v->name, "joyaxis_fire")
|| !stricmp(v->name, "joyaxis_firenormal")) || !stricmp(v->name, "joyaxis_firenormal"))
{ {
@ -1715,7 +1708,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "None")) joyaxis_count++; if (!stricmp(valstr, "None")) joyaxis_count++;
else joyaxis_default = false; else joyaxis_default = false;
} }
#endif
// reset all axis settings to defaults // reset all axis settings to defaults
if (joyaxis_count == 6) if (joyaxis_count == 6)
{ {
@ -1732,7 +1724,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (joyaxis2_default) if (joyaxis2_default)
{ {
#if !defined (_WII) && !defined (WMINPUT)
if (!stricmp(v->name, "joyaxis2_turn")) if (!stricmp(v->name, "joyaxis2_turn"))
{ {
if (joyaxis2_count > 6) return false; if (joyaxis2_count > 6) return false;
@ -1742,7 +1733,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "X-Axis")) joyaxis2_count++; if (!stricmp(valstr, "X-Axis")) joyaxis2_count++;
else joyaxis2_default = false; else joyaxis2_default = false;
} }
// #if !defined (PSP)
if (!stricmp(v->name, "joyaxis2_move")) if (!stricmp(v->name, "joyaxis2_move"))
{ {
if (joyaxis2_count > 6) return false; if (joyaxis2_count > 6) return false;
@ -1751,8 +1741,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "Y-Axis")) joyaxis2_count++; if (!stricmp(valstr, "Y-Axis")) joyaxis2_count++;
else joyaxis2_default = false; else joyaxis2_default = false;
} }
// #endif
#if !defined (_arch_dreamcast) && !defined (_XBOX) && !defined (PSP)
if (!stricmp(v->name, "joyaxis2_side")) if (!stricmp(v->name, "joyaxis2_side"))
{ {
if (joyaxis2_count > 6) return false; if (joyaxis2_count > 6) return false;
@ -1761,8 +1749,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "Z-Axis")) joyaxis2_count++; if (!stricmp(valstr, "Z-Axis")) joyaxis2_count++;
else joyaxis2_default = false; else joyaxis2_default = false;
} }
#endif
#if !defined (_XBOX) // && !defined (PSP)
if (!stricmp(v->name, "joyaxis2_look")) if (!stricmp(v->name, "joyaxis2_look"))
{ {
if (joyaxis2_count > 6) return false; if (joyaxis2_count > 6) return false;
@ -1771,7 +1757,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "None")) joyaxis2_count++; if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false; else joyaxis2_default = false;
} }
#endif
if (!stricmp(v->name, "joyaxis2_fire") if (!stricmp(v->name, "joyaxis2_fire")
|| !stricmp(v->name, "joyaxis2_firenormal")) || !stricmp(v->name, "joyaxis2_firenormal"))
{ {
@ -1781,7 +1766,6 @@ static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr)
if (!stricmp(valstr, "None")) joyaxis2_count++; if (!stricmp(valstr, "None")) joyaxis2_count++;
else joyaxis2_default = false; else joyaxis2_default = false;
} }
#endif
// reset all axis settings to defaults // reset all axis settings to defaults
if (joyaxis2_count == 6) if (joyaxis2_count == 6)

View file

@ -42,6 +42,7 @@
#include "lzf.h" #include "lzf.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "md5.h"
#ifdef CLIENT_LOADINGSCREEN #ifdef CLIENT_LOADINGSCREEN
// cl loading screen // cl loading screen
@ -110,6 +111,9 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p
static UINT8 player_joining = false; static UINT8 player_joining = false;
UINT8 hu_resynching = 0; UINT8 hu_resynching = 0;
UINT8 adminpassmd5[16];
boolean adminpasswordset = false;
// Client specific // Client specific
static ticcmd_t localcmds; static ticcmd_t localcmds;
static ticcmd_t localcmds2; static ticcmd_t localcmds2;
@ -509,6 +513,10 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->currentweapon = LONG(players[i].currentweapon); rsp->currentweapon = LONG(players[i].currentweapon);
rsp->ringweapons = LONG(players[i].ringweapons); rsp->ringweapons = LONG(players[i].ringweapons);
rsp->ammoremoval = (UINT16)SHORT(players[i].ammoremoval);
rsp->ammoremovaltimer = (tic_t)LONG(players[i].ammoremovaltimer);
rsp->ammoremovalweapon = LONG(players[i].ammoremovalweapon);
for (j = 0; j < NUMPOWERS; ++j) for (j = 0; j < NUMPOWERS; ++j)
rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]);
@ -640,6 +648,10 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].currentweapon = LONG(rsp->currentweapon); players[i].currentweapon = LONG(rsp->currentweapon);
players[i].ringweapons = LONG(rsp->ringweapons); players[i].ringweapons = LONG(rsp->ringweapons);
players[i].ammoremoval = (UINT16)SHORT(rsp->ammoremoval);
players[i].ammoremovaltimer = (tic_t)LONG(rsp->ammoremovaltimer);
players[i].ammoremovalweapon = LONG(rsp->ammoremovalweapon);
for (j = 0; j < NUMPOWERS; ++j) for (j = 0; j < NUMPOWERS; ++j)
players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]);
@ -3784,6 +3796,7 @@ static void HandlePacketFromPlayer(SINT8 node)
INT32 netconsole; INT32 netconsole;
tic_t realend, realstart; tic_t realend, realstart;
UINT8 *pak, *txtpak, numtxtpak; UINT8 *pak, *txtpak, numtxtpak;
UINT8 finalmd5[16];/* Well, it's the cool thing to do? */
txtpak = NULL; txtpak = NULL;
@ -3981,6 +3994,32 @@ static void HandlePacketFromPlayer(SINT8 node)
textcmd[0] += (UINT8)netbuffer->u.textcmd[0]; textcmd[0] += (UINT8)netbuffer->u.textcmd[0];
} }
break; break;
case PT_LOGIN:
if (client)
break;
#ifndef NOMD5
if (doomcom->datalength < 16)/* ignore partial sends */
break;
if (!adminpasswordset)
{
CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[netconsole]);
break;
}
// Do the final pass to compare with the sent md5
D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", netconsole), &finalmd5);
if (!memcmp(netbuffer->u.md5sum, finalmd5, 16))
{
CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[netconsole]);
COM_BufInsertText(va("promote %d\n", netconsole)); // do this immediately
}
else
CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[netconsole]);
#endif
break;
case PT_NODETIMEOUT: case PT_NODETIMEOUT:
case PT_CLIENTQUIT: case PT_CLIENTQUIT:
if (client) if (client)
@ -4858,3 +4897,29 @@ tic_t GetLag(INT32 node)
{ {
return gametic - nettics[node]; return gametic - nettics[node];
} }
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest)
{
#ifdef NOMD5
(void)buffer;
(void)len;
(void)salt;
memset(dest, 0, 16);
#else
char tmpbuf[256];
const size_t sl = strlen(salt);
if (len > 256-sl)
len = 256-sl;
memcpy(tmpbuf, buffer, len);
memmove(&tmpbuf[len], salt, sl);
//strcpy(&tmpbuf[len], salt);
len += strlen(salt);
if (len < 256)
memset(&tmpbuf[len],0,256-len);
// Yes, we intentionally md5 the ENTIRE buffer regardless of size...
md5_buffer(tmpbuf, 256, dest);
#endif
}

View file

@ -70,6 +70,9 @@ typedef enum
PT_NODETIMEOUT, // Packet sent to self if the connection times out. PT_NODETIMEOUT, // Packet sent to self if the connection times out.
PT_RESYNCHING, // Packet sent to resync players. PT_RESYNCHING, // Packet sent to resync players.
// Blocks game advance until synched. // Blocks game advance until synched.
PT_LOGIN, // Login attempt from the client.
#ifdef NEWPING #ifdef NEWPING
PT_PING, // Packet sent to tell clients the other client's latency to server. PT_PING, // Packet sent to tell clients the other client's latency to server.
#endif #endif
@ -161,6 +164,9 @@ typedef struct
angle_t aiming; angle_t aiming;
INT32 currentweapon; INT32 currentweapon;
INT32 ringweapons; INT32 ringweapons;
UINT16 ammoremoval;
tic_t ammoremovaltimer;
INT32 ammoremovalweapon;
UINT16 powers[NUMPOWERS]; UINT16 powers[NUMPOWERS];
// Score is resynched in the confirm resync packet // Score is resynched in the confirm resync packet
@ -407,6 +413,7 @@ typedef struct
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
filetx_pak filetxpak; // 139 bytes filetx_pak filetxpak; // 139 bytes
clientconfig_pak clientcfg; // 136 bytes clientconfig_pak clientcfg; // 136 bytes
UINT8 md5sum[16];
serverinfo_pak serverinfo; // 1024 bytes serverinfo_pak serverinfo; // 1024 bytes
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
askinfo_pak askinfo; // 61 bytes askinfo_pak askinfo; // 61 bytes
@ -535,5 +542,10 @@ void D_ResetTiccmds(void);
tic_t GetLag(INT32 node); tic_t GetLag(INT32 node);
UINT8 GetFreeXCmdSize(void); UINT8 GetFreeXCmdSize(void);
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
extern UINT8 hu_resynching; extern UINT8 hu_resynching;
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
#endif #endif

View file

@ -34,18 +34,19 @@
#include "p_spec.h" #include "p_spec.h"
#include "m_cheat.h" #include "m_cheat.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "d_net.h"
#include "v_video.h" #include "v_video.h"
#include "d_main.h" #include "d_main.h"
#include "m_random.h" #include "m_random.h"
#include "f_finale.h" #include "f_finale.h"
#include "filesrch.h" #include "filesrch.h"
#include "mserv.h" #include "mserv.h"
#include "md5.h"
#include "z_zone.h" #include "z_zone.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "m_cond.h" #include "m_cond.h"
#include "m_anigif.h" #include "m_anigif.h"
#include "md5.h"
#ifdef NETGAME_DEVMODE #ifdef NETGAME_DEVMODE
#define CV_RESTRICT CV_NETVAR #define CV_RESTRICT CV_NETVAR
@ -140,7 +141,6 @@ static void Command_Clearscores_f(void);
// Remote Administration // Remote Administration
static void Command_Changepassword_f(void); static void Command_Changepassword_f(void);
static void Command_Login_f(void); static void Command_Login_f(void);
static void Got_Login(UINT8 **cp, INT32 playernum);
static void Got_Verification(UINT8 **cp, INT32 playernum); static void Got_Verification(UINT8 **cp, INT32 playernum);
static void Got_Removal(UINT8 **cp, INT32 playernum); static void Got_Removal(UINT8 **cp, INT32 playernum);
static void Command_Verify_f(void); static void Command_Verify_f(void);
@ -435,7 +435,6 @@ void D_RegisterServerCommands(void)
// Remote Administration // Remote Administration
COM_AddCommand("password", Command_Changepassword_f); COM_AddCommand("password", Command_Changepassword_f);
RegisterNetXCmd(XD_LOGIN, Got_Login);
COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin COM_AddCommand("login", Command_Login_f); // useful in dedicated to kick off remote admin
COM_AddCommand("promote", Command_Verify_f); COM_AddCommand("promote", Command_Verify_f);
RegisterNetXCmd(XD_VERIFIED, Got_Verification); RegisterNetXCmd(XD_VERIFIED, Got_Verification);
@ -599,6 +598,11 @@ void D_RegisterClientCommands(void)
Color_cons_t[MAXSKINCOLORS].value = 0; Color_cons_t[MAXSKINCOLORS].value = 0;
Color_cons_t[MAXSKINCOLORS].strvalue = NULL; Color_cons_t[MAXSKINCOLORS].strvalue = NULL;
// Set default player names
// Monster Iestyn (12/08/19): not sure where else I could have actually put this, but oh well
for (i = 0; i < MAXPLAYERS; i++)
sprintf(player_names[i], "Player %d", i);
if (dedicated) if (dedicated)
return; return;
@ -2719,35 +2723,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
// Attempts to make password system a little sane without // Attempts to make password system a little sane without
// rewriting the entire goddamn XD_file system // rewriting the entire goddamn XD_file system
// //
#include "md5.h"
static void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest)
{
#ifdef NOMD5
(void)buffer;
(void)len;
(void)salt;
memset(dest, 0, 16);
#else
char tmpbuf[256];
const size_t sl = strlen(salt);
if (len > 256-sl)
len = 256-sl;
memcpy(tmpbuf, buffer, len);
memmove(&tmpbuf[len], salt, sl);
//strcpy(&tmpbuf[len], salt);
len += strlen(salt);
if (len < 256)
memset(&tmpbuf[len],0,256-len);
// Yes, we intentionally md5 the ENTIRE buffer regardless of size...
md5_buffer(tmpbuf, 256, dest);
#endif
}
#define BASESALT "basepasswordstorage" #define BASESALT "basepasswordstorage"
static UINT8 adminpassmd5[16];
static boolean adminpasswordset = false;
void D_SetPassword(const char *pw) void D_SetPassword(const char *pw)
{ {
@ -2785,7 +2761,6 @@ static void Command_Login_f(void)
// If we have no MD5 support then completely disable XD_LOGIN responses for security. // If we have no MD5 support then completely disable XD_LOGIN responses for security.
CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n"); CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
#else #else
UINT8 finalmd5[16];
const char *pw; const char *pw;
if (!netgame) if (!netgame)
@ -2805,47 +2780,15 @@ static void Command_Login_f(void)
pw = COM_Argv(1); pw = COM_Argv(1);
// Do the base pass to get what the server has (or should?) // Do the base pass to get what the server has (or should?)
D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &finalmd5); D_MD5PasswordPass((const UINT8 *)pw, strlen(pw), BASESALT, &netbuffer->u.md5sum);
// Do the final pass to get the comparison the server will come up with // Do the final pass to get the comparison the server will come up with
D_MD5PasswordPass(finalmd5, 16, va("PNUM%02d", consoleplayer), &finalmd5); D_MD5PasswordPass(netbuffer->u.md5sum, 16, va("PNUM%02d", consoleplayer), &netbuffer->u.md5sum);
CONS_Printf(M_GetText("Sending login... (Notice only given if password is correct.)\n")); CONS_Printf(M_GetText("Sending login... (Notice only given if password is correct.)\n"));
SendNetXCmd(XD_LOGIN, finalmd5, 16); netbuffer->packettype = PT_LOGIN;
#endif HSendPacket(servernode, true, 0, 16);
}
static void Got_Login(UINT8 **cp, INT32 playernum)
{
#ifdef NOMD5
// If we have no MD5 support then completely disable XD_LOGIN responses for security.
(void)cp;
(void)playernum;
#else
UINT8 sentmd5[16], finalmd5[16];
READMEM(*cp, sentmd5, 16);
if (client)
return;
if (!adminpasswordset)
{
CONS_Printf(M_GetText("Password from %s failed (no password set).\n"), player_names[playernum]);
return;
}
// Do the final pass to compare with the sent md5
D_MD5PasswordPass(adminpassmd5, 16, va("PNUM%02d", playernum), &finalmd5);
if (!memcmp(sentmd5, finalmd5, 16))
{
CONS_Printf(M_GetText("%s passed authentication.\n"), player_names[playernum]);
COM_BufInsertText(va("promote %d\n", playernum)); // do this immediately
}
else
CONS_Printf(M_GetText("Password from %s failed.\n"), player_names[playernum]);
#endif #endif
} }

View file

@ -129,8 +129,8 @@ typedef enum
XD_ADDPLAYER, // 10 XD_ADDPLAYER, // 10
XD_TEAMCHANGE, // 11 XD_TEAMCHANGE, // 11
XD_CLEARSCORES, // 12 XD_CLEARSCORES, // 12
XD_LOGIN, // 13 // UNUSED 13 (Because I don't want to change these comments)
XD_VERIFIED, // 14 XD_VERIFIED = 14,//14
XD_RANDOMSEED, // 15 XD_RANDOMSEED, // 15
XD_RUNSOC, // 16 XD_RUNSOC, // 16
XD_REQADDFILE, // 17 XD_REQADDFILE, // 17

View file

@ -745,9 +745,12 @@ void Got_Filetxpak(void)
{ {
INT32 filenum = netbuffer->u.filetxpak.fileid; INT32 filenum = netbuffer->u.filetxpak.fileid;
fileneeded_t *file = &fileneeded[filenum]; fileneeded_t *file = &fileneeded[filenum];
char *filename = file->filename; char *filename;
static INT32 filetime = 0; static INT32 filetime = 0;
filename = va("%s", file->filename);
nameonly(filename);
if (!(strcmp(filename, "srb2.pk3") if (!(strcmp(filename, "srb2.pk3")
&& strcmp(filename, "srb2.srb") && strcmp(filename, "srb2.srb")
&& strcmp(filename, "srb2.wad") && strcmp(filename, "srb2.wad")
@ -758,6 +761,8 @@ void Got_Filetxpak(void)
)) ))
I_Error("Tried to download \"%s\"", filename); I_Error("Tried to download \"%s\"", filename);
filename = file->filename;
if (filenum >= fileneedednum) if (filenum >= fileneedednum)
{ {
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum)); DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));

View file

@ -333,6 +333,10 @@ typedef struct player_s
INT32 currentweapon; // current weapon selected. INT32 currentweapon; // current weapon selected.
INT32 ringweapons; // weapons currently obtained. INT32 ringweapons; // weapons currently obtained.
UINT16 ammoremoval; // amount of ammo removed for the current weapon.
tic_t ammoremovaltimer; // flashing counter for ammo used.
INT32 ammoremovalweapon; // weapon from which the ammo was removed.
// Power ups. invinc and invis are tic counters. // Power ups. invinc and invis are tic counters.
UINT16 powers[NUMPOWERS]; UINT16 powers[NUMPOWERS];

View file

@ -3352,6 +3352,10 @@ static void readmaincfg(MYFILE *f)
{ {
gameovertics = get_number(word2); gameovertics = get_number(word2);
} }
else if (fastcmp(word, "AMMOREMOVALTICS"))
{
ammoremovaltics = get_number(word2);
}
else if (fastcmp(word, "INTROTOPLAY")) else if (fastcmp(word, "INTROTOPLAY"))
{ {
introtoplay = (UINT8)get_number(word2); introtoplay = (UINT8)get_number(word2);
@ -4621,25 +4625,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE_PANIC5", "S_EGGMOBILE_PANIC5",
"S_EGGMOBILE_PANIC6", "S_EGGMOBILE_PANIC6",
"S_EGGMOBILE_PANIC7", "S_EGGMOBILE_PANIC7",
"S_EGGMOBILE_PANIC8",
"S_EGGMOBILE_PANIC9",
"S_EGGMOBILE_PANIC10",
"S_EGGMOBILE_PAIN", "S_EGGMOBILE_PAIN",
"S_EGGMOBILE_PAIN2", "S_EGGMOBILE_PAIN2",
"S_EGGMOBILE_DIE1", "S_EGGMOBILE_DIE1",
"S_EGGMOBILE_DIE2", "S_EGGMOBILE_DIE2",
"S_EGGMOBILE_DIE3", "S_EGGMOBILE_DIE3",
"S_EGGMOBILE_DIE4", "S_EGGMOBILE_DIE4",
"S_EGGMOBILE_DIE5",
"S_EGGMOBILE_DIE6",
"S_EGGMOBILE_DIE7",
"S_EGGMOBILE_DIE8",
"S_EGGMOBILE_DIE9",
"S_EGGMOBILE_DIE10",
"S_EGGMOBILE_DIE11",
"S_EGGMOBILE_DIE12",
"S_EGGMOBILE_DIE13",
"S_EGGMOBILE_DIE14",
"S_EGGMOBILE_FLEE1", "S_EGGMOBILE_FLEE1",
"S_EGGMOBILE_FLEE2", "S_EGGMOBILE_FLEE2",
"S_EGGMOBILE_BALL", "S_EGGMOBILE_BALL",
@ -4660,16 +4651,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE2_DIE2", "S_EGGMOBILE2_DIE2",
"S_EGGMOBILE2_DIE3", "S_EGGMOBILE2_DIE3",
"S_EGGMOBILE2_DIE4", "S_EGGMOBILE2_DIE4",
"S_EGGMOBILE2_DIE5",
"S_EGGMOBILE2_DIE6",
"S_EGGMOBILE2_DIE7",
"S_EGGMOBILE2_DIE8",
"S_EGGMOBILE2_DIE9",
"S_EGGMOBILE2_DIE10",
"S_EGGMOBILE2_DIE11",
"S_EGGMOBILE2_DIE12",
"S_EGGMOBILE2_DIE13",
"S_EGGMOBILE2_DIE14",
"S_EGGMOBILE2_FLEE1", "S_EGGMOBILE2_FLEE1",
"S_EGGMOBILE2_FLEE2", "S_EGGMOBILE2_FLEE2",
@ -4719,16 +4700,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE3_DIE2", "S_EGGMOBILE3_DIE2",
"S_EGGMOBILE3_DIE3", "S_EGGMOBILE3_DIE3",
"S_EGGMOBILE3_DIE4", "S_EGGMOBILE3_DIE4",
"S_EGGMOBILE3_DIE5",
"S_EGGMOBILE3_DIE6",
"S_EGGMOBILE3_DIE7",
"S_EGGMOBILE3_DIE8",
"S_EGGMOBILE3_DIE9",
"S_EGGMOBILE3_DIE10",
"S_EGGMOBILE3_DIE11",
"S_EGGMOBILE3_DIE12",
"S_EGGMOBILE3_DIE13",
"S_EGGMOBILE3_DIE14",
"S_EGGMOBILE3_FLEE1", "S_EGGMOBILE3_FLEE1",
"S_EGGMOBILE3_FLEE2", "S_EGGMOBILE3_FLEE2",
@ -4775,16 +4746,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE4_DIE2", "S_EGGMOBILE4_DIE2",
"S_EGGMOBILE4_DIE3", "S_EGGMOBILE4_DIE3",
"S_EGGMOBILE4_DIE4", "S_EGGMOBILE4_DIE4",
"S_EGGMOBILE4_DIE5",
"S_EGGMOBILE4_DIE6",
"S_EGGMOBILE4_DIE7",
"S_EGGMOBILE4_DIE8",
"S_EGGMOBILE4_DIE9",
"S_EGGMOBILE4_DIE10",
"S_EGGMOBILE4_DIE11",
"S_EGGMOBILE4_DIE12",
"S_EGGMOBILE4_DIE13",
"S_EGGMOBILE4_DIE14",
"S_EGGMOBILE4_FLEE1", "S_EGGMOBILE4_FLEE1",
"S_EGGMOBILE4_FLEE2", "S_EGGMOBILE4_FLEE2",
"S_EGGMOBILE4_MACE", "S_EGGMOBILE4_MACE",
@ -4840,6 +4801,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FANG_FIRE3", "S_FANG_FIRE3",
"S_FANG_FIRE4", "S_FANG_FIRE4",
"S_FANG_FIREREPEAT", "S_FANG_FIREREPEAT",
"S_FANG_LOBSHOT0",
"S_FANG_LOBSHOT1", "S_FANG_LOBSHOT1",
"S_FANG_LOBSHOT2", "S_FANG_LOBSHOT2",
"S_FANG_WAIT1", "S_FANG_WAIT1",
@ -4856,6 +4818,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FANG_PINCHFALL2", "S_FANG_PINCHFALL2",
"S_FANG_PINCHSKID1", "S_FANG_PINCHSKID1",
"S_FANG_PINCHSKID2", "S_FANG_PINCHSKID2",
"S_FANG_PINCHLOBSHOT0",
"S_FANG_PINCHLOBSHOT1", "S_FANG_PINCHLOBSHOT1",
"S_FANG_PINCHLOBSHOT2", "S_FANG_PINCHLOBSHOT2",
"S_FANG_PINCHLOBSHOT3", "S_FANG_PINCHLOBSHOT3",
@ -5161,8 +5124,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_METALSONIC_DEATH4", "S_METALSONIC_DEATH4",
"S_METALSONIC_FLEE1", "S_METALSONIC_FLEE1",
"S_METALSONIC_FLEE2", "S_METALSONIC_FLEE2",
"S_METALSONIC_FLEE3",
"S_METALSONIC_FLEE4",
"S_MSSHIELD_F1", "S_MSSHIELD_F1",
"S_MSSHIELD_F2", "S_MSSHIELD_F2",

View file

@ -210,7 +210,7 @@ typedef struct
extern const UINT8 Color_Index[MAXTRANSLATIONS-1][16]; extern const UINT8 Color_Index[MAXTRANSLATIONS-1][16];
extern const char *Color_Names[MAXSKINCOLORS + NUMSUPERCOLORS]; extern const char *Color_Names[MAXSKINCOLORS + NUMSUPERCOLORS];
extern const UINT8 Color_Opposite[(MAXSKINCOLORS - 1)*2]; extern const UINT8 Color_Opposite[MAXSKINCOLORS - 1][2];
#define NUMMAPS 1035 #define NUMMAPS 1035

View file

@ -206,7 +206,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 28 #define MODVERSION 30
// To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically.
// Increment MINOREXECVERSION whenever a config change is needed that does not correspond // Increment MINOREXECVERSION whenever a config change is needed that does not correspond

View file

@ -217,6 +217,8 @@ UINT16 nightslinktics = 2*TICRATE;
INT32 gameovertics = 15*TICRATE; INT32 gameovertics = 15*TICRATE;
UINT8 ammoremovaltics = 2*TICRATE;
UINT8 use1upSound = 0; UINT8 use1upSound = 0;
UINT8 maxXtraLife = 2; // Max extra lives from rings UINT8 maxXtraLife = 2; // Max extra lives from rings
@ -416,49 +418,13 @@ consvar_t cv_spinaxis2 = {"joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
#if MAXPLAYERS > 32
#error "please update player_name table using the new value for MAXPLAYERS"
#endif
#ifdef SEENAMES #ifdef SEENAMES
player_t *seenplayer; // player we're aiming at right now player_t *seenplayer; // player we're aiming at right now
#endif #endif
char player_names[MAXPLAYERS][MAXPLAYERNAME+1] = // now automatically allocated in D_RegisterClientCommands
{ // so that it doesn't have to be updated depending on the value of MAXPLAYERS
"Player 1", char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
"Player 2",
"Player 3",
"Player 4",
"Player 5",
"Player 6",
"Player 7",
"Player 8",
"Player 9",
"Player 10",
"Player 11",
"Player 12",
"Player 13",
"Player 14",
"Player 15",
"Player 16",
"Player 17",
"Player 18",
"Player 19",
"Player 20",
"Player 21",
"Player 22",
"Player 23",
"Player 24",
"Player 25",
"Player 26",
"Player 27",
"Player 28",
"Player 29",
"Player 30",
"Player 31",
"Player 32"
};
INT16 rw_maximums[NUM_WEAPONS] = INT16 rw_maximums[NUM_WEAPONS] =
{ {
@ -3321,9 +3287,11 @@ void G_LoadGameSettings(void)
{ {
// defaults // defaults
spstage_start = 1; spstage_start = 1;
sstage_start = smpstage_start = 50; sstage_start = 50;
sstage_end = smpstage_end = 56; // 7 special stages in vanilla SRB2 sstage_end = 56; // 7 special stages in vanilla SRB2
sstage_end++; // plus one weirdo sstage_end++; // plus one weirdo
smpstage_start = 60;
smpstage_end = 66; // 7 multiplayer special stages too
// initialize free sfx slots for skin sounds // initialize free sfx slots for skin sounds
S_InitRuntimeSounds(); S_InitRuntimeSounds();

View file

@ -51,6 +51,7 @@ extern tic_t levelstarttic;
// for modding? // for modding?
extern INT16 prevmap, nextmap; extern INT16 prevmap, nextmap;
extern INT32 gameovertics; extern INT32 gameovertics;
extern UINT8 ammoremovaltics;
extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
extern INT16 rw_maximums[NUM_WEAPONS]; extern INT16 rw_maximums[NUM_WEAPONS];
extern INT32 pausedelay; extern INT32 pausedelay;

View file

@ -1043,8 +1043,8 @@ state_t states[NUMSTATES] =
{SPR_CBFS, 7, 1, {A_FaceStabHurl}, 6, S_FACESTABBER_CHARGE4, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE3 {SPR_CBFS, 7, 1, {A_FaceStabHurl}, 6, S_FACESTABBER_CHARGE4, S_FACESTABBER_CHARGE3}, // S_FACESTABBER_CHARGE3
{SPR_CBFS, 7, 1, {A_FaceStabMiss}, 0, S_FACESTABBER_STND1, S_FACESTABBER_CHARGE4}, // S_FACESTABBER_CHARGE4 {SPR_CBFS, 7, 1, {A_FaceStabMiss}, 0, S_FACESTABBER_STND1, S_FACESTABBER_CHARGE4}, // S_FACESTABBER_CHARGE4
{SPR_CBFS, 0, 35, {A_Pain}, 0, 0, S_FACESTABBER_STND1}, // S_FACESTABBER_PAIN {SPR_CBFS, 0, 35, {A_Pain}, 0, 0, S_FACESTABBER_STND1}, // S_FACESTABBER_PAIN
{SPR_CBFS, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE2}, // S_FACESTABBER_DIE1 {SPR_CBFS, 0, 2, {A_BossScream}, 1, 0, S_FACESTABBER_DIE2}, // S_FACESTABBER_DIE1
{SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_FACESTABBER_DIE3}, // S_FACESTABBER_DIE2 {SPR_NULL, 0, 2, {A_BossScream}, 1, 0, S_FACESTABBER_DIE3}, // S_FACESTABBER_DIE2
{SPR_NULL, 0, 0, {A_Repeat}, 7, S_FACESTABBER_DIE1, S_XPLD_FLICKY}, // S_FACESTABBER_DIE3 {SPR_NULL, 0, 0, {A_Repeat}, 7, S_FACESTABBER_DIE1, S_XPLD_FLICKY}, // S_FACESTABBER_DIE3
{SPR_STAB, FF_PAPERSPRITE|FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSPEAR {SPR_STAB, FF_PAPERSPRITE|FF_TRANS50|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_FACESTABBERSPEAR
@ -1205,33 +1205,20 @@ state_t states[NUMSTATES] =
{SPR_EGGM, 19, 10, {NULL}, 0, 0, S_EGGMOBILE_RATK10}, // S_EGGMOBILE_RATK9 {SPR_EGGM, 19, 10, {NULL}, 0, 0, S_EGGMOBILE_RATK10}, // S_EGGMOBILE_RATK9
{SPR_EGGM, 20, 2, {NULL}, 0, 0, S_EGGMOBILE_STND}, // S_EGGMOBILE_RATK10 {SPR_EGGM, 20, 2, {NULL}, 0, 0, S_EGGMOBILE_STND}, // S_EGGMOBILE_RATK10
{SPR_EGGM, 3, 12, {NULL}, 0, 0, S_EGGMOBILE_PANIC2}, // S_EGGMOBILE_PANIC1 {SPR_EGGM, 3, 12, {NULL}, 0, 0, S_EGGMOBILE_PANIC2}, // S_EGGMOBILE_PANIC1
{SPR_EGGM, 4, 4, {A_Boss1Spikeballs}, 0, 4, S_EGGMOBILE_PANIC3}, // S_EGGMOBILE_PANIC2 {SPR_EGGM, 4, 45, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC3}, // S_EGGMOBILE_PANIC2
{SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC4}, // S_EGGMOBILE_PANIC3 {SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC4}, // S_EGGMOBILE_PANIC3
{SPR_EGGM, 4, 4, {A_Boss1Spikeballs}, 1, 4, S_EGGMOBILE_PANIC5}, // S_EGGMOBILE_PANIC4 {SPR_EGGM, 4, 45, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC5 }, // S_EGGMOBILE_PANIC4
{SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC6}, // S_EGGMOBILE_PANIC5 {SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC6}, // S_EGGMOBILE_PANIC5
{SPR_EGGM, 4, 4, {A_Boss1Spikeballs}, 2, 4, S_EGGMOBILE_PANIC7}, // S_EGGMOBILE_PANIC6 {SPR_EGGM, 4, 45, {A_Boss1Laser}, MT_LASER, 2, S_EGGMOBILE_PANIC7 }, // S_EGGMOBILE_PANIC6
{SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC8}, // S_EGGMOBILE_PANIC7 {SPR_EGGM, 0, 35, {NULL}, 0, 0, S_EGGMOBILE_STND }, // S_EGGMOBILE_PANIC7
{SPR_EGGM, 4, 4, {A_Boss1Spikeballs}, 3, 4, S_EGGMOBILE_PANIC9}, // S_EGGMOBILE_PANIC8
{SPR_EGGM, 3, 8, {NULL}, 0, 0, S_EGGMOBILE_PANIC10},// S_EGGMOBILE_PANIC9
{SPR_EGGM, 0, 35, {A_SkullAttack}, 0, 0, S_EGGMOBILE_STND}, // S_EGGMOBILE_PANIC10
{SPR_EGGM, 21, 24, {A_Pain}, 0, 0, S_EGGMOBILE_PAIN2}, // S_EGGMOBILE_PAIN {SPR_EGGM, 21, 24, {A_Pain}, 0, 0, S_EGGMOBILE_PAIN2}, // S_EGGMOBILE_PAIN
{SPR_EGGM, 21, 16, {A_SkullAttack}, 1, 1, S_EGGMOBILE_STND}, // S_EGGMOBILE_PAIN2 {SPR_EGGM, 21, 16, {A_SkullAttack}, 1, 1, S_EGGMOBILE_STND}, // S_EGGMOBILE_PAIN2
{SPR_EGGM, 22, 8, {A_Fall}, 0, 0, S_EGGMOBILE_DIE2}, // S_EGGMOBILE_DIE1 {SPR_EGGM, 22, 2, {A_Fall}, 0, 0, S_EGGMOBILE_DIE2}, // S_EGGMOBILE_DIE1
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE3}, // S_EGGMOBILE_DIE2 {SPR_EGGM, 22, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE3}, // S_EGGMOBILE_DIE2
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE4}, // S_EGGMOBILE_DIE3 {SPR_EGGM, 22, 0, {A_Repeat}, 17, S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE4}, // S_EGGMOBILE_DIE3
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE5}, // S_EGGMOBILE_DIE4 {SPR_EGGM, 22, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE_DIE4
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE6}, // S_EGGMOBILE_DIE5 {SPR_EGGM, 23, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_FLEE2}, // S_EGGMOBILE_FLEE1
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE7}, // S_EGGMOBILE_DIE6 {SPR_EGGM, 24, 2, {A_BossScream}, 0, 0, S_EGGMOBILE_FLEE1}, // S_EGGMOBILE_FLEE2
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE8}, // S_EGGMOBILE_DIE7
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE9}, // S_EGGMOBILE_DIE8
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE10}, // S_EGGMOBILE_DIE9
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE11}, // S_EGGMOBILE_DIE10
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE12}, // S_EGGMOBILE_DIE11
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE13}, // S_EGGMOBILE_DIE12
{SPR_EGGM, 22, 8, {A_BossScream}, 0, 0, S_EGGMOBILE_DIE14}, // S_EGGMOBILE_DIE13
{SPR_EGGM, 22, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE_DIE14
{SPR_EGGM, 23, 5, {NULL}, 0, 0, S_EGGMOBILE_FLEE2}, // S_EGGMOBILE_FLEE1
{SPR_EGGM, 24, 5, {NULL}, 0, 0, S_EGGMOBILE_FLEE1}, // S_EGGMOBILE_FLEE2
{SPR_UNID, 1, 1, {A_UnidusBall}, 2, 0, S_EGGMOBILE_BALL}, // S_EGGMOBILE_BALL {SPR_UNID, 1, 1, {A_UnidusBall}, 2, 0, S_EGGMOBILE_BALL}, // S_EGGMOBILE_BALL
{SPR_NULL, 0, 1, {A_FocusTarget}, 0, 0, S_EGGMOBILE_TARGET}, // S_EGGMOBILE_TARGET {SPR_NULL, 0, 1, {A_FocusTarget}, 0, 0, S_EGGMOBILE_TARGET}, // S_EGGMOBILE_TARGET
@ -1246,22 +1233,12 @@ state_t states[NUMSTATES] =
{SPR_EGGN, 1, 2, {NULL}, 0, 0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_POGO7 {SPR_EGGN, 1, 2, {NULL}, 0, 0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_POGO7
{SPR_EGGN, 3, 24, {A_Boss2TakeDamage}, 24+TICRATE, 0, S_EGGMOBILE2_STND}, // S_EGGMOBILE2_PAIN {SPR_EGGN, 3, 24, {A_Boss2TakeDamage}, 24+TICRATE, 0, S_EGGMOBILE2_STND}, // S_EGGMOBILE2_PAIN
{SPR_EGGN, 4, 24, {A_Boss2TakeDamage}, 24+TICRATE, 0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_PAIN2 {SPR_EGGN, 4, 24, {A_Boss2TakeDamage}, 24+TICRATE, 0, S_EGGMOBILE2_POGO4}, // S_EGGMOBILE2_PAIN2
{SPR_EGGN, 5, 8, {A_Fall}, 0, 0, S_EGGMOBILE2_DIE2}, // S_EGGMOBILE2_DIE1 {SPR_EGGN, 5, 2, {A_Fall}, 0, 0, S_EGGMOBILE2_DIE2}, // S_EGGMOBILE2_DIE1
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE3}, // S_EGGMOBILE2_DIE2 {SPR_EGGN, 5, 2, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE3}, // S_EGGMOBILE2_DIE2
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE4}, // S_EGGMOBILE2_DIE3 {SPR_EGGN, 5, 0, {A_Repeat}, 17, S_EGGMOBILE2_DIE2, S_EGGMOBILE2_DIE4}, // S_EGGMOBILE2_DIE3
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE5}, // S_EGGMOBILE2_DIE4 {SPR_EGGN, 5, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE2_DIE4
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE6}, // S_EGGMOBILE2_DIE5 {SPR_EGGN, 6, 2, {A_BossScream}, 0, 0, S_EGGMOBILE2_FLEE2}, // S_EGGMOBILE2_FLEE1
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE7}, // S_EGGMOBILE2_DIE6 {SPR_EGGN, 7, 2, {A_BossScream}, 0, 0, S_EGGMOBILE2_FLEE1}, // S_EGGMOBILE2_FLEE2
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE8}, // S_EGGMOBILE2_DIE7
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE9}, // S_EGGMOBILE2_DIE8
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE10}, // S_EGGMOBILE2_DIE9
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE11}, // S_EGGMOBILE2_DIE10
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE12}, // S_EGGMOBILE2_DIE11
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE13}, // S_EGGMOBILE2_DIE12
{SPR_EGGN, 5, 8, {A_BossScream}, 0, 0, S_EGGMOBILE2_DIE14}, // S_EGGMOBILE2_DIE13
{SPR_EGGN, 5, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE2_DIE14
{SPR_EGGN, 6, 5, {NULL}, 0, 0, S_EGGMOBILE2_FLEE2}, // S_EGGMOBILE2_FLEE1
{SPR_EGGN, 7, 5, {NULL}, 0, 0, S_EGGMOBILE2_FLEE1}, // S_EGGMOBILE2_FLEE2
{SPR_TNKA, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK1 {SPR_TNKA, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK1
{SPR_TNKB, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK2 {SPR_TNKB, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BOSSTANK2
@ -1305,22 +1282,12 @@ state_t states[NUMSTATES] =
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_LAUGH20 {SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_LAUGH20
{SPR_EGGO, 8, 1, {A_Boss3TakeDamage}, 0, 0, S_EGGMOBILE3_PAIN2}, // S_EGGMOBILE3_PAIN {SPR_EGGO, 8, 1, {A_Boss3TakeDamage}, 0, 0, S_EGGMOBILE3_PAIN2}, // S_EGGMOBILE3_PAIN
{SPR_EGGO, 8, 23, {A_Pain}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_PAIN2 {SPR_EGGO, 8, 23, {A_Pain}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_PAIN2
{SPR_EGGO, 9, 8, {A_Fall}, 0, 0, S_EGGMOBILE3_DIE2}, // S_EGGMOBILE3_DIE1 {SPR_EGGO, 9, 2, {A_Fall}, 0, 0, S_EGGMOBILE3_DIE2}, // S_EGGMOBILE3_DIE1
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE3}, // S_EGGMOBILE3_DIE2 {SPR_EGGO, 9, 2, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE3}, // S_EGGMOBILE3_DIE2
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE4}, // S_EGGMOBILE3_DIE3 {SPR_EGGO, 9, 0, {A_Repeat}, 17, S_EGGMOBILE3_DIE2, S_EGGMOBILE3_DIE4}, // S_EGGMOBILE3_DIE3
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE5}, // S_EGGMOBILE3_DIE4 {SPR_EGGO, 9, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE3_DIE4
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE6}, // S_EGGMOBILE3_DIE5 {SPR_EGGO, 10, 2, {A_BossScream}, 0, 0, S_EGGMOBILE3_FLEE2}, // S_EGGMOBILE3_FLEE1
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE7}, // S_EGGMOBILE3_DIE6 {SPR_EGGO, 11, 2, {A_BossScream}, 0, 0, S_EGGMOBILE3_FLEE1}, // S_EGGMOBILE3_FLEE2
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE8}, // S_EGGMOBILE3_DIE7
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE9}, // S_EGGMOBILE3_DIE8
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE10}, // S_EGGMOBILE3_DIE9
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE11}, // S_EGGMOBILE3_DIE10
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE12}, // S_EGGMOBILE3_DIE11
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE13}, // S_EGGMOBILE3_DIE12
{SPR_EGGO, 9, 8, {A_BossScream}, 0, 0, S_EGGMOBILE3_DIE14}, // S_EGGMOBILE3_DIE13
{SPR_EGGO, 9, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE3_DIE14
{SPR_EGGO, 10, 5, {NULL}, 0, 0, S_EGGMOBILE3_FLEE2}, // S_EGGMOBILE3_FLEE1
{SPR_EGGO, 11, 5, {NULL}, 0, 0, S_EGGMOBILE3_FLEE1}, // S_EGGMOBILE3_FLEE2
// Boss 3 Propeller // Boss 3 Propeller
{SPR_PRPL, 0, 1, {NULL}, 0, 0, S_PROPELLER2}, // S_PROPELLER1 {SPR_PRPL, 0, 1, {NULL}, 0, 0, S_PROPELLER2}, // S_PROPELLER1
@ -1361,26 +1328,16 @@ state_t states[NUMSTATES] =
{SPR_EGGP,13|FF_ANIMATE, -1, {NULL}, 1, 10, S_NULL}, // S_EGGMOBILE4_RAISE2 {SPR_EGGP,13|FF_ANIMATE, -1, {NULL}, 1, 10, S_NULL}, // S_EGGMOBILE4_RAISE2
{SPR_EGGP,11, 0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2}, // S_EGGMOBILE4_PAIN1 {SPR_EGGP,11, 0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2}, // S_EGGMOBILE4_PAIN1
{SPR_EGGP,11, 24, {A_Pain}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_PAIN2 {SPR_EGGP,11, 24, {A_Pain}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_PAIN2
{SPR_EGGP,12, 8, {A_Fall}, 0, 0, S_EGGMOBILE4_DIE2}, // S_EGGMOBILE4_DIE1 {SPR_EGGP,12, 2, {A_Fall}, 0, 0, S_EGGMOBILE4_DIE2}, // S_EGGMOBILE4_DIE1
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE3}, // S_EGGMOBILE4_DIE2 {SPR_EGGP,12, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE3}, // S_EGGMOBILE4_DIE2
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE4}, // S_EGGMOBILE4_DIE3 {SPR_EGGP,12, 0, {A_Repeat}, 17, S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE4}, // S_EGGMOBILE4_DIE3
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE5}, // S_EGGMOBILE4_DIE4 {SPR_EGGP,12, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE4_DIE4
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE6}, // S_EGGMOBILE4_DIE5 {SPR_EGGP,13, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_FLEE2}, // S_EGGMOBILE4_FLEE1
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE7}, // S_EGGMOBILE4_DIE6 {SPR_EGGP,14, 2, {A_BossScream}, 0, 0, S_EGGMOBILE4_FLEE1}, // S_EGGMOBILE4_FLEE2
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE8}, // S_EGGMOBILE4_DIE7
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE9}, // S_EGGMOBILE4_DIE8
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE10}, // S_EGGMOBILE4_DIE9
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE11}, // S_EGGMOBILE4_DIE10
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE12}, // S_EGGMOBILE4_DIE11
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE13}, // S_EGGMOBILE4_DIE12
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE14}, // S_EGGMOBILE4_DIE13
{SPR_EGGP,12, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_EGGMOBILE4_DIE14
{SPR_EGGP,13, 5, {NULL}, 0, 0, S_EGGMOBILE4_FLEE2}, // S_EGGMOBILE4_FLEE1
{SPR_EGGP,14, 5, {NULL}, 0, 0, S_EGGMOBILE4_FLEE1}, // S_EGGMOBILE4_FLEE2
{SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_MACE {SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_MACE
{SPR_BMCE, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_EGGMOBILE4_MACE_DIE2}, // S_EGGMOBILE4_MACE_DIE1 {SPR_BMCE, 0, 2, {A_BossScream}, 1, 0, S_EGGMOBILE4_MACE_DIE2}, // S_EGGMOBILE4_MACE_DIE1
{SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_EGGMOBILE4_MACE_DIE3}, // S_EGGMOBILE4_MACE_DIE2 {SPR_NULL, 0, 2, {A_BossScream}, 1, 0, S_EGGMOBILE4_MACE_DIE3}, // S_EGGMOBILE4_MACE_DIE2
{SPR_NULL, 0, 0, {A_Repeat}, 7, S_EGGMOBILE4_MACE_DIE1, S_BOSSEXPLODE}, // S_EGGMOBILE4_MACE_DIE3 {SPR_NULL, 0, 0, {A_Repeat}, 7, S_EGGMOBILE4_MACE_DIE1, S_SONIC3KBOSSEXPLOSION1}, // S_EGGMOBILE4_MACE_DIE3
// Boss 4 jet flame // Boss 4 jet flame
{SPR_EFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_JETFLAME {SPR_EFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_JETFLAME
@ -1430,7 +1387,7 @@ state_t states[NUMSTATES] =
{SPR_FANG, 4, 1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2}, // S_FANG_SKID2 {SPR_FANG, 4, 1, {A_DoNPCSkid}, S_FANG_SKID3, 0, S_FANG_SKID2}, // S_FANG_SKID2
{SPR_FANG, 4, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK}, // S_FANG_SKID3 {SPR_FANG, 4, 10, {NULL}, 0, 0, S_FANG_CHOOSEATTACK}, // S_FANG_SKID3
{SPR_FANG, 0, 0, {A_RandomState}, S_FANG_LOBSHOT1, S_FANG_FIRESTART1, S_NULL}, // S_FANG_CHOOSEATTACK {SPR_FANG, 0, 0, {A_RandomState}, S_FANG_LOBSHOT0, S_FANG_FIRESTART1, S_NULL}, // S_FANG_CHOOSEATTACK
{SPR_FANG, 5, 0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2}, // S_FANG_FIRESTART1 // Reset loop {SPR_FANG, 5, 0, {A_PrepareRepeat}, 3, 0, S_FANG_FIRESTART2}, // S_FANG_FIRESTART1 // Reset loop
{SPR_FANG, 5, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1}, // S_FANG_FIRESTART2 {SPR_FANG, 5, 18, {A_LookForBetter}, 1, 0, S_FANG_FIRE1}, // S_FANG_FIRESTART2
@ -1440,7 +1397,8 @@ state_t states[NUMSTATES] =
{SPR_FANG, 5, 5, {NULL}, 2, 0, S_FANG_FIREREPEAT}, // S_FANG_FIRE4 {SPR_FANG, 5, 5, {NULL}, 2, 0, S_FANG_FIREREPEAT}, // S_FANG_FIRE4
{SPR_FANG, 5, 0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1}, // S_FANG_FIREREPEAT // End of loop {SPR_FANG, 5, 0, {A_Repeat}, 3, S_FANG_FIRE1, S_FANG_WAIT1}, // S_FANG_FIREREPEAT // End of loop
{SPR_FANG, 19, 18, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2}, // S_FANG_LOBSHOT1 {SPR_FANG, 18, 16, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT1}, // S_FANG_LOBSHOT0
{SPR_FANG, 19, 2, {A_LookForBetter}, 1, 0, S_FANG_LOBSHOT2}, // S_FANG_LOBSHOT1
{SPR_FANG, 20, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1}, // S_FANG_LOBSHOT2 {SPR_FANG, 20, 18, {A_BrakLobShot}, MT_FBOMB, 32+(1<<16), S_FANG_WAIT1}, // S_FANG_LOBSHOT2
{SPR_FANG, FF_ANIMATE|15, 70, {NULL}, 1, 5, S_FANG_WAIT2}, // S_FANG_WAIT1 {SPR_FANG, FF_ANIMATE|15, 70, {NULL}, 1, 5, S_FANG_WAIT2}, // S_FANG_WAIT1
@ -1458,17 +1416,18 @@ state_t states[NUMSTATES] =
{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2}, // S_FANG_PINCHFALL1 {SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL2}, // S_FANG_PINCHFALL1
{SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL2 {SPR_FANG, 13, 1, {A_Boss5CheckOnGround}, S_FANG_PINCHSKID1, 0, S_FANG_PINCHFALL1}, // S_FANG_PINCHFALL2
{SPR_FANG, 4, 0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID1 {SPR_FANG, 4, 0, {A_PlayAttackSound}, 0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID1
{SPR_FANG, 4, 1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT1, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID2 {SPR_FANG, 4, 1, {A_DoNPCSkid}, S_FANG_PINCHLOBSHOT0, 0, S_FANG_PINCHSKID2}, // S_FANG_PINCHSKID2
{SPR_FANG, 19, 18, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2}, // S_FANG_PINCHLOBSHOT1 {SPR_FANG, 18, 16, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT1}, // S_FANG_PINCHLOBSHOT0
{SPR_FANG, 19, 2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2}, // S_FANG_PINCHLOBSHOT1
{SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3}, // S_FANG_PINCHLOBSHOT2 {SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3}, // S_FANG_PINCHLOBSHOT2
{SPR_FANG, 19, 18, {A_LinedefExecute}, LE_BOSS4DROP, 0, S_FANG_PINCHLOBSHOT4}, // S_FANG_PINCHLOBSHOT3 {SPR_FANG, 20, 18, {A_LinedefExecute}, LE_BOSS4DROP, 0, S_FANG_PINCHLOBSHOT4}, // S_FANG_PINCHLOBSHOT3
{SPR_FANG, 19, 0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1}, // S_FANG_PINCHLOBSHOT4 {SPR_FANG, 0, 0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1}, // S_FANG_PINCHLOBSHOT4
{SPR_FANG, 14, 0, {A_DoNPCPain}, 0, 0, S_FANG_DIE2}, // S_FANG_DIE1 {SPR_FANG, 21, 0, {A_DoNPCPain}, 0, 0, S_FANG_DIE2}, // S_FANG_DIE1
{SPR_FANG, 14, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2 {SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2
{SPR_FANG, 17, 0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3 {SPR_FANG, 22, 0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3
{SPR_FANG, 17, 104, {NULL}, 0, 0, S_FANG_DIE5}, // S_FANG_DIE4 {SPR_FANG, 22, 104, {NULL}, 0, 0, S_FANG_DIE5}, // S_FANG_DIE4
{SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5 {SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5
{SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6 {SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6
@ -1480,7 +1439,7 @@ state_t states[NUMSTATES] =
{SPR_FANG, 9, 2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2}, // S_FANG_FLEEBOUNCE1 {SPR_FANG, 9, 2, {NULL}, 0, 0, S_FANG_FLEEBOUNCE2}, // S_FANG_FLEEBOUNCE1
{SPR_FANG, 10, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_FANG_FLEEBOUNCE2 {SPR_FANG, 10, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_FANG_FLEEBOUNCE2
{SPR_FANG, 18, 7*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FANG_KO {SPR_FANG, 17, 7*TICRATE, {NULL}, 0, 0, S_NULL}, // S_FANG_KO
{SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1 {SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1
{SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2 {SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2
@ -1621,7 +1580,7 @@ state_t states[NUMSTATES] =
{SPR_BRAK, 18, 0, {A_CheckHealth}, 3, S_CYBRAKDEMON_PAIN3, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN2 {SPR_BRAK, 18, 0, {A_CheckHealth}, 3, S_CYBRAKDEMON_PAIN3, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN2
{SPR_BRAK, 18, 0, {A_LinedefExecute}, LE_PINCHPHASE, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN3 {SPR_BRAK, 18, 0, {A_LinedefExecute}, LE_PINCHPHASE, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN3
{SPR_BRAK, 18, 1, {A_Repeat}, 1, S_CYBRAKDEMON_DIE1, S_CYBRAKDEMON_DIE2}, // S_CYBRAKDEMON_DIE1 {SPR_BRAK, 18, 1, {A_Repeat}, 1, S_CYBRAKDEMON_DIE1, S_CYBRAKDEMON_DIE2}, // S_CYBRAKDEMON_DIE1
{SPR_BRAK, 18, 2, {A_BossScream}, 0, MT_SONIC3KBOSSEXPLODE, S_CYBRAKDEMON_DIE3}, // S_CYBRAKDEMON_DIE2 {SPR_BRAK, 18, 2, {A_BossScream}, 0, 0, S_CYBRAKDEMON_DIE3}, // S_CYBRAKDEMON_DIE2
{SPR_BRAK, 18, 0, {A_Repeat}, 52, S_CYBRAKDEMON_DIE2, S_CYBRAKDEMON_DIE4}, // S_CYBRAKDEMON_DIE3 {SPR_BRAK, 18, 0, {A_Repeat}, 52, S_CYBRAKDEMON_DIE2, S_CYBRAKDEMON_DIE4}, // S_CYBRAKDEMON_DIE3
{SPR_BRAK, 13, 14, {A_PlaySound}, sfx_bedie2, 0, S_CYBRAKDEMON_DIE5}, // S_CYBRAKDEMON_DIE4 {SPR_BRAK, 13, 14, {A_PlaySound}, sfx_bedie2, 0, S_CYBRAKDEMON_DIE5}, // S_CYBRAKDEMON_DIE4
{SPR_BRAK, 14, 7, {NULL}, 0, 0, S_CYBRAKDEMON_DIE6}, // S_CYBRAKDEMON_DIE5 {SPR_BRAK, 14, 7, {NULL}, 0, 0, S_CYBRAKDEMON_DIE6}, // S_CYBRAKDEMON_DIE5
@ -1737,7 +1696,7 @@ state_t states[NUMSTATES] =
{SPR_NULL, 0, 1, {A_SetFuse}, TICRATE, 0, S_CYBRAKDEMONVILEEXPLOSION2}, //S_CYBRAKDEMONVILEEXPLOSION1, {SPR_NULL, 0, 1, {A_SetFuse}, TICRATE, 0, S_CYBRAKDEMONVILEEXPLOSION2}, //S_CYBRAKDEMONVILEEXPLOSION1,
{SPR_NULL, 0, 0, {A_ScoreRise}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION3}, //S_CYBRAKDEMONVILEEXPLOSION2, {SPR_NULL, 0, 0, {A_ScoreRise}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION3}, //S_CYBRAKDEMONVILEEXPLOSION2,
{SPR_NULL, 0, 1, {A_BossScream}, 0, MT_SONIC3KBOSSEXPLODE, S_CYBRAKDEMONVILEEXPLOSION1}, //S_CYBRAKDEMONVILEEXPLOSION3, {SPR_NULL, 0, 1, {A_BossScream}, 0, 0, S_CYBRAKDEMONVILEEXPLOSION1}, //S_CYBRAKDEMONVILEEXPLOSION3,
// Metal Sonic // Metal Sonic
{SPR_METL, 0, 35, {NULL}, 0, 0, S_METALSONIC_WAIT1}, // S_METALSONIC_STAND {SPR_METL, 0, 35, {NULL}, 0, 0, S_METALSONIC_WAIT1}, // S_METALSONIC_STAND
@ -1766,14 +1725,12 @@ state_t states[NUMSTATES] =
{SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE {SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE
{SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT {SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT
{SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN {SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN
{SPR_METL, 13, 8, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1 {SPR_METL, 13, 2, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1
{SPR_METL, 13, 8, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2 {SPR_METL, 13, 4, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2
{SPR_METL, 13, 0, {A_Repeat}, 11, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3 {SPR_METL, 13, 0, {A_Repeat}, 17, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3
{SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4 {SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1 {SPR_METL, 11, 1, {A_BossScream}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
{SPR_METL, 11, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2 {SPR_METL, 11, 7, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE2
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4
{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1
{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2 {SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2
@ -3740,8 +3697,8 @@ state_t states[NUMSTATES] =
{SPR_HIVE, 2, 2, {NULL}, 0, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_SHOOT2 {SPR_HIVE, 2, 2, {NULL}, 0, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_SHOOT2
{SPR_HIVE, 0, 5, {A_ParentTriesToSleep}, S_HIVEELEMENTAL_PREPARE1, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_DORMANT {SPR_HIVE, 0, 5, {A_ParentTriesToSleep}, S_HIVEELEMENTAL_PREPARE1, 0, S_HIVEELEMENTAL_DORMANT}, // S_HIVEELEMENTAL_DORMANT
{SPR_HIVE, 3, 35, {A_Pain}, 0, 0, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_PAIN {SPR_HIVE, 3, 35, {A_Pain}, 0, 0, S_HIVEELEMENTAL_LOOK}, // S_HIVEELEMENTAL_PAIN
{SPR_HIVE, 3, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_HIVEELEMENTAL_DIE2}, // S_HIVEELEMENTAL_DIE1 {SPR_HIVE, 3, 2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE2}, // S_HIVEELEMENTAL_DIE1
{SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_HIVEELEMENTAL_DIE3}, // S_HIVEELEMENTAL_DIE2 {SPR_NULL, 0, 2, {A_BossScream}, 1, 0, S_HIVEELEMENTAL_DIE3}, // S_HIVEELEMENTAL_DIE2
{SPR_NULL, 0, 0, {A_Repeat}, 7, S_HIVEELEMENTAL_DIE1, S_XPLD_FLICKY}, // S_HIVEELEMENTAL_DIE3 {SPR_NULL, 0, 0, {A_Repeat}, 7, S_HIVEELEMENTAL_DIE1, S_XPLD_FLICKY}, // S_HIVEELEMENTAL_DIE3
{SPR_BUMB, 1, 10, {NULL}, 0, 0, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_SPAWN {SPR_BUMB, 1, 10, {NULL}, 0, 0, S_BUMBLEBORE_LOOK1}, // S_BUMBLEBORE_SPAWN
@ -4639,7 +4596,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_FACESTABBER_CHARGE1, // missilestate S_FACESTABBER_CHARGE1, // missilestate
S_FACESTABBER_DIE1, // deathstate S_FACESTABBER_DIE1, // deathstate
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_cybdth, // deathsound sfx_s3kb4, // deathsound
3, // speed 3, // speed
32*FRACUNIT, // radius 32*FRACUNIT, // radius
72*FRACUNIT, // height 72*FRACUNIT, // height
@ -5206,7 +5163,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_EGGMOBILE_RATK1, // missilestate S_EGGMOBILE_RATK1, // missilestate
S_EGGMOBILE_DIE1, // deathstate S_EGGMOBILE_DIE1, // deathstate
S_EGGMOBILE_FLEE1, // xdeathstate S_EGGMOBILE_FLEE1, // xdeathstate
sfx_cybdth, // deathsound sfx_s3kb4, // deathsound
4, // speed 4, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
76*FRACUNIT, // height 76*FRACUNIT, // height
@ -5341,7 +5298,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
(statenum_t)MT_EGGMOBILE2_POGO, // missilestate (statenum_t)MT_EGGMOBILE2_POGO, // missilestate
S_EGGMOBILE2_DIE1, // deathstate S_EGGMOBILE2_DIE1, // deathstate
S_EGGMOBILE2_FLEE1,// xdeathstate S_EGGMOBILE2_FLEE1,// xdeathstate
sfx_cybdth, // deathsound sfx_s3kb4, // deathsound
2*FRACUNIT, // speed 2*FRACUNIT, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
76*FRACUNIT, // height 76*FRACUNIT, // height
@ -5403,7 +5360,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass 100, // mass
1, // damage 1, // damage
sfx_None, // activesound sfx_None, // activesound
MF_NOBLOCKMAP, // flags MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -5430,7 +5387,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass 100, // mass
1, // damage 1, // damage
sfx_None, // activesound sfx_None, // activesound
MF_NOBLOCKMAP, // flags MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -5457,7 +5414,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass 100, // mass
1, // damage 1, // damage
sfx_None, // activesound sfx_None, // activesound
MF_NOBLOCKMAP, // flags MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
@ -5530,7 +5487,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_EGGMOBILE3_LAUGH1,// missilestate S_EGGMOBILE3_LAUGH1,// missilestate
S_EGGMOBILE3_DIE1, // deathstate S_EGGMOBILE3_DIE1, // deathstate
S_EGGMOBILE3_FLEE1, // xdeathstate S_EGGMOBILE3_FLEE1, // xdeathstate
sfx_cybdth, // deathsound sfx_s3kb4, // deathsound
8*FRACUNIT, // speed 8*FRACUNIT, // speed
32*FRACUNIT, // radius 32*FRACUNIT, // radius
116*FRACUNIT, // height 116*FRACUNIT, // height
@ -5638,7 +5595,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_EGGMOBILE4_RATK1,// missilestate S_EGGMOBILE4_RATK1,// missilestate
S_EGGMOBILE4_DIE1, // deathstate S_EGGMOBILE4_DIE1, // deathstate
S_EGGMOBILE4_FLEE1,// xdeathstate S_EGGMOBILE4_FLEE1,// xdeathstate
sfx_cybdth, // deathsound sfx_s3kb4, // deathsound
0, // speed 0, // speed
24*FRACUNIT, // radius 24*FRACUNIT, // radius
76*FRACUNIT, // height 76*FRACUNIT, // height
@ -6367,7 +6324,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_METALSONIC_SHOOT, // missilestate S_METALSONIC_SHOOT, // missilestate
S_METALSONIC_DEATH1,// deathstate S_METALSONIC_DEATH1,// deathstate
S_METALSONIC_FLEE1, // xdeathstate S_METALSONIC_FLEE1, // xdeathstate
sfx_s3k6e, // deathsound sfx_s3kb4, // deathsound
MT_ENERGYBALL, // speed MT_ENERGYBALL, // speed
16*FRACUNIT, // radius 16*FRACUNIT, // radius
48*FRACUNIT, // height 48*FRACUNIT, // height
@ -6554,7 +6511,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound sfx_None, // painsound
S_NULL, // meleestate S_NULL, // meleestate
S_NULL, // missilestate S_NULL, // missilestate
S_BOSSEXPLODE, // deathstate S_SONIC3KBOSSEXPLOSION1, // deathstate
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_cybdth, // deathsound sfx_cybdth, // deathsound
38*FRACUNIT, // speed 38*FRACUNIT, // speed
@ -18983,7 +18940,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // missilestate S_NULL, // missilestate
S_HIVEELEMENTAL_DIE1, // deathstate S_HIVEELEMENTAL_DIE1, // deathstate
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_cybdth, // deathsound sfx_s3kb4, // deathsound
6*FRACUNIT, // speed 6*FRACUNIT, // speed
30*FRACUNIT, // radius 30*FRACUNIT, // radius
80*FRACUNIT, // height 80*FRACUNIT, // height

View file

@ -1369,25 +1369,12 @@ typedef enum state
S_EGGMOBILE_PANIC5, S_EGGMOBILE_PANIC5,
S_EGGMOBILE_PANIC6, S_EGGMOBILE_PANIC6,
S_EGGMOBILE_PANIC7, S_EGGMOBILE_PANIC7,
S_EGGMOBILE_PANIC8,
S_EGGMOBILE_PANIC9,
S_EGGMOBILE_PANIC10,
S_EGGMOBILE_PAIN, S_EGGMOBILE_PAIN,
S_EGGMOBILE_PAIN2, S_EGGMOBILE_PAIN2,
S_EGGMOBILE_DIE1, S_EGGMOBILE_DIE1,
S_EGGMOBILE_DIE2, S_EGGMOBILE_DIE2,
S_EGGMOBILE_DIE3, S_EGGMOBILE_DIE3,
S_EGGMOBILE_DIE4, S_EGGMOBILE_DIE4,
S_EGGMOBILE_DIE5,
S_EGGMOBILE_DIE6,
S_EGGMOBILE_DIE7,
S_EGGMOBILE_DIE8,
S_EGGMOBILE_DIE9,
S_EGGMOBILE_DIE10,
S_EGGMOBILE_DIE11,
S_EGGMOBILE_DIE12,
S_EGGMOBILE_DIE13,
S_EGGMOBILE_DIE14,
S_EGGMOBILE_FLEE1, S_EGGMOBILE_FLEE1,
S_EGGMOBILE_FLEE2, S_EGGMOBILE_FLEE2,
S_EGGMOBILE_BALL, S_EGGMOBILE_BALL,
@ -1408,16 +1395,6 @@ typedef enum state
S_EGGMOBILE2_DIE2, S_EGGMOBILE2_DIE2,
S_EGGMOBILE2_DIE3, S_EGGMOBILE2_DIE3,
S_EGGMOBILE2_DIE4, S_EGGMOBILE2_DIE4,
S_EGGMOBILE2_DIE5,
S_EGGMOBILE2_DIE6,
S_EGGMOBILE2_DIE7,
S_EGGMOBILE2_DIE8,
S_EGGMOBILE2_DIE9,
S_EGGMOBILE2_DIE10,
S_EGGMOBILE2_DIE11,
S_EGGMOBILE2_DIE12,
S_EGGMOBILE2_DIE13,
S_EGGMOBILE2_DIE14,
S_EGGMOBILE2_FLEE1, S_EGGMOBILE2_FLEE1,
S_EGGMOBILE2_FLEE2, S_EGGMOBILE2_FLEE2,
@ -1467,16 +1444,6 @@ typedef enum state
S_EGGMOBILE3_DIE2, S_EGGMOBILE3_DIE2,
S_EGGMOBILE3_DIE3, S_EGGMOBILE3_DIE3,
S_EGGMOBILE3_DIE4, S_EGGMOBILE3_DIE4,
S_EGGMOBILE3_DIE5,
S_EGGMOBILE3_DIE6,
S_EGGMOBILE3_DIE7,
S_EGGMOBILE3_DIE8,
S_EGGMOBILE3_DIE9,
S_EGGMOBILE3_DIE10,
S_EGGMOBILE3_DIE11,
S_EGGMOBILE3_DIE12,
S_EGGMOBILE3_DIE13,
S_EGGMOBILE3_DIE14,
S_EGGMOBILE3_FLEE1, S_EGGMOBILE3_FLEE1,
S_EGGMOBILE3_FLEE2, S_EGGMOBILE3_FLEE2,
@ -1523,16 +1490,6 @@ typedef enum state
S_EGGMOBILE4_DIE2, S_EGGMOBILE4_DIE2,
S_EGGMOBILE4_DIE3, S_EGGMOBILE4_DIE3,
S_EGGMOBILE4_DIE4, S_EGGMOBILE4_DIE4,
S_EGGMOBILE4_DIE5,
S_EGGMOBILE4_DIE6,
S_EGGMOBILE4_DIE7,
S_EGGMOBILE4_DIE8,
S_EGGMOBILE4_DIE9,
S_EGGMOBILE4_DIE10,
S_EGGMOBILE4_DIE11,
S_EGGMOBILE4_DIE12,
S_EGGMOBILE4_DIE13,
S_EGGMOBILE4_DIE14,
S_EGGMOBILE4_FLEE1, S_EGGMOBILE4_FLEE1,
S_EGGMOBILE4_FLEE2, S_EGGMOBILE4_FLEE2,
S_EGGMOBILE4_MACE, S_EGGMOBILE4_MACE,
@ -1588,6 +1545,7 @@ typedef enum state
S_FANG_FIRE3, S_FANG_FIRE3,
S_FANG_FIRE4, S_FANG_FIRE4,
S_FANG_FIREREPEAT, S_FANG_FIREREPEAT,
S_FANG_LOBSHOT0,
S_FANG_LOBSHOT1, S_FANG_LOBSHOT1,
S_FANG_LOBSHOT2, S_FANG_LOBSHOT2,
S_FANG_WAIT1, S_FANG_WAIT1,
@ -1604,6 +1562,7 @@ typedef enum state
S_FANG_PINCHFALL2, S_FANG_PINCHFALL2,
S_FANG_PINCHSKID1, S_FANG_PINCHSKID1,
S_FANG_PINCHSKID2, S_FANG_PINCHSKID2,
S_FANG_PINCHLOBSHOT0,
S_FANG_PINCHLOBSHOT1, S_FANG_PINCHLOBSHOT1,
S_FANG_PINCHLOBSHOT2, S_FANG_PINCHLOBSHOT2,
S_FANG_PINCHLOBSHOT3, S_FANG_PINCHLOBSHOT3,
@ -1909,8 +1868,6 @@ typedef enum state
S_METALSONIC_DEATH4, S_METALSONIC_DEATH4,
S_METALSONIC_FLEE1, S_METALSONIC_FLEE1,
S_METALSONIC_FLEE2, S_METALSONIC_FLEE2,
S_METALSONIC_FLEE3,
S_METALSONIC_FLEE4,
S_MSSHIELD_F1, S_MSSHIELD_F1,
S_MSSHIELD_F2, S_MSSHIELD_F2,

View file

@ -308,6 +308,8 @@ static int lib_cvRegisterVar(lua_State *L)
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e); #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e);
#define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1)))
memset(cvar, 0x00, sizeof(consvar_t)); // zero everything by default
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, 1)) { while (lua_next(L, 1)) {
// stack: cvar table, cvar userdata, key/index, value // stack: cvar table, cvar userdata, key/index, value
@ -395,6 +397,13 @@ static int lib_cvRegisterVar(lua_State *L)
#undef FIELDERROR #undef FIELDERROR
#undef TYPEERROR #undef TYPEERROR
if (!cvar->name)
return luaL_error(L, M_GetText("Variable has no name!\n"));
if ((cvar->flags & CV_NOINIT) && !(cvar->flags & CV_CALL))
return luaL_error(L, M_GetText("Variable %s has CV_NOINIT without CV_CALL\n"), cvar->name);
if ((cvar->flags & CV_CALL) && !cvar->func)
return luaL_error(L, M_GetText("Variable %s has CV_CALL without a function\n"), cvar->name);
// stack: cvar table, cvar userdata // stack: cvar table, cvar userdata
lua_getfield(L, LUA_REGISTRYINDEX, "CV_Vars"); lua_getfield(L, LUA_REGISTRYINDEX, "CV_Vars");
I_Assert(lua_istable(L, 3)); I_Assert(lua_istable(L, 3));

View file

@ -173,15 +173,15 @@ static int lib_all7emeralds(lua_State *L)
return 1; return 1;
} }
// Whee, special Lua-exclusive function for making use of Color_Opposite[] without needing *2 or +1 // Whee, special Lua-exclusive function for making use of Color_Opposite[]
// Returns both color and frame numbers! // Returns both color and signpost shade numbers!
static int lib_coloropposite(lua_State *L) static int lib_coloropposite(lua_State *L)
{ {
UINT8 colornum = (UINT8)luaL_checkinteger(L, 1); UINT8 colornum = (UINT8)luaL_checkinteger(L, 1);
if (colornum >= MAXSKINCOLORS) if (!colornum || colornum >= MAXSKINCOLORS)
return luaL_error(L, "skincolor %d out of range (0 - %d).", colornum, MAXSKINCOLORS-1); return luaL_error(L, "skincolor %d out of range (1 - %d).", colornum, MAXSKINCOLORS-1);
lua_pushinteger(L, Color_Opposite[colornum*2]); // push color lua_pushinteger(L, Color_Opposite[colornum-1][0]); // push color
lua_pushinteger(L, Color_Opposite[colornum*2+1]); // push frame lua_pushinteger(L, Color_Opposite[colornum-1][1]); // push sign shade index, 0-15
return 2; return 2;
} }

View file

@ -136,6 +136,12 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->currentweapon); lua_pushinteger(L, plr->currentweapon);
else if (fastcmp(field,"ringweapons")) else if (fastcmp(field,"ringweapons"))
lua_pushinteger(L, plr->ringweapons); lua_pushinteger(L, plr->ringweapons);
else if (fastcmp(field,"ammoremoval"))
lua_pushinteger(L, plr->ammoremoval);
else if (fastcmp(field,"ammoremovaltimer"))
lua_pushinteger(L, plr->ammoremovaltimer);
else if (fastcmp(field,"ammoremovalweapon"))
lua_pushinteger(L, plr->ammoremovalweapon);
else if (fastcmp(field,"powers")) else if (fastcmp(field,"powers"))
LUA_PushUserdata(L, plr->powers, META_POWERS); LUA_PushUserdata(L, plr->powers, META_POWERS);
else if (fastcmp(field,"pflags")) else if (fastcmp(field,"pflags"))
@ -428,6 +434,12 @@ static int player_set(lua_State *L)
plr->currentweapon = (INT32)luaL_checkinteger(L, 3); plr->currentweapon = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"ringweapons")) else if (fastcmp(field,"ringweapons"))
plr->ringweapons = (INT32)luaL_checkinteger(L, 3); plr->ringweapons = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"ammoremoval"))
plr->ammoremoval = (UINT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"ammoremovaltimer"))
plr->ammoremovaltimer = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"ammoremovalweapon"))
plr->ammoremovalweapon = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"powers")) else if (fastcmp(field,"powers"))
return NOSET; return NOSET;
else if (fastcmp(field,"pflags")) else if (fastcmp(field,"pflags"))

View file

@ -6980,8 +6980,8 @@ static void M_DrawLoadGameData(void)
col = 134; col = 134;
else else
{ {
col = (charskin->prefcolor - 1)*2; col = charskin->prefcolor - 1;
col = Color_Index[Color_Opposite[col]-1][Color_Opposite[col+1]]; col = Color_Index[Color_Opposite[col][0]-1][Color_Opposite[col][1]];
} }
V_DrawFill(x+6, y+64, 72, 50, col); V_DrawFill(x+6, y+64, 72, 50, col);

View file

@ -3007,6 +3007,8 @@ void A_Boss7FireMissiles(mobj_t *actor)
// var2: // var2:
// 0 - Boss 1 Left side // 0 - Boss 1 Left side
// 1 - Boss 1 Right side // 1 - Boss 1 Right side
// 2 - Triple laser
// >3 - Boss 1 Middle
// //
void A_Boss1Laser(mobj_t *actor) void A_Boss1Laser(mobj_t *actor)
{ {
@ -3042,6 +3044,15 @@ void A_Boss1Laser(mobj_t *actor)
else else
z = actor->z + FixedMul(56*FRACUNIT, actor->scale); z = actor->z + FixedMul(56*FRACUNIT, actor->scale);
break; break;
case 2:
var2 = 3; // Fire middle laser
A_Boss1Laser(actor);
var2 = 0; // Fire left laser
A_Boss1Laser(actor);
var2 = 1; // Fire right laser
A_Boss1Laser(actor);
return;
break;
default: default:
x = actor->x; x = actor->x;
y = actor->y; y = actor->y;
@ -3049,7 +3060,7 @@ void A_Boss1Laser(mobj_t *actor)
break; break;
} }
if (!(actor->flags2 & MF2_FIRING)) if (!(actor->flags2 & MF2_FIRING) && actor->tics > 1)
{ {
actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);
if (mobjinfo[locvar1].seesound) if (mobjinfo[locvar1].seesound)
@ -3071,6 +3082,7 @@ void A_Boss1Laser(mobj_t *actor)
angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT);
else else
angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y)); angle = R_PointToAngle2(z + (mobjinfo[locvar1].height>>1), 0, actor->target->z, R_PointToDist2(x, y, actor->target->x, actor->target->y));
point = P_SpawnMobj(x, y, z, locvar1); point = P_SpawnMobj(x, y, z, locvar1);
P_SetTarget(&point->target, actor); P_SetTarget(&point->target, actor);
point->angle = actor->angle; point->angle = actor->angle;
@ -3342,7 +3354,7 @@ void A_BossZoom(mobj_t *actor)
// var1: // var1:
// 0 - Use movecount to spawn explosions evenly // 0 - Use movecount to spawn explosions evenly
// 1 - Use P_Random to spawn explosions at complete random // 1 - Use P_Random to spawn explosions at complete random
// var2 = Object to spawn. Default is MT_BOSSEXPLODE. // var2 = Object to spawn. Default is MT_SONIC3KBOSSEXPLODE.
// //
void A_BossScream(mobj_t *actor) void A_BossScream(mobj_t *actor)
{ {
@ -3374,7 +3386,7 @@ void A_BossScream(mobj_t *actor)
// Determine what mobj to spawn. If undefined or invalid, use MT_BOSSEXPLODE as default. // Determine what mobj to spawn. If undefined or invalid, use MT_BOSSEXPLODE as default.
if (locvar2 <= 0 || locvar2 >= NUMMOBJTYPES) if (locvar2 <= 0 || locvar2 >= NUMMOBJTYPES)
explodetype = MT_BOSSEXPLODE; explodetype = MT_SONIC3KBOSSEXPLODE; //MT_BOSSEXPLODE; -- piss to you, sonic 2
else else
explodetype = (mobjtype_t)locvar2; explodetype = (mobjtype_t)locvar2;
@ -3941,14 +3953,24 @@ bossjustdie:
mo->flags |= MF_NOGRAVITY|MF_NOCLIP; mo->flags |= MF_NOGRAVITY|MF_NOCLIP;
mo->flags |= MF_NOCLIPHEIGHT; mo->flags |= MF_NOCLIPHEIGHT;
mo->movedir = 0;
mo->extravalue1 = 35;
mo->flags2 |= MF2_BOSSFLEE;
mo->momz = 2*mo->scale;
if (mo->target) if (mo->target)
{ {
mo->angle = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y); angle_t diff = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y) - mo->angle;
mo->flags2 |= MF2_BOSSFLEE; if (diff)
mo->momz = FixedMul(FixedDiv(mo->target->z - mo->z, P_AproxDistance(mo->x-mo->target->x,mo->y-mo->target->y)), FixedMul(2*FRACUNIT, mo->scale)); {
if (diff > ANGLE_180)
diff = InvAngle(InvAngle(diff)/mo->extravalue1);
else
diff /= mo->extravalue1;
mo->movedir = diff;
}
} }
else
mo->momz = FixedMul(2*FRACUNIT, mo->scale);
break; break;
} }
} }
@ -4903,12 +4925,12 @@ void A_SignPlayer(mobj_t *actor)
of in the name. If you have a better idea, feel free of in the name. If you have a better idea, feel free
to let me know. ~toast 2016/07/20 to let me know. ~toast 2016/07/20
*/ */
actor->frame += (15 - Color_Opposite[(Color_Opposite[(skin->prefoppositecolor - 1)*2] - 1)*2 + 1]); actor->frame += (15 - Color_Opposite[Color_Opposite[skin->prefoppositecolor - 1][0] - 1][1]);
} }
else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor. else if (actor->target->player->skincolor) // Set the sign to be an appropriate background color for this player's skincolor.
{ {
actor->color = Color_Opposite[(actor->target->player->skincolor - 1)*2]; actor->color = Color_Opposite[actor->target->player->skincolor - 1][0];
actor->frame += (15 - Color_Opposite[(actor->target->player->skincolor - 1)*2 + 1]); actor->frame += (15 - Color_Opposite[actor->target->player->skincolor - 1][1]);
} }
if (skin->sprites[SPR2_SIGN].numframes) if (skin->sprites[SPR2_SIGN].numframes)
@ -12096,7 +12118,7 @@ void A_MineExplode(mobj_t *actor)
{ {
#define dist 64 #define dist 64
UINT8 i; UINT8 i;
mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE); mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_SONIC3KBOSSEXPLODE);
S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e)); S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e));
P_SpawnMobj(actor->x, actor->y, actor->z, type); P_SpawnMobj(actor->x, actor->y, actor->z, type);
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)

View file

@ -428,7 +428,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|| special->state == &states[S_FANG_BOUNCE4] || special->state == &states[S_FANG_BOUNCE4]
|| special->state == &states[S_FANG_PINCHBOUNCE3] || special->state == &states[S_FANG_PINCHBOUNCE3]
|| special->state == &states[S_FANG_PINCHBOUNCE4]) || special->state == &states[S_FANG_PINCHBOUNCE4])
&& P_MobjFlip(special)*((special->z + special->height/2) - (toucher->z - toucher->height/2)) > 0) && P_MobjFlip(special)*((special->z + special->height/2) - (toucher->z - toucher->height/2)) > -(special->height/4))
{ {
P_DamageMobj(toucher, special, special, 1, 0); P_DamageMobj(toucher, special, special, 1, 0);
P_SetTarget(&special->tracer, toucher); P_SetTarget(&special->tracer, toucher);

View file

@ -285,6 +285,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (spring->info->painchance != 2) if (spring->info->painchance != 2)
{ {
if (object->player)
object->player->pflags &= ~PF_APPLYAUTOBRAKE;
if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA if ((horizspeed && vertispeed) || (object->player && object->player->homing)) // Mimic SA
{ {
object->momx = object->momy = 0; object->momx = object->momy = 0;
@ -2884,7 +2887,7 @@ static boolean P_ThingHeightClip(mobj_t *thing)
if (thing->z != oldz) if (thing->z != oldz)
{ {
if (thing->player) if (thing->player)
P_PlayerHitFloor(thing->player, false); P_PlayerHitFloor(thing->player, !onfloor);
} }
// debug: be sure it falls to the floor // debug: be sure it falls to the floor
@ -4136,7 +4139,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
{ {
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect // Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
if (!P_MobjTouchingPolyobj(po, mo)) if (!P_MobjInsidePolyobj(po, mo))
continue; continue;
if (!PIT_ChangeSector(mo, false)) if (!PIT_ChangeSector(mo, false))
@ -4246,7 +4249,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
{ {
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect // Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
if (!P_MobjTouchingPolyobj(po, mo)) if (!P_MobjInsidePolyobj(po, mo))
continue; continue;
PIT_ChangeSector(mo, true); PIT_ChangeSector(mo, true);

View file

@ -4236,12 +4236,7 @@ static void P_GenericBossThinker(mobj_t *mobj)
if (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE)) if (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE))
{ {
if (mobj->health <= 0) if (mobj->health <= 0)
{
// look for a new target
if (P_BossTargetPlayer(mobj, false) && mobj->info->mass) // Bid farewell!
S_StartSound(mobj, mobj->info->mass);
return; return;
}
// look for a new target // look for a new target
if (P_BossTargetPlayer(mobj, false) && mobj->info->seesound) if (P_BossTargetPlayer(mobj, false) && mobj->info->seesound)
@ -4263,7 +4258,7 @@ static void P_GenericBossThinker(mobj_t *mobj)
// AI for the first boss. // AI for the first boss.
static void P_Boss1Thinker(mobj_t *mobj) static void P_Boss1Thinker(mobj_t *mobj)
{ {
if (mobj->flags2 & MF2_FRET && (statenum_t)(mobj->state-states) == mobj->info->spawnstate) { if (mobj->flags2 & MF2_FRET && mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1) {
mobj->flags2 &= ~(MF2_FRET|MF2_SKULLFLY); mobj->flags2 &= ~(MF2_FRET|MF2_SKULLFLY);
mobj->momx = mobj->momy = mobj->momz = 0; mobj->momx = mobj->momy = mobj->momz = 0;
} }
@ -4281,11 +4276,7 @@ static void P_Boss1Thinker(mobj_t *mobj)
return; // It's okay, then. return; // It's okay, then.
if (mobj->health <= 0) if (mobj->health <= 0)
{
if (P_BossTargetPlayer(mobj, false) && mobj->info->mass) // Bid farewell!
S_StartSound(mobj, mobj->info->mass);
return; return;
}
// look for a new target // look for a new target
if (P_BossTargetPlayer(mobj, false) && mobj->info->seesound) if (P_BossTargetPlayer(mobj, false) && mobj->info->seesound)
@ -4332,12 +4323,7 @@ static void P_Boss2Thinker(mobj_t *mobj)
if (mobj->health <= mobj->info->damage && (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE))) if (mobj->health <= mobj->info->damage && (!mobj->target || !(mobj->target->flags & MF_SHOOTABLE)))
{ {
if (mobj->health <= 0) if (mobj->health <= 0)
{
// look for a new target
if (P_BossTargetPlayer(mobj, false) && mobj->info->mass) // Bid farewell!
S_StartSound(mobj, mobj->info->mass);
return; return;
}
// look for a new target // look for a new target
if (P_BossTargetPlayer(mobj, false) && mobj->info->seesound) if (P_BossTargetPlayer(mobj, false) && mobj->info->seesound)
@ -7107,6 +7093,11 @@ void P_MobjThinker(mobj_t *mobj)
switch (mobj->type) switch (mobj->type)
{ {
case MT_BOSSTANK1:
case MT_BOSSTANK2:
case MT_BOSSSPIGOT:
mobj->flags2 ^= MF2_DONTDRAW;
break;
case MT_MACEPOINT: case MT_MACEPOINT:
case MT_CHAINMACEPOINT: case MT_CHAINMACEPOINT:
case MT_SPRINGBALLPOINT: case MT_SPRINGBALLPOINT:
@ -7730,7 +7721,25 @@ void P_MobjThinker(mobj_t *mobj)
break; break;
} }
if (mobj->flags2 & MF2_BOSSFLEE) if (mobj->flags2 & MF2_BOSSFLEE)
P_InstaThrust(mobj, mobj->angle, FixedMul(12*FRACUNIT, mobj->scale)); {
if (mobj->extravalue1)
{
if (!(--mobj->extravalue1))
{
if (mobj->target)
{
mobj->momz = FixedMul(FixedDiv(mobj->target->z - mobj->z, P_AproxDistance(mobj->x-mobj->target->x,mobj->y-mobj->target->y)), mobj->scale<<1);
mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
}
else
mobj->momz = 8*mobj->scale;
}
else
mobj->angle += mobj->movedir;
}
else if (mobj->target)
P_InstaThrust(mobj, mobj->angle, FixedMul(12*FRACUNIT, mobj->scale));
}
} }
else if (mobj->health <= 0) // Dead things think differently than the living. else if (mobj->health <= 0) // Dead things think differently than the living.
switch (mobj->type) switch (mobj->type)
@ -7842,8 +7851,8 @@ void P_MobjThinker(mobj_t *mobj)
mobj->x + (P_RandomRange(r, -r) << FRACBITS), mobj->x + (P_RandomRange(r, -r) << FRACBITS),
mobj->y + (P_RandomRange(r, -r) << FRACBITS), mobj->y + (P_RandomRange(r, -r) << FRACBITS),
mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS), mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS),
MT_BOSSEXPLODE); MT_SONIC3KBOSSEXPLODE);
S_StartSound(explosion, sfx_cybdth); S_StartSound(explosion, sfx_s3kb4);
} }
if (mobj->movedir == DMG_DROWNED) if (mobj->movedir == DMG_DROWNED)
P_SetObjectMomZ(mobj, -FRACUNIT / 2, true); // slower fall from drowning P_SetObjectMomZ(mobj, -FRACUNIT / 2, true); // slower fall from drowning

View file

@ -125,6 +125,10 @@ static void P_NetArchivePlayers(void)
WRITEINT32(save_p, players[i].currentweapon); WRITEINT32(save_p, players[i].currentweapon);
WRITEINT32(save_p, players[i].ringweapons); WRITEINT32(save_p, players[i].ringweapons);
WRITEUINT16(save_p, players[i].ammoremoval);
WRITEUINT32(save_p, players[i].ammoremovaltimer);
WRITEINT32(save_p, players[i].ammoremovaltimer);
for (j = 0; j < NUMPOWERS; j++) for (j = 0; j < NUMPOWERS; j++)
WRITEUINT16(save_p, players[i].powers[j]); WRITEUINT16(save_p, players[i].powers[j]);
@ -329,6 +333,10 @@ static void P_NetUnArchivePlayers(void)
players[i].currentweapon = READINT32(save_p); players[i].currentweapon = READINT32(save_p);
players[i].ringweapons = READINT32(save_p); players[i].ringweapons = READINT32(save_p);
players[i].ammoremoval = READUINT16(save_p);
players[i].ammoremovaltimer = READUINT32(save_p);
players[i].ammoremovalweapon = READINT32(save_p);
for (j = 0; j < NUMPOWERS; j++) for (j = 0; j < NUMPOWERS; j++)
players[i].powers[j] = READUINT16(save_p); players[i].powers[j] = READUINT16(save_p);

View file

@ -716,9 +716,11 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
vector3_t mom; // Ditto. vector3_t mom; // Ditto.
if (slope->flags & SL_NOPHYSICS) { // No physics, no need to make anything complicated. if (slope->flags & SL_NOPHYSICS) { // No physics, no need to make anything complicated.
if (P_MobjFlip(thing)*(thing->momz) < 0) { // falling, land on slope if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope
//thing->momz = -P_MobjFlip(thing); {
thing->standingslope = slope; thing->standingslope = slope;
if (!thing->player || !(thing->player->pflags & PF_BOUNCING))
thing->momz = -P_MobjFlip(thing);
} }
return; return;
} }
@ -732,9 +734,9 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope
thing->momx = mom.x; thing->momx = mom.x;
thing->momy = mom.y; thing->momy = mom.y;
//thing->momz = -P_MobjFlip(thing);
thing->standingslope = slope; thing->standingslope = slope;
if (!thing->player || !(thing->player->pflags & PF_BOUNCING))
thing->momz = -P_MobjFlip(thing);
} }
} }

View file

@ -3096,7 +3096,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
break; break;
case 432: // Enable 2D Mode (Disable if noclimb) case 432: // Enable 2D Mode (Disable if noclimb)
if (mo->player) if (mo && mo->player)
{ {
if (line->flags & ML_NOCLIMB) if (line->flags & ML_NOCLIMB)
mo->flags2 &= ~MF2_TWOD; mo->flags2 &= ~MF2_TWOD;
@ -3122,7 +3122,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
break; break;
case 434: // Custom Power case 434: // Custom Power
if (mo->player) if (mo && mo->player)
{ {
mobj_t *dummy = P_SpawnMobj(mo->x, mo->y, mo->z, MT_NULL); mobj_t *dummy = P_SpawnMobj(mo->x, mo->y, mo->z, MT_NULL);
@ -3205,7 +3205,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
break; break;
case 437: // Disable Player Controls case 437: // Disable Player Controls
if (mo->player) if (mo && mo->player)
{ {
UINT16 fractime = (UINT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); UINT16 fractime = (UINT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS);
if (fractime < 1) if (fractime < 1)

View file

@ -1051,6 +1051,8 @@ void P_ResetPlayer(player_t *player)
// //
boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) boolean P_PlayerCanDamage(player_t *player, mobj_t *thing)
{ {
fixed_t bottomheight, topheight;
if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing)) if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing))
return false; return false;
@ -1090,13 +1092,26 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing)
return true; return true;
// From the top/bottom. // From the top/bottom.
if (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0) bottomheight = player->mo->z;
topheight = player->mo->z + player->mo->height;
if (player->mo->eflags & MFE_VERTICALFLIP)
{ {
if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*player->mo->momz < 0)) fixed_t swap = bottomheight;
bottomheight = topheight;
topheight = swap;
}
if (P_MobjFlip(player->mo)*(bottomheight - (thing->z + thing->height/2)) > 0)
{
if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) < 0))
return true;
}
else if (P_MobjFlip(player->mo)*(topheight - (thing->z + thing->height/2)) < 0)
{
if (player->charability == CA_FLY && player->panim == PA_ABILITY && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) > 0))
return true; return true;
} }
else if (player->charability == CA_FLY && player->panim == PA_ABILITY)
return true;
// Shield stomp. // Shield stomp.
if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)) if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY))
@ -2198,7 +2213,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
{ {
if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_THOKKED) && (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale))) if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_THOKKED) && (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
player->pflags |= PF_SPINNING; player->pflags |= PF_SPINNING;
else else if (!(player->pflags & PF_STARTDASH))
player->pflags &= ~PF_SPINNING; player->pflags &= ~PF_SPINNING;
} }
@ -2217,7 +2232,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
player->skidtime = TICRATE; player->skidtime = TICRATE;
player->mo->tics = -1; player->mo->tics = -1;
} }
else else if (!player->skidtime)
player->pflags &= ~PF_GLIDING; player->pflags &= ~PF_GLIDING;
} }
else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
@ -2268,7 +2283,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
} }
else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
; ;
else if (player->pflags & PF_JUMPED || player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED) else if (player->panim != PA_IDLE && player->panim != PA_WALK && player->panim != PA_RUN && player->panim != PA_DASH)
{ {
if (player->cmomx || player->cmomy) if (player->cmomx || player->cmomy)
{ {
@ -3885,6 +3900,33 @@ static void P_SetWeaponDelay(player_t *player, INT32 delay)
} }
} }
//
// P_DrainWeaponAmmo
//
// Reduces rings and weapon ammo. Also penalizes the player
// for using weapon rings with no normal rings! >:V
//
static void P_DrainWeaponAmmo (player_t *player, INT32 power)
{
player->powers[power]--;
if (player->rings < 1)
{
player->ammoremovalweapon = player->currentweapon;
player->ammoremovaltimer = ammoremovaltics;
if (player->powers[power] > 0) // can't take a ring that doesn't exist
{
player->powers[power]--;
player->ammoremoval = 2;
}
else
player->ammoremoval = 1;
}
else
player->rings--;
}
// //
// P_DoFiring() // P_DoFiring()
// //
@ -3923,22 +3965,12 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_ATTACKDOWN;
#define TAKE_AMMO(player, power) \
player->powers[power]--; \
if (player->rings < 1) \
{ \
if (player->powers[power] > 0) \
player->powers[power]--; \
} \
else \
player->rings--;
if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring. if (cmd->buttons & BT_FIRENORMAL) // No powers, just a regular ring.
goto firenormal; //code repetition sucks. goto firenormal; //code repetition sucks.
// Bounce ring // Bounce ring
else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering]) else if (player->currentweapon == WEP_BOUNCE && player->powers[pw_bouncering])
{ {
TAKE_AMMO(player, pw_bouncering); P_DrainWeaponAmmo(player, pw_bouncering);
P_SetWeaponDelay(player, TICRATE/4); P_SetWeaponDelay(player, TICRATE/4);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNBOUNCE, MF2_BOUNCERING);
@ -3949,7 +3981,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
// Rail ring // Rail ring
else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring]) else if (player->currentweapon == WEP_RAIL && player->powers[pw_railring])
{ {
TAKE_AMMO(player, pw_railring); P_DrainWeaponAmmo(player, pw_railring);
P_SetWeaponDelay(player, (3*TICRATE)/2); P_SetWeaponDelay(player, (3*TICRATE)/2);
mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW); mo = P_SpawnPlayerMissile(player->mo, MT_REDRING, MF2_RAILRING|MF2_DONTDRAW);
@ -3960,7 +3992,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
// Automatic // Automatic
else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring]) else if (player->currentweapon == WEP_AUTO && player->powers[pw_automaticring])
{ {
TAKE_AMMO(player, pw_automaticring); P_DrainWeaponAmmo(player, pw_automaticring);
player->pflags &= ~PF_ATTACKDOWN; player->pflags &= ~PF_ATTACKDOWN;
P_SetWeaponDelay(player, 2); P_SetWeaponDelay(player, 2);
@ -3969,7 +4001,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
// Explosion // Explosion
else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring]) else if (player->currentweapon == WEP_EXPLODE && player->powers[pw_explosionring])
{ {
TAKE_AMMO(player, pw_explosionring); P_DrainWeaponAmmo(player, pw_explosionring);
P_SetWeaponDelay(player, (3*TICRATE)/2); P_SetWeaponDelay(player, (3*TICRATE)/2);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNEXPLOSION, MF2_EXPLOSION);
@ -3977,7 +4009,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
// Grenade // Grenade
else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering]) else if (player->currentweapon == WEP_GRENADE && player->powers[pw_grenadering])
{ {
TAKE_AMMO(player, pw_grenadering); P_DrainWeaponAmmo(player, pw_grenadering);
P_SetWeaponDelay(player, TICRATE/3); P_SetWeaponDelay(player, TICRATE/3);
mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION); mo = P_SpawnPlayerMissile(player->mo, MT_THROWNGRENADE, MF2_EXPLOSION);
@ -3996,7 +4028,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
angle_t shotangle = player->mo->angle; angle_t shotangle = player->mo->angle;
angle_t oldaiming = player->aiming; angle_t oldaiming = player->aiming;
TAKE_AMMO(player, pw_scatterring); P_DrainWeaponAmmo(player, pw_scatterring);
P_SetWeaponDelay(player, (2*TICRATE)/3); P_SetWeaponDelay(player, (2*TICRATE)/3);
// Center // Center
@ -4058,8 +4090,6 @@ firenormal:
} }
} }
#undef TAKE_AMMO
if (mo) if (mo)
{ {
if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING) if (mo->flags & MF_MISSILE && mo->flags2 & MF2_RAILRING)
@ -6509,12 +6539,12 @@ static void P_DoNiGHTSCapsule(player_t *player)
player->capsule->health = sphereresult; player->capsule->health = sphereresult;
} }
// Spawn a 'pop' for every 5 tics // Spawn a 'pop' for every 2 tics
if (!((tictimer - firstpoptic) % 5)) if (!((tictimer - firstpoptic) % 2))
S_StartSound(P_SpawnMobj(player->capsule->x + ((P_SignedRandom()/2)<<FRACBITS), S_StartSound(P_SpawnMobj(player->capsule->x + ((P_SignedRandom()/2)<<FRACBITS),
player->capsule->y + ((P_SignedRandom()/2)<<FRACBITS), player->capsule->y + ((P_SignedRandom()/2)<<FRACBITS),
player->capsule->z + (player->capsule->height/2) + ((P_SignedRandom()/2)<<FRACBITS), player->capsule->z + (player->capsule->height/2) + ((P_SignedRandom()/2)<<FRACBITS),
MT_BOSSEXPLODE),sfx_cybdth); MT_SONIC3KBOSSEXPLODE),sfx_s3kb4);
} }
else else
{ {
@ -10186,6 +10216,7 @@ void P_DoPityCheck(player_t *player)
} }
} }
static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *nz) static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *nz)
{ {
sector_t *sec = R_PointInSubsector(x, y)->sector; sector_t *sec = R_PointInSubsector(x, y)->sector;
@ -10598,6 +10629,191 @@ static void P_MinecartThink(player_t *player)
player->powers[pw_flashing]--; player->powers[pw_flashing]--;
} }
// Handle Tails' fluff
static void P_DoTailsOverlay(player_t *player, mobj_t *tails)
{
// init...
boolean smilesonground = P_IsObjectOnGround(player->mo);
angle_t horizangle = player->drawangle;
fixed_t zoffs = 0;
fixed_t backwards = -1*FRACUNIT;
boolean doroll = (player->panim == PA_ROLL || player->panim == PA_JUMP);
angle_t rollangle;
boolean panimchange;
INT32 ticnum = 0;
statenum_t chosenstate;
if (!tails->skin)
{
tails->skin = player->mo->skin;
P_SetMobjState(tails, S_TAILSOVERLAY_STAND);
tails->movecount = -1;
}
panimchange = (tails->movecount != (INT32)player->panim);
// initial position...
if (doroll)
{
fixed_t testval, zdist;
if (player->speed < FRACUNIT)
testval = FRACUNIT;
else
{
testval = (FixedMul(player->speed, FINECOSINE((horizangle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT)));
if (testval < FRACUNIT)
testval = FRACUNIT;
}
if (smilesonground && !player->mo->reactiontime)
zdist = (player->mo->z - tails->threshold);
else
zdist = player->mo->momz;
rollangle = R_PointToAngle2(0, 0, testval, -P_MobjFlip(player->mo)*zdist);
zoffs = 3*FRACUNIT + 12*FINESINE(rollangle >> ANGLETOFINESHIFT);
backwards = -12*FINECOSINE(rollangle >> ANGLETOFINESHIFT);
}
else if (player->panim == PA_RUN)
backwards = -5*FRACUNIT;
else if (player->panim == PA_SPRING)
{
zoffs += 4*FRACUNIT;
backwards /= 2;
}
else if (player->panim == PA_PAIN)
backwards /= 16;
else if (player->mo->state-states == S_PLAY_GASP)
{
backwards /= 16;
zoffs += 12*FRACUNIT;
}
else if (player->mo->state-states == S_PLAY_EDGE)
{
backwards /= 16;
zoffs = 3*FRACUNIT;
}
else if (player->panim == PA_ABILITY2)
{
zoffs = -7*FRACUNIT;
backwards = -9*FRACUNIT;
}
else if (player->mo->sprite2 == SPR2_FLY || player->mo->sprite2 == SPR2_TIRE)
backwards = -5*FRACUNIT;
// sprite...
if (doroll)
{
statenum_t add = ((rollangle > ANGLE_180) ? 2 : 0);
if (add)
rollangle = InvAngle(rollangle);
rollangle += ANG15; // modify the thresholds to be nice clean numbers
if (rollangle > ANG60)
chosenstate = S_TAILSOVERLAY_PLUS60DEGREES + add;
else if (rollangle > ANG30)
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES + add;
else
chosenstate = S_TAILSOVERLAY_0DEGREES;
}
else if (player->panim == PA_SPRING)
chosenstate = S_TAILSOVERLAY_MINUS60DEGREES;
else if (player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
chosenstate = S_TAILSOVERLAY_PLUS60DEGREES;
else if (player->panim == PA_PAIN)
chosenstate = S_TAILSOVERLAY_PAIN;
else if (player->mo->state-states == S_PLAY_GASP)
chosenstate = S_TAILSOVERLAY_GASP;
else if (player->mo->state-states == S_PLAY_EDGE)
chosenstate = S_TAILSOVERLAY_EDGE;
else if (player->panim == PA_RUN)
chosenstate = S_TAILSOVERLAY_RUN;
else if (player->panim == PA_WALK)
{
if (!smilesonground || player->mo->state-states == S_PLAY_SKID)
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES;
else if (player->speed >= FixedMul(player->runspeed/2, player->mo->scale))
chosenstate = S_TAILSOVERLAY_0DEGREES;
else
chosenstate = S_TAILSOVERLAY_MINUS30DEGREES;
}
else if (player->mo->sprite2 == SPR2_FLY)
chosenstate = S_TAILSOVERLAY_FLY;
else if (player->mo->sprite2 == SPR2_TIRE)
chosenstate = S_TAILSOVERLAY_TIRE;
else if (player->panim == PA_ABILITY2)
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES;
else if (player->panim == PA_IDLE)
chosenstate = S_TAILSOVERLAY_STAND;
else
chosenstate = S_INVISIBLE;
// state...
if (panimchange)
{
tails->sprite2 = -1;
P_SetMobjState(tails, chosenstate);
}
else
{
if (tails->state != states+chosenstate)
{
if (states[chosenstate].sprite == SPR_PLAY)
tails->sprite2 = P_GetSkinSprite2(((skin_t *)tails->skin), (states[chosenstate].frame & FF_FRAMEMASK), player);
P_SetMobjState(tails, chosenstate);
}
}
if (player->fly1 != 0 && player->powers[pw_tailsfly] != 0 && !smilesonground)
P_SetMobjState(tails, chosenstate);
// animation...
if (player->panim == PA_SPRING || player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
{
if (FixedDiv(abs(player->mo->momz), player->mo->scale) < 20<<FRACBITS)
ticnum = 2;
else
ticnum = 1;
}
else if (player->panim == PA_PAIN)
ticnum = 2;
else if (player->mo->state-states == S_PLAY_GASP)
tails->tics = -1;
else if (player->mo->sprite2 == SPR2_TIRE)
ticnum = 4;
else if (player->panim != PA_IDLE)
ticnum = player->mo->tics;
if (ticnum && tails->tics > ticnum)
tails->tics = ticnum;
// final handling...
tails->color = player->mo->color;
tails->threshold = player->mo->z;
tails->movecount = player->panim;
tails->angle = horizangle;
P_SetScale(tails, player->mo->scale);
tails->destscale = player->mo->destscale;
tails->radius = player->mo->radius;
tails->height = player->mo->height;
zoffs = FixedMul(zoffs, tails->scale);
if (player->mo->eflags & MFE_VERTICALFLIP)
{
tails->eflags |= MFE_VERTICALFLIP;
tails->flags2 |= MF2_OBJECTFLIP;
zoffs = player->mo->height - tails->height - zoffs;
}
else
{
tails->eflags &= ~MFE_VERTICALFLIP;
tails->flags2 &= ~MF2_OBJECTFLIP;
}
P_UnsetThingPosition(tails);
tails->x = player->mo->x + P_ReturnThrustX(tails, tails->angle, FixedMul(backwards, tails->scale));
tails->y = player->mo->y + P_ReturnThrustY(tails, tails->angle, FixedMul(backwards, tails->scale));
tails->z = player->mo->z + zoffs;
P_SetThingPosition(tails);
}
// //
// P_PlayerThink // P_PlayerThink
// //
@ -10740,6 +10956,9 @@ void P_PlayerThink(player_t *player)
if (player->exiting && countdown2) if (player->exiting && countdown2)
player->exiting = 5; player->exiting = 5;
// The following code is disabled for now as this causes the game to freeze sometimes
// Monster Iestyn -- 16/08/19
#if 0
// Same check as below, just at 1 second before // Same check as below, just at 1 second before
// so we can fade music // so we can fade music
if (!exitfadestarted && if (!exitfadestarted &&
@ -10777,6 +10996,7 @@ void P_PlayerThink(player_t *player)
S_FadeOutStopMusic(1*MUSICRATE); S_FadeOutStopMusic(1*MUSICRATE);
} }
} }
#endif
if (player->exiting == 2 || countdown2 == 2) if (player->exiting == 2 || countdown2 == 2)
{ {
@ -11095,6 +11315,16 @@ void P_PlayerThink(player_t *player)
if (!currentlyonground) if (!currentlyonground)
acceleration /= 2; acceleration /= 2;
// fake skidding! see P_SkidStuff for reference on conditionals
else if (!player->skidtime && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID) && P_AproxDistance(player->mo->momx, player->mo->momy) >= FixedMul(player->runspeed/2, player->mo->scale))
{
if (player->mo->state-states != S_PLAY_SKID)
P_SetPlayerMobjState(player->mo, S_PLAY_SKID);
player->mo->tics = player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
if (P_IsLocalPlayer(player)) // the sound happens way more frequently now, so give co-op players' ears a brake...
S_StartSound(player->mo, sfx_skid);
}
if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration...
acceleration = FixedMul(acceleration<<FRACBITS, player->mo->movefactor)>>FRACBITS; acceleration = FixedMul(acceleration<<FRACBITS, player->mo->movefactor)>>FRACBITS;
@ -11179,6 +11409,12 @@ void P_PlayerThink(player_t *player)
// Counters, time dependent power ups. // Counters, time dependent power ups.
// Time Bonus & Ring Bonus count settings // Time Bonus & Ring Bonus count settings
if (player->ammoremovaltimer)
{
if (--player->ammoremovaltimer == 0)
player->ammoremoval = 0;
}
// Strength counts up to diminish fade. // Strength counts up to diminish fade.
if (player->powers[pw_sneakers] && player->powers[pw_sneakers] < UINT16_MAX) if (player->powers[pw_sneakers] && player->powers[pw_sneakers] < UINT16_MAX)
player->powers[pw_sneakers]--; player->powers[pw_sneakers]--;
@ -11552,130 +11788,149 @@ void P_PlayerAfterThink(player_t *player)
/* if (player->powers[pw_carry] == CR_NONE && player->mo->tracer && !player->homing) /* if (player->powers[pw_carry] == CR_NONE && player->mo->tracer && !player->homing)
P_SetTarget(&player->mo->tracer, NULL); P_SetTarget(&player->mo->tracer, NULL);
else */ else */
if (player->powers[pw_carry] == CR_PLAYER && player->mo->tracer) if (player->mo->tracer)
{ {
player->mo->height = FixedDiv(P_GetPlayerHeight(player), FixedDiv(14*FRACUNIT,10*FRACUNIT)); switch (player->powers[pw_carry])
if (player->mo->tracer->player && !(player->mo->tracer->player->pflags & PF_CANCARRY))
player->powers[pw_carry] = CR_NONE;
if (player->mo->eflags & MFE_VERTICALFLIP)
{ {
if ((player->mo->tracer->z + player->mo->tracer->height + player->mo->height + FixedMul(FRACUNIT, player->mo->scale)) <= player->mo->tracer->ceilingz case CR_PLAYER: // being carried by a flying character (such as Tails)
&& (player->mo->tracer->eflags & MFE_VERTICALFLIP)) // Reverse gravity check for the carrier - Flame
player->mo->z = player->mo->tracer->z + player->mo->tracer->height + FixedMul(FRACUNIT, player->mo->scale);
else
player->powers[pw_carry] = CR_NONE;
}
else
{
if ((player->mo->tracer->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale)) >= player->mo->tracer->floorz
&& !(player->mo->tracer->eflags & MFE_VERTICALFLIP)) // Correct gravity check for the carrier - Flame
player->mo->z = player->mo->tracer->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale);
else
player->powers[pw_carry] = CR_NONE;
}
if (player->mo->tracer->health <= 0)
player->powers[pw_carry] = CR_NONE;
else
{
P_TryMove(player->mo, player->mo->tracer->x, player->mo->tracer->y, true);
player->mo->momx = player->mo->tracer->momx;
player->mo->momy = player->mo->tracer->momy;
player->mo->momz = player->mo->tracer->momz;
}
if (gametype == GT_COOP)
{
player->mo->angle = player->mo->tracer->angle;
if (!demoplayback || P_AnalogMove(player))
{ {
if (player == &players[consoleplayer]) mobj_t *tails = player->mo->tracer;
localangle = player->mo->angle; player->mo->height = FixedDiv(P_GetPlayerHeight(player), FixedDiv(14*FRACUNIT,10*FRACUNIT));
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
}
}
if (P_AproxDistance(player->mo->x - player->mo->tracer->x, player->mo->y - player->mo->tracer->y) > player->mo->radius) if (tails->player && !(tails->player->pflags & PF_CANCARRY))
player->powers[pw_carry] = CR_NONE; player->powers[pw_carry] = CR_NONE;
if (player->powers[pw_carry] != CR_NONE) if (player->mo->eflags & MFE_VERTICALFLIP)
{
if (player->mo->state-states != S_PLAY_RIDE)
P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
}
else
P_SetTarget(&player->mo->tracer, NULL);
if (player-players == consoleplayer && botingame)
CV_SetValue(&cv_analog2, (player->powers[pw_carry] != CR_PLAYER));
}
else if (player->powers[pw_carry] == CR_GENERIC && player->mo->tracer)
{
// tracer is what you're hanging onto
P_UnsetThingPosition(player->mo);
player->mo->x = player->mo->tracer->x;
player->mo->y = player->mo->tracer->y;
if (player->mo->eflags & MFE_VERTICALFLIP)
player->mo->z = player->mo->tracer->z + player->mo->tracer->height - FixedDiv(player->mo->height, 3*FRACUNIT);
else
player->mo->z = player->mo->tracer->z - FixedDiv(player->mo->height, 3*FRACUNIT/2);
player->mo->momx = player->mo->momy = player->mo->momz = 0;
P_SetThingPosition(player->mo);
if (player->mo->state-states != S_PLAY_RIDE)
P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
// Controllable missile
if (player->mo->tracer->type == MT_BLACKEGGMAN_MISSILE)
{
if (cmd->forwardmove > 0)
player->mo->tracer->momz += FixedMul(FRACUNIT/4, player->mo->tracer->scale);
else if (cmd->forwardmove < 0)
player->mo->tracer->momz -= FixedMul(FRACUNIT/4, player->mo->tracer->scale);
player->mo->tracer->angle = player->mo->angle;
P_InstaThrust(player->mo->tracer, player->mo->tracer->angle, FixedMul(player->mo->tracer->info->speed, player->mo->tracer->scale));
if (player->mo->z <= player->mo->floorz
|| player->mo->tracer->health <= 0)
{
player->powers[pw_carry] = CR_NONE;
P_SetTarget(&player->mo->tracer, NULL);
}
}
}
else if (player->powers[pw_carry] == CR_MACESPIN && player->mo->tracer && player->mo->tracer->tracer)
{
player->mo->height = P_GetPlayerSpinHeight(player);
// tracer is what you're hanging onto....
player->mo->momx = (player->mo->tracer->x - player->mo->x)*2;
player->mo->momy = (player->mo->tracer->y - player->mo->y)*2;
player->mo->momz = (player->mo->tracer->z - (player->mo->height-player->mo->tracer->height/2) - player->mo->z)*2;
P_TeleportMove(player->mo, player->mo->tracer->x, player->mo->tracer->y, player->mo->tracer->z - (player->mo->height-player->mo->tracer->height/2));
if (!player->powers[pw_flashing]) // handle getting hurt
{
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_NOJUMPDAMAGE;
player->secondjump = 0;
player->pflags &= ~PF_THOKKED;
if ((player->mo->tracer->tracer->flags & MF_SLIDEME) // Noclimb on chain parameters gives this
&& !(twodlevel || player->mo->flags2 & MF2_TWOD)) // why on earth would you want to turn them in 2D mode?
{
player->mo->tracer->tracer->angle += cmd->sidemove<<ANGLETOFINESHIFT;
player->mo->angle += cmd->sidemove<<ANGLETOFINESHIFT; // 2048 --> ANGLE_MAX
if (!demoplayback || P_AnalogMove(player))
{ {
if (player == &players[consoleplayer]) if ((tails->z + tails->height + player->mo->height + FixedMul(FRACUNIT, player->mo->scale)) <= tails->ceilingz
localangle = player->mo->angle; // Adjust the local control angle. && (tails->eflags & MFE_VERTICALFLIP)) // Reverse gravity check for the carrier - Flame
else if (player == &players[secondarydisplayplayer]) player->mo->z = tails->z + tails->height + FixedMul(FRACUNIT, player->mo->scale);
localangle2 = player->mo->angle; else
player->powers[pw_carry] = CR_NONE;
} }
else
{
if ((tails->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale)) >= tails->floorz
&& !(tails->eflags & MFE_VERTICALFLIP)) // Correct gravity check for the carrier - Flame
player->mo->z = tails->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale);
else
player->powers[pw_carry] = CR_NONE;
}
if (tails->health <= 0)
player->powers[pw_carry] = CR_NONE;
else
{
P_TryMove(player->mo, tails->x, tails->y, true);
player->mo->momx = tails->momx;
player->mo->momy = tails->momy;
player->mo->momz = tails->momz;
}
if (gametype == GT_COOP)
{
player->mo->angle = tails->angle;
if (!demoplayback || P_AnalogMove(player))
{
if (player == &players[consoleplayer])
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
}
}
if (P_AproxDistance(player->mo->x - tails->x, player->mo->y - tails->y) > player->mo->radius)
player->powers[pw_carry] = CR_NONE;
if (player->powers[pw_carry] != CR_NONE)
{
if (player->mo->state-states != S_PLAY_RIDE)
P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
}
else
P_SetTarget(&player->mo->tracer, NULL);
if (player-players == consoleplayer && botingame)
CV_SetValue(&cv_analog2, (player->powers[pw_carry] != CR_PLAYER));
break;
} }
case CR_GENERIC: // being carried by some generic item
{
mobj_t *item = player->mo->tracer;
// tracer is what you're hanging onto
P_UnsetThingPosition(player->mo);
player->mo->x = item->x;
player->mo->y = item->y;
if (player->mo->eflags & MFE_VERTICALFLIP)
player->mo->z = item->z + item->height - FixedDiv(player->mo->height, 3*FRACUNIT);
else
player->mo->z = item->z - FixedDiv(player->mo->height, 3*FRACUNIT/2);
player->mo->momx = player->mo->momy = player->mo->momz = 0;
P_SetThingPosition(player->mo);
if (player->mo->state-states != S_PLAY_RIDE)
P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
// Controllable missile
if (item->type == MT_BLACKEGGMAN_MISSILE)
{
if (cmd->forwardmove > 0)
item->momz += FixedMul(FRACUNIT/4, item->scale);
else if (cmd->forwardmove < 0)
item->momz -= FixedMul(FRACUNIT/4, item->scale);
item->angle = player->mo->angle;
P_InstaThrust(item, item->angle, FixedMul(item->info->speed, item->scale));
if (player->mo->z <= player->mo->floorz || item->health <= 0)
{
player->powers[pw_carry] = CR_NONE;
P_SetTarget(&player->mo->tracer, NULL);
}
}
break;
}
case CR_MACESPIN: // being carried by a spinning chain
{
mobj_t *chain;
mobj_t *macecenter;
if (!player->mo->tracer->tracer) // can't spin around a point if... there is no point in doing so
break;
chain = player->mo->tracer;
macecenter = player->mo->tracer->tracer;
player->mo->height = P_GetPlayerSpinHeight(player);
// tracer is what you're hanging onto....
player->mo->momx = (chain->x - player->mo->x)*2;
player->mo->momy = (chain->y - player->mo->y)*2;
player->mo->momz = (chain->z - (player->mo->height-chain->height/2) - player->mo->z)*2;
P_TeleportMove(player->mo, chain->x, chain->y, chain->z - (player->mo->height-chain->height/2));
if (!player->powers[pw_flashing]) // handle getting hurt
{
player->pflags |= PF_JUMPED;
player->pflags &= ~PF_NOJUMPDAMAGE;
player->secondjump = 0;
player->pflags &= ~PF_THOKKED;
if ((macecenter->flags & MF_SLIDEME) // Noclimb on chain parameters gives this
&& !(twodlevel || player->mo->flags2 & MF2_TWOD)) // why on earth would you want to turn them in 2D mode?
{
macecenter->angle += cmd->sidemove<<ANGLETOFINESHIFT;
player->mo->angle += cmd->sidemove<<ANGLETOFINESHIFT; // 2048 --> ANGLE_MAX
if (!demoplayback || P_AnalogMove(player))
{
if (player == &players[consoleplayer])
localangle = player->mo->angle; // Adjust the local control angle.
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
}
}
}
break;
}
default:
break;
} }
} }
@ -11736,188 +11991,7 @@ void P_PlayerAfterThink(player_t *player)
switch (player->followmobj->type) switch (player->followmobj->type)
{ {
case MT_TAILSOVERLAY: // c: case MT_TAILSOVERLAY: // c:
{ P_DoTailsOverlay(player, player->followmobj);
// init...
boolean smilesonground = P_IsObjectOnGround(player->mo);
angle_t horizangle = player->drawangle;
fixed_t zoffs = 0;
fixed_t backwards = -1*FRACUNIT;
boolean doroll = (player->panim == PA_ROLL || player->panim == PA_JUMP);
angle_t rollangle;
boolean panimchange;
INT32 ticnum = 0;
statenum_t chosenstate;
if (!player->followmobj->skin)
{
player->followmobj->skin = player->mo->skin;
P_SetMobjState(player->followmobj, S_TAILSOVERLAY_STAND);
player->followmobj->movecount = -1;
}
panimchange = (player->followmobj->movecount != (INT32)player->panim);
// initial position...
if (doroll)
{
fixed_t testval, zdist;
if (player->speed < FRACUNIT)
testval = FRACUNIT;
else
{
testval = (FixedMul(player->speed, FINECOSINE((horizangle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT)));
if (testval < FRACUNIT)
testval = FRACUNIT;
}
if (smilesonground && !player->mo->reactiontime)
zdist = (player->mo->z - player->followmobj->threshold);
else
zdist = player->mo->momz;
rollangle = R_PointToAngle2(0, 0, testval, -P_MobjFlip(player->mo)*zdist);
zoffs = 3*FRACUNIT + 12*FINESINE(rollangle >> ANGLETOFINESHIFT);
backwards = -12*FINECOSINE(rollangle >> ANGLETOFINESHIFT);
}
else if (player->panim == PA_RUN)
backwards = -5*FRACUNIT;
else if (player->panim == PA_SPRING)
{
zoffs += 4*FRACUNIT;
backwards /= 2;
}
else if (player->panim == PA_PAIN)
backwards /= 16;
else if (player->mo->state-states == S_PLAY_GASP)
{
backwards /= 16;
zoffs += 12*FRACUNIT;
}
else if (player->mo->state-states == S_PLAY_EDGE)
{
backwards /= 16;
zoffs = 3*FRACUNIT;
}
else if (player->panim == PA_ABILITY2)
{
zoffs = -7*FRACUNIT;
backwards = -9*FRACUNIT;
}
else if (player->mo->sprite2 == SPR2_FLY || player->mo->sprite2 == SPR2_TIRE)
backwards = -5*FRACUNIT;
// sprite...
if (doroll)
{
statenum_t add = ((rollangle > ANGLE_180) ? 2 : 0);
if (add)
rollangle = InvAngle(rollangle);
rollangle += ANG15; // modify the thresholds to be nice clean numbers
if (rollangle > ANG60)
chosenstate = S_TAILSOVERLAY_PLUS60DEGREES + add;
else if (rollangle > ANG30)
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES + add;
else
chosenstate = S_TAILSOVERLAY_0DEGREES;
}
else if (player->panim == PA_SPRING)
chosenstate = S_TAILSOVERLAY_MINUS60DEGREES;
else if (player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
chosenstate = S_TAILSOVERLAY_PLUS60DEGREES;
else if (player->panim == PA_PAIN)
chosenstate = S_TAILSOVERLAY_PAIN;
else if (player->mo->state-states == S_PLAY_GASP)
chosenstate = S_TAILSOVERLAY_GASP;
else if (player->mo->state-states == S_PLAY_EDGE)
chosenstate = S_TAILSOVERLAY_EDGE;
else if (player->panim == PA_RUN)
chosenstate = S_TAILSOVERLAY_RUN;
else if (player->panim == PA_WALK)
{
if (!smilesonground || player->mo->state-states == S_PLAY_SKID)
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES;
else if (player->speed >= FixedMul(player->runspeed/2, player->mo->scale))
chosenstate = S_TAILSOVERLAY_0DEGREES;
else
chosenstate = S_TAILSOVERLAY_MINUS30DEGREES;
}
else if (player->mo->sprite2 == SPR2_FLY)
chosenstate = S_TAILSOVERLAY_FLY;
else if (player->mo->sprite2 == SPR2_TIRE)
chosenstate = S_TAILSOVERLAY_TIRE;
else if (player->panim == PA_ABILITY2)
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES;
else if (player->panim == PA_IDLE)
chosenstate = S_TAILSOVERLAY_STAND;
else
chosenstate = S_INVISIBLE;
// state...
if (panimchange)
{
player->followmobj->sprite2 = -1;
P_SetMobjState(player->followmobj, chosenstate);
}
else
{
if (player->followmobj->state != states+chosenstate)
{
if (states[chosenstate].sprite == SPR_PLAY)
player->followmobj->sprite2 = P_GetSkinSprite2(((skin_t *)player->followmobj->skin), (states[chosenstate].frame & FF_FRAMEMASK), player);
P_SetMobjState(player->followmobj, chosenstate);
}
}
if (player->fly1 != 0 && player->powers[pw_tailsfly] != 0 && !smilesonground)
P_SetMobjState(player->followmobj, chosenstate);
// animation...
if (player->panim == PA_SPRING || player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
{
if (FixedDiv(abs(player->mo->momz), player->mo->scale) < 20<<FRACBITS)
ticnum = 2;
else
ticnum = 1;
}
else if (player->panim == PA_PAIN)
ticnum = 2;
else if (player->mo->state-states == S_PLAY_GASP)
player->followmobj->tics = -1;
else if (player->mo->sprite2 == SPR2_TIRE)
ticnum = 4;
else if (player->panim != PA_IDLE)
ticnum = player->mo->tics;
if (ticnum && player->followmobj->tics > ticnum)
player->followmobj->tics = ticnum;
// final handling...
player->followmobj->color = player->mo->color;
player->followmobj->threshold = player->mo->z;
player->followmobj->movecount = player->panim;
player->followmobj->angle = horizangle;
P_SetScale(player->followmobj, player->mo->scale);
player->followmobj->destscale = player->mo->destscale;
player->followmobj->radius = player->mo->radius;
player->followmobj->height = player->mo->height;
zoffs = FixedMul(zoffs, player->followmobj->scale);
if (player->mo->eflags & MFE_VERTICALFLIP)
{
player->followmobj->eflags |= MFE_VERTICALFLIP;
player->followmobj->flags2 |= MF2_OBJECTFLIP;
zoffs = player->mo->height - player->followmobj->height - zoffs;
}
else
{
player->followmobj->eflags &= ~MFE_VERTICALFLIP;
player->followmobj->flags2 &= ~MF2_OBJECTFLIP;
}
P_UnsetThingPosition(player->followmobj);
player->followmobj->x = player->mo->x + P_ReturnThrustX(player->followmobj, player->followmobj->angle, FixedMul(backwards, player->followmobj->scale));
player->followmobj->y = player->mo->y + P_ReturnThrustY(player->followmobj, player->followmobj->angle, FixedMul(backwards, player->followmobj->scale));
player->followmobj->z = player->mo->z + zoffs;
P_SetThingPosition(player->followmobj);
}
break; break;
default: default:
var1 = 1; var1 = 1;

View file

@ -352,77 +352,79 @@ const char *Color_Names[MAXSKINCOLORS + NUMSUPERCOLORS] =
A word of warning: If the following array is non-symmetrical, A word of warning: If the following array is non-symmetrical,
A_SignPlayer's prefoppositecolor behaviour will break. A_SignPlayer's prefoppositecolor behaviour will break.
*/ */
const UINT8 Color_Opposite[(MAXSKINCOLORS - 1)*2] = // [0] = opposite skin color,
// [1] = shade index used by signpost, 0-15 (actual sprite frame is 15 minus this value)
const UINT8 Color_Opposite[MAXSKINCOLORS - 1][2] =
{ {
// SKINCOLOR_NONE,8, // SKINCOLOR_NONE // {SKINCOLOR_NONE, 8}, // SKINCOLOR_NONE
// Greyscale ranges // Greyscale ranges
SKINCOLOR_BLACK,5, // SKINCOLOR_WHITE, {SKINCOLOR_BLACK, 5}, // SKINCOLOR_WHITE,
SKINCOLOR_JET,7, // SKINCOLOR_BONE, {SKINCOLOR_JET, 7}, // SKINCOLOR_BONE,
SKINCOLOR_CARBON,7, // SKINCOLOR_CLOUDY, {SKINCOLOR_CARBON, 7}, // SKINCOLOR_CLOUDY,
SKINCOLOR_AETHER,12, // SKINCOLOR_GREY, {SKINCOLOR_AETHER, 12}, // SKINCOLOR_GREY,
SKINCOLOR_SLATE,12, // SKINCOLOR_SILVER, {SKINCOLOR_SLATE, 12}, // SKINCOLOR_SILVER,
SKINCOLOR_CLOUDY,7, // SKINCOLOR_CARBON, {SKINCOLOR_CLOUDY, 7}, // SKINCOLOR_CARBON,
SKINCOLOR_BONE,7, // SKINCOLOR_JET, {SKINCOLOR_BONE, 7}, // SKINCOLOR_JET,
SKINCOLOR_WHITE,7, // SKINCOLOR_BLACK, {SKINCOLOR_WHITE, 7}, // SKINCOLOR_BLACK,
// Desaturated // Desaturated
SKINCOLOR_GREY,15, // SKINCOLOR_AETHER, {SKINCOLOR_GREY, 15}, // SKINCOLOR_AETHER,
SKINCOLOR_SILVER,12, // SKINCOLOR_SLATE, {SKINCOLOR_SILVER, 12}, // SKINCOLOR_SLATE,
SKINCOLOR_AZURE,9, // SKINCOLOR_PINK, {SKINCOLOR_AZURE, 9}, // SKINCOLOR_PINK,
SKINCOLOR_RUST,7, // SKINCOLOR_YOGURT, {SKINCOLOR_RUST, 7}, // SKINCOLOR_YOGURT,
SKINCOLOR_TAN,2, // SKINCOLOR_BROWN, {SKINCOLOR_TAN, 2}, // SKINCOLOR_BROWN,
SKINCOLOR_BROWN,12, // SKINCOLOR_TAN, {SKINCOLOR_BROWN, 12}, // SKINCOLOR_TAN,
SKINCOLOR_MOSS,5, // SKINCOLOR_BEIGE, {SKINCOLOR_MOSS, 5}, // SKINCOLOR_BEIGE,
SKINCOLOR_BEIGE,13, // SKINCOLOR_MOSS, {SKINCOLOR_BEIGE, 13}, // SKINCOLOR_MOSS,
SKINCOLOR_PINK,5, // SKINCOLOR_AZURE, {SKINCOLOR_PINK, 5}, // SKINCOLOR_AZURE,
SKINCOLOR_GOLD,4, // SKINCOLOR_LAVENDER, {SKINCOLOR_GOLD, 4}, // SKINCOLOR_LAVENDER,
// Viv's vivid colours (toast 21/07/17) // Viv's vivid colours (toast 21/07/17)
SKINCOLOR_EMERALD,10, // SKINCOLOR_RUBY, {SKINCOLOR_EMERALD, 10}, // SKINCOLOR_RUBY,
SKINCOLOR_FOREST,6, // SKINCOLOR_SALMON, {SKINCOLOR_FOREST, 6}, // SKINCOLOR_SALMON,
SKINCOLOR_GREEN,10, // SKINCOLOR_RED, {SKINCOLOR_GREEN, 10}, // SKINCOLOR_RED,
SKINCOLOR_ICY,10, // SKINCOLOR_CRIMSON, {SKINCOLOR_ICY, 10}, // SKINCOLOR_CRIMSON,
SKINCOLOR_PURPLE,8, // SKINCOLOR_FLAME, {SKINCOLOR_PURPLE, 8}, // SKINCOLOR_FLAME,
SKINCOLOR_TEAL,7, // SKINCOLOR_PEACHY, {SKINCOLOR_TEAL, 7}, // SKINCOLOR_PEACHY,
SKINCOLOR_WAVE,5, // SKINCOLOR_QUAIL, {SKINCOLOR_WAVE, 5}, // SKINCOLOR_QUAIL,
SKINCOLOR_SAPPHIRE,5, // SKINCOLOR_SUNSET, {SKINCOLOR_SAPPHIRE, 5}, // SKINCOLOR_SUNSET,
SKINCOLOR_CYAN,4, // SKINCOLOR_APRICOT, {SKINCOLOR_CYAN, 4}, // SKINCOLOR_APRICOT,
SKINCOLOR_BLUE,4, // SKINCOLOR_ORANGE, {SKINCOLOR_BLUE, 4}, // SKINCOLOR_ORANGE,
SKINCOLOR_YOGURT,8, // SKINCOLOR_RUST, {SKINCOLOR_YOGURT, 8}, // SKINCOLOR_RUST,
SKINCOLOR_LAVENDER,10, // SKINCOLOR_GOLD, {SKINCOLOR_LAVENDER, 10}, // SKINCOLOR_GOLD,
SKINCOLOR_SKY,8, // SKINCOLOR_SANDY, {SKINCOLOR_SKY, 8}, // SKINCOLOR_SANDY,
SKINCOLOR_CORNFLOWER,8, // SKINCOLOR_YELLOW, {SKINCOLOR_CORNFLOWER, 8}, // SKINCOLOR_YELLOW,
SKINCOLOR_DUSK,3, // SKINCOLOR_OLIVE, {SKINCOLOR_DUSK, 3}, // SKINCOLOR_OLIVE,
SKINCOLOR_MAGENTA,9, // SKINCOLOR_LIME, {SKINCOLOR_MAGENTA, 9}, // SKINCOLOR_LIME,
SKINCOLOR_COBALT,2, // SKINCOLOR_PERIDOT, {SKINCOLOR_COBALT, 2}, // SKINCOLOR_PERIDOT,
SKINCOLOR_RED,6, // SKINCOLOR_GREEN, {SKINCOLOR_RED, 6}, // SKINCOLOR_GREEN,
SKINCOLOR_SALMON,9, // SKINCOLOR_FOREST, {SKINCOLOR_SALMON, 9}, // SKINCOLOR_FOREST,
SKINCOLOR_RUBY,4, // SKINCOLOR_EMERALD, {SKINCOLOR_RUBY, 4}, // SKINCOLOR_EMERALD,
SKINCOLOR_VIOLET,5, // SKINCOLOR_MINT, {SKINCOLOR_VIOLET, 5}, // SKINCOLOR_MINT,
SKINCOLOR_PLUM,6, // SKINCOLOR_SEAFOAM, {SKINCOLOR_PLUM, 6}, // SKINCOLOR_SEAFOAM,
SKINCOLOR_ROSY,7, // SKINCOLOR_AQUA, {SKINCOLOR_ROSY, 7}, // SKINCOLOR_AQUA,
SKINCOLOR_PEACHY,7, // SKINCOLOR_TEAL, {SKINCOLOR_PEACHY, 7}, // SKINCOLOR_TEAL,
SKINCOLOR_QUAIL,5, // SKINCOLOR_WAVE, {SKINCOLOR_QUAIL, 5}, // SKINCOLOR_WAVE,
SKINCOLOR_APRICOT,6, // SKINCOLOR_CYAN, {SKINCOLOR_APRICOT, 6}, // SKINCOLOR_CYAN,
SKINCOLOR_SANDY,1, // SKINCOLOR_SKY, {SKINCOLOR_SANDY, 1}, // SKINCOLOR_SKY,
SKINCOLOR_NEON,4, // SKINCOLOR_CERULEAN, {SKINCOLOR_NEON, 4}, // SKINCOLOR_CERULEAN,
SKINCOLOR_CRIMSON,0, // SKINCOLOR_ICY, {SKINCOLOR_CRIMSON, 0}, // SKINCOLOR_ICY,
SKINCOLOR_SUNSET,5, // SKINCOLOR_SAPPHIRE, {SKINCOLOR_SUNSET, 5}, // SKINCOLOR_SAPPHIRE,
SKINCOLOR_YELLOW,4, // SKINCOLOR_CORNFLOWER, {SKINCOLOR_YELLOW, 4}, // SKINCOLOR_CORNFLOWER,
SKINCOLOR_ORANGE,5, // SKINCOLOR_BLUE, {SKINCOLOR_ORANGE, 5}, // SKINCOLOR_BLUE,
SKINCOLOR_PERIDOT,5, // SKINCOLOR_COBALT, {SKINCOLOR_PERIDOT, 5}, // SKINCOLOR_COBALT,
SKINCOLOR_LILAC,4, // SKINCOLOR_VAPOR, {SKINCOLOR_LILAC, 4}, // SKINCOLOR_VAPOR,
SKINCOLOR_OLIVE,0, // SKINCOLOR_DUSK, {SKINCOLOR_OLIVE, 0}, // SKINCOLOR_DUSK,
SKINCOLOR_BUBBLEGUM,9, // SKINCOLOR_PASTEL, {SKINCOLOR_BUBBLEGUM, 9}, // SKINCOLOR_PASTEL,
SKINCOLOR_FLAME,7, // SKINCOLOR_PURPLE, {SKINCOLOR_FLAME, 7}, // SKINCOLOR_PURPLE,
SKINCOLOR_PASTEL,8, // SKINCOLOR_BUBBLEGUM, {SKINCOLOR_PASTEL, 8}, // SKINCOLOR_BUBBLEGUM,
SKINCOLOR_LIME,6, // SKINCOLOR_MAGENTA, {SKINCOLOR_LIME, 6}, // SKINCOLOR_MAGENTA,
SKINCOLOR_CERULEAN,2, // SKINCOLOR_NEON, {SKINCOLOR_CERULEAN, 2}, // SKINCOLOR_NEON,
SKINCOLOR_MINT,6, // SKINCOLOR_VIOLET, {SKINCOLOR_MINT, 6}, // SKINCOLOR_VIOLET,
SKINCOLOR_VAPOR,4, // SKINCOLOR_LILAC, {SKINCOLOR_VAPOR, 4}, // SKINCOLOR_LILAC,
SKINCOLOR_MINT,7, // SKINCOLOR_PLUM, {SKINCOLOR_MINT, 7}, // SKINCOLOR_PLUM,
SKINCOLOR_AQUA,1 // SKINCOLOR_ROSY, {SKINCOLOR_AQUA, 1} // SKINCOLOR_ROSY,
}; };
CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
@ -521,33 +523,49 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
INT32 i, starttranscolor, skinramplength; INT32 i, starttranscolor, skinramplength;
// Handle a couple of simple special cases // Handle a couple of simple special cases
if (skinnum == TC_BOSS if (skinnum < TC_DEFAULT)
|| skinnum == TC_ALLWHITE
|| skinnum == TC_METALSONIC
|| skinnum == TC_BLINK
|| color == SKINCOLOR_NONE)
{ {
if (skinnum == TC_ALLWHITE) switch (skinnum)
memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8));
else if (skinnum == TC_BLINK && color != SKINCOLOR_NONE)
memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8));
else
{ {
for (i = 0; i < NUM_PALETTE_ENTRIES; i++) case TC_ALLWHITE:
dest_colormap[i] = (UINT8)i; memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8));
return;
case TC_RAINBOW:
if (color >= MAXTRANSLATIONS)
I_Error("Invalid skin color #%hu.", (UINT16)color);
if (color != SKINCOLOR_NONE)
{
R_RainbowColormap(dest_colormap, color);
return;
}
break;
case TC_BLINK:
if (color >= MAXTRANSLATIONS)
I_Error("Invalid skin color #%hu.", (UINT16)color);
if (color != SKINCOLOR_NONE)
{
memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8));
return;
}
break;
default:
break;
} }
for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
dest_colormap[i] = (UINT8)i;
// White! // White!
if (skinnum == TC_BOSS) if (skinnum == TC_BOSS)
dest_colormap[31] = 0; dest_colormap[31] = 0;
else if (skinnum == TC_METALSONIC) else if (skinnum == TC_METALSONIC)
dest_colormap[159] = 0; dest_colormap[159] = 0;
return; return;
} }
else if (skinnum == TC_RAINBOW) else if (color == SKINCOLOR_NONE)
{ {
R_RainbowColormap(dest_colormap, color); for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
dest_colormap[i] = (UINT8)i;
return; return;
} }
@ -556,6 +574,9 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR;
if (starttranscolor >= NUM_PALETTE_ENTRIES)
I_Error("Invalid startcolor #%d.", starttranscolor);
// Fill in the entries of the palette that are fixed // Fill in the entries of the palette that are fixed
for (i = 0; i < starttranscolor; i++) for (i = 0; i < starttranscolor; i++)
dest_colormap[i] = (UINT8)i; dest_colormap[i] = (UINT8)i;
@ -568,7 +589,7 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
skinramplength = 16; skinramplength = 16;
} }
else else
skinramplength = i - NUM_PALETTE_ENTRIES; skinramplength = i - NUM_PALETTE_ENTRIES; // shouldn't this be NUM_PALETTE_ENTRIES - starttranscolor?
// Build the translated ramp // Build the translated ramp
for (i = 0; i < skinramplength; i++) for (i = 0; i < skinramplength; i++)
@ -590,13 +611,16 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags)
INT32 skintableindex; INT32 skintableindex;
// Adjust if we want the default colormap // Adjust if we want the default colormap
if (skinnum == TC_DEFAULT) skintableindex = DEFAULT_TT_CACHE_INDEX; switch (skinnum)
else if (skinnum == TC_BOSS) skintableindex = BOSS_TT_CACHE_INDEX; {
else if (skinnum == TC_METALSONIC) skintableindex = METALSONIC_TT_CACHE_INDEX; case TC_DEFAULT: skintableindex = DEFAULT_TT_CACHE_INDEX; break;
else if (skinnum == TC_ALLWHITE) skintableindex = ALLWHITE_TT_CACHE_INDEX; case TC_BOSS: skintableindex = BOSS_TT_CACHE_INDEX; break;
else if (skinnum == TC_RAINBOW) skintableindex = RAINBOW_TT_CACHE_INDEX; case TC_METALSONIC: skintableindex = METALSONIC_TT_CACHE_INDEX; break;
else if (skinnum == TC_BLINK) skintableindex = BLINK_TT_CACHE_INDEX; case TC_ALLWHITE: skintableindex = ALLWHITE_TT_CACHE_INDEX; break;
else skintableindex = skinnum; case TC_RAINBOW: skintableindex = RAINBOW_TT_CACHE_INDEX; break;
case TC_BLINK: skintableindex = BLINK_TT_CACHE_INDEX; break;
default: skintableindex = skinnum; break;
}
if (flags & GTC_CACHE) if (flags & GTC_CACHE)
{ {

View file

@ -1219,7 +1219,7 @@
C01FCF4B08A954540054247B /* Debug */ = { C01FCF4B08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.24; CURRENT_PROJECT_VERSION = 2.1.25;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)", "$(inherited)",
NORMALSRB2, NORMALSRB2,
@ -1231,7 +1231,7 @@
C01FCF4C08A954540054247B /* Release */ = { C01FCF4C08A954540054247B /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CURRENT_PROJECT_VERSION = 2.1.24; CURRENT_PROJECT_VERSION = 2.1.25;
GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (

View file

@ -1960,6 +1960,7 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I
static void ST_drawMatchHUD(void) static void ST_drawMatchHUD(void)
{ {
char penaltystr[5];
const INT32 y = 176; // HUD_LIVES const INT32 y = 176; // HUD_LIVES
INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6; INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6;
@ -1986,18 +1987,20 @@ static void ST_drawMatchHUD(void)
ST_drawWeaponSelect(offset, y); ST_drawWeaponSelect(offset, y);
} }
offset += 20; ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset + 20, y, autoring);
ST_drawWeaponRing(pw_automaticring, RW_AUTO, WEP_AUTO, offset, y, autoring); ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset + 40, y, bouncering);
offset += 20; ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset + 60, y, scatterring);
ST_drawWeaponRing(pw_bouncering, RW_BOUNCE, WEP_BOUNCE, offset, y, bouncering); ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset + 80, y, grenadering);
offset += 20; ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset + 100, y, explosionring);
ST_drawWeaponRing(pw_scatterring, RW_SCATTER, WEP_SCATTER, offset, y, scatterring); ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset + 120, y, railring);
offset += 20;
ST_drawWeaponRing(pw_grenadering, RW_GRENADE, WEP_GRENADE, offset, y, grenadering); if (stplyr->ammoremovaltimer && leveltime % 8 < 4)
offset += 20; {
ST_drawWeaponRing(pw_explosionring, RW_EXPLODE, WEP_EXPLODE, offset, y, explosionring); sprintf(penaltystr, "-%d", stplyr->ammoremoval);
offset += 20; V_DrawString(offset + 8 + stplyr->ammoremovalweapon * 20, y,
ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, y, railring); V_REDMAP, penaltystr);
}
} }
} }