Merge branch 'master' into spindash

This commit is contained in:
Sally Coolatta 2020-07-23 19:12:00 -04:00
commit 25e9c72bab
36 changed files with 2493 additions and 502 deletions

View file

@ -1,3 +1,4 @@
# vim: ft=make
#
# Makefile.cfg for SRB2
#
@ -7,6 +8,66 @@
# and other things
#
# See the following variable don't start with 'GCC'. This is
# to avoid a false positive with the version detection...
SUPPORTED_GCC_VERSIONS:=\
91\
81 82 83\
71 72\
61 62 63 64\
51 52 53 54\
40 41 42 43 44 45 46 47 48 49
LATEST_GCC_VERSION=9.1
# gcc or g++
ifdef PREFIX
CC=$(PREFIX)-gcc
CXX=$(PREFIX)-g++
OBJCOPY=$(PREFIX)-objcopy
OBJDUMP=$(PREFIX)-objdump
STRIP=$(PREFIX)-strip
WINDRES=$(PREFIX)-windres
else
OBJCOPY=objcopy
OBJDUMP=objdump
STRIP=strip
WINDRES=windres
endif
# because Apple screws with us on this
# need to get bintools from homebrew
ifdef MACOSX
CC=clang
CXX=clang
OBJCOPY=gobjcopy
OBJDUMP=gobjdump
endif
# Automatically set version flag, but not if one was manually set
ifeq (,$(filter GCC%,$(.VARIABLES)))
ifneq (,$(findstring gcc,$(shell $(CC) --version))) # if it's GCC
version:=$(shell $(CC) -dumpversion)
# Turn version into words of major, minor
v:=$(subst ., ,$(version))
# concat. major minor
v:=$(word 1,$(v))$(word 2,$(v))
# If this version is not in the list, default to the latest supported
ifeq (,$(filter $(v),$(SUPPORTED_GCC_VERSIONS)))
$(info\
Your compiler version, GCC $(version), is not supported by the Makefile.\
The Makefile will assume GCC $(LATEST_GCC_VERSION).)
GCC$(subst .,,$(LATEST_GCC_VERSION))=1
else
$(info Detected GCC $(version) (GCC$(v)))
GCC$(v)=1
endif
endif
endif
ifdef GCC91
GCC83=1
endif
@ -134,6 +195,9 @@ endif
ifndef GCC295
WFLAGS+=-Wendif-labels
endif
ifdef GCC40
WFLAGS+=-std=gnu89
endif
ifdef GCC41
WFLAGS+=-Wshadow
endif
@ -463,30 +527,6 @@ ifdef ARCHNAME
BIN:=$(BIN)/$(ARCHNAME)
endif
# gcc or g++
ifdef PREFIX
CC=$(PREFIX)-gcc
CXX=$(PREFIX)-g++
OBJCOPY=$(PREFIX)-objcopy
OBJDUMP=$(PREFIX)-objdump
STRIP=$(PREFIX)-strip
WINDRES=$(PREFIX)-windres
else
OBJCOPY=objcopy
OBJDUMP=objdump
STRIP=strip
WINDRES=windres
endif
# because Apple screws with us on this
# need to get bintools from homebrew
ifdef MACOSX
CC=clang
CXX=clang
OBJCOPY=gobjcopy
OBJDUMP=gobjdump
endif
OBJDUMP_OPTS?=--wide --source --line-numbers
LD=$(CC)

View file

@ -116,6 +116,16 @@ static void Skin_OnChange(void);
static void Skin2_OnChange(void);
static void Skin3_OnChange(void);
static void Skin4_OnChange(void);
static void Follower_OnChange(void);
static void Follower2_OnChange(void);
static void Follower3_OnChange(void);
static void Follower4_OnChange(void);
static void Followercolor_OnChange(void);
static void Followercolor2_OnChange(void);
static void Followercolor3_OnChange(void);
static void Followercolor4_OnChange(void);
static void Color_OnChange(void);
static void Color2_OnChange(void);
static void Color3_OnChange(void);
@ -292,6 +302,23 @@ consvar_t cv_skin2 = {"skin2", DEFAULTSKIN2, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Sk
consvar_t cv_skin3 = {"skin3", DEFAULTSKIN3, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin3_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_skin4 = {"skin4", DEFAULTSKIN4, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin4_OnChange, 0, NULL, NULL, 0, 0, NULL};
// player's followers. Also saved.
consvar_t cv_follower = {"follower", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_follower2 = {"follower2", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower2_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_follower3 = {"follower3", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower3_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_follower4 = {"follower4", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower4_OnChange, 0, NULL, NULL, 0, 0, NULL};
// player's follower colors... Also saved...
consvar_t cv_followercolor = {"followercolor", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_followercolor2 = {"followercolor2", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor2_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_followercolor3 = {"followercolor3", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor3_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_followercolor4 = {"followercolor4", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor4_OnChange, 0, NULL, NULL, 0, 0, NULL};
// Follower toggle
static CV_PossibleValue_t followers_cons_t[] = {{0, "Yours only"}, {1, "Everyone's"}, {0, NULL}};
consvar_t cv_showfollowers = {"showfollowers", "Everyone's", CV_SAVE, followers_cons_t, 0, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_skipmapcheck = {"skipmapcheck", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
INT32 cv_debug;
@ -804,11 +831,17 @@ void D_RegisterClientCommands(void)
for (i = 0; i < MAXSKINCOLORS; i++)
{
Color_cons_t[i].value = i;
Color_cons_t[i].strvalue = KartColor_Names[i]; // SRB2kart
Color_cons_t[i].value = Followercolor_cons_t[i].value = i;
Color_cons_t[i].strvalue = Followercolor_cons_t[i].strvalue = KartColor_Names[i]; // SRB2kart
}
Color_cons_t[MAXSKINCOLORS].value = 0;
Color_cons_t[MAXSKINCOLORS].strvalue = NULL;
Color_cons_t[MAXSKINCOLORS].value = Followercolor_cons_t[MAXSKINCOLORS+2].value = 0;
Color_cons_t[MAXSKINCOLORS].strvalue = Followercolor_cons_t[MAXSKINCOLORS+2].strvalue = NULL;
Followercolor_cons_t[MAXSKINCOLORS].value = MAXSKINCOLORS;
Followercolor_cons_t[MAXSKINCOLORS].strvalue = "Match"; // Add "Match" option, which will make the follower color match the player's
Followercolor_cons_t[MAXSKINCOLORS+1].value = MAXSKINCOLORS+1;
Followercolor_cons_t[MAXSKINCOLORS+1].strvalue = "Opposite"; // Add "Opposite" option, ...which is like "Match", but for coloropposite.
if (dedicated)
return;
@ -880,18 +913,27 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_playername);
CV_RegisterVar(&cv_playercolor);
CV_RegisterVar(&cv_skin); // r_things.c (skin NAME)
CV_RegisterVar(&cv_follower);
CV_RegisterVar(&cv_followercolor);
CV_RegisterVar(&cv_showfollowers);
// secondary player (splitscreen)
CV_RegisterVar(&cv_playername2);
CV_RegisterVar(&cv_playercolor2);
CV_RegisterVar(&cv_skin2);
CV_RegisterVar(&cv_follower2);
CV_RegisterVar(&cv_followercolor2);
// third player
CV_RegisterVar(&cv_playername3);
CV_RegisterVar(&cv_playercolor3);
CV_RegisterVar(&cv_skin3);
CV_RegisterVar(&cv_follower3);
CV_RegisterVar(&cv_followercolor3);
// fourth player
CV_RegisterVar(&cv_playername4);
CV_RegisterVar(&cv_playercolor4);
CV_RegisterVar(&cv_skin4);
CV_RegisterVar(&cv_follower4);
CV_RegisterVar(&cv_followercolor4);
// preferred number of players
CV_RegisterVar(&cv_splitplayers);
@ -1449,7 +1491,7 @@ static INT32 snacpending = 0, snac2pending = 0, snac3pending = 0, snac4pending =
//
static void SendNameAndColor(void)
{
XBOXSTATIC char buf[MAXPLAYERNAME+2];
XBOXSTATIC char buf[MAXPLAYERNAME+3];
char *p;
p = buf;
@ -1474,10 +1516,13 @@ static void SendNameAndColor(void)
CV_StealthSet(&cv_playercolor, cv_playercolor.defaultvalue);
}
if (!strcmp(cv_playername.string, player_names[consoleplayer])
&& cv_playercolor.value == players[consoleplayer].skincolor
&& !strcmp(cv_skin.string, skins[players[consoleplayer].skin].name))
return;
// ditto for follower colour:
if (!cv_followercolor.value)
CV_StealthSet(&cv_followercolor, "Match"); // set it to "Match". I don't care about your stupidity!
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
if (cv_follower.value > numfollowers-1 || cv_follower.value < -1)
CV_StealthSet(&cv_follower, "-1");
// We'll handle it later if we're not playing.
if (!Playing())
@ -1496,6 +1541,10 @@ static void SendNameAndColor(void)
if (players[consoleplayer].mo)
players[consoleplayer].mo->color = players[consoleplayer].skincolor;
// Update follower for local games:
if (cv_follower.value >= -1 && cv_follower.value != players[consoleplayer].followerskin)
SetFollower(consoleplayer, cv_follower.value);
if (metalrecording)
{ // Metal Sonic is Sonic, obviously.
SetPlayerSkinByNum(consoleplayer, 0);
@ -1559,6 +1608,8 @@ static void SendNameAndColor(void)
WRITESTRINGN(p, cv_playername.zstring, MAXPLAYERNAME);
WRITEUINT8(p, (UINT8)cv_playercolor.value);
WRITEUINT8(p, (UINT8)cv_skin.value);
WRITESINT8(p, (UINT8)cv_follower.value);
WRITESINT8(p, (UINT8)cv_followercolor.value);
SendNetXCmd(XD_NAMEANDCOLOR, buf, p - buf);
}
@ -1566,7 +1617,7 @@ static void SendNameAndColor(void)
static void SendNameAndColor2(void)
{
INT32 secondplaya = -1;
XBOXSTATIC char buf[MAXPLAYERNAME+2];
XBOXSTATIC char buf[MAXPLAYERNAME+3];
char *p;
if (splitscreen < 1)
@ -1602,6 +1653,14 @@ static void SendNameAndColor2(void)
CV_StealthSet(&cv_playercolor2, cv_playercolor2.defaultvalue);
}
// ditto for follower colour:
if (!cv_followercolor2.value)
CV_StealthSet(&cv_followercolor2, "Match"); // set it to "Match". I don't care about your stupidity!
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
if (cv_follower2.value > numfollowers-1 || cv_follower2.value < -1)
CV_StealthSet(&cv_follower2, "-1");
// We'll handle it later if we're not playing.
if (!Playing())
return;
@ -1619,6 +1678,10 @@ static void SendNameAndColor2(void)
if (players[secondplaya].mo)
players[secondplaya].mo->color = players[secondplaya].skincolor;
// Update follower for local games:
if (cv_follower2.value >= -1 && cv_follower2.value != players[secondplaya].followerskin)
SetFollower(secondplaya, cv_follower2.value);
if ((foundskin = R_SkinAvailable(cv_skin2.string)) != -1)
{
//boolean notsame;
@ -1675,13 +1738,15 @@ static void SendNameAndColor2(void)
WRITESTRINGN(p, cv_playername2.zstring, MAXPLAYERNAME);
WRITEUINT8(p, (UINT8)cv_playercolor2.value);
WRITEUINT8(p, (UINT8)cv_skin2.value);
WRITESINT8(p, (UINT8)cv_follower2.value);
WRITESINT8(p, (UINT8)cv_followercolor2.value);
SendNetXCmd2(XD_NAMEANDCOLOR, buf, p - buf);
}
static void SendNameAndColor3(void)
{
INT32 thirdplaya = -1;
XBOXSTATIC char buf[MAXPLAYERNAME+2];
XBOXSTATIC char buf[MAXPLAYERNAME+3];
char *p;
if (splitscreen < 2)
@ -1706,6 +1771,10 @@ static void SendNameAndColor3(void)
CV_StealthSetValue(&cv_playercolor3, skincolor_blueteam);
}
// ditto for follower colour:
if (!cv_followercolor3.value)
CV_StealthSet(&cv_followercolor3, "Match"); // set it to "Match". I don't care about your stupidity!
// never allow the color "none"
if (!cv_playercolor3.value)
{
@ -1717,6 +1786,10 @@ static void SendNameAndColor3(void)
CV_StealthSet(&cv_playercolor3, cv_playercolor3.defaultvalue);
}
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
if (cv_follower3.value > numfollowers-1 || cv_follower3.value < -1)
CV_StealthSet(&cv_follower3, "-1");
// We'll handle it later if we're not playing.
if (!Playing())
return;
@ -1734,6 +1807,10 @@ static void SendNameAndColor3(void)
if (players[thirdplaya].mo)
players[thirdplaya].mo->color = players[thirdplaya].skincolor;
// Update follower for local games:
if (cv_follower3.value >= -1 && cv_follower3.value != players[thirdplaya].followerskin)
SetFollower(thirdplaya, cv_follower3.value);
if ((foundskin = R_SkinAvailable(cv_skin3.string)) != -1)
{
//boolean notsame;
@ -1790,13 +1867,15 @@ static void SendNameAndColor3(void)
WRITESTRINGN(p, cv_playername3.zstring, MAXPLAYERNAME);
WRITEUINT8(p, (UINT8)cv_playercolor3.value);
WRITEUINT8(p, (UINT8)cv_skin3.value);
WRITESINT8(p, (UINT8)cv_follower3.value);
WRITESINT8(p, (UINT8)cv_followercolor3.value);
SendNetXCmd3(XD_NAMEANDCOLOR, buf, p - buf);
}
static void SendNameAndColor4(void)
{
INT32 fourthplaya = -1;
XBOXSTATIC char buf[MAXPLAYERNAME+2];
XBOXSTATIC char buf[MAXPLAYERNAME+3];
char *p;
if (splitscreen < 3)
@ -1821,6 +1900,10 @@ static void SendNameAndColor4(void)
CV_StealthSetValue(&cv_playercolor4, skincolor_blueteam);
}
// ditto for follower colour:
if (!cv_followercolor4.value)
CV_StealthSet(&cv_followercolor4, "Match"); // set it to "Match". I don't care about your stupidity!
// never allow the color "none"
if (!cv_playercolor4.value)
{
@ -1832,6 +1915,10 @@ static void SendNameAndColor4(void)
CV_StealthSet(&cv_playercolor4, cv_playercolor4.defaultvalue);
}
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
if (cv_follower4.value > numfollowers-1 || cv_follower4.value < -1)
CV_StealthSet(&cv_follower4, "-1");
// We'll handle it later if we're not playing.
if (!Playing())
return;
@ -1849,6 +1936,10 @@ static void SendNameAndColor4(void)
if (players[fourthplaya].mo)
players[fourthplaya].mo->color = players[fourthplaya].skincolor;
// Update follower for local games:
if (cv_follower4.value >= -1 && cv_follower4.value != players[fourthplaya].followerskin)
SetFollower(fourthplaya, cv_follower4.value);
if ((foundskin = R_SkinAvailable(cv_skin4.string)) != -1)
{
//boolean notsame;
@ -1905,6 +1996,8 @@ static void SendNameAndColor4(void)
WRITESTRINGN(p, cv_playername4.zstring, MAXPLAYERNAME);
WRITEUINT8(p, (UINT8)cv_playercolor4.value);
WRITEUINT8(p, (UINT8)cv_skin4.value);
WRITESINT8(p, (UINT8)cv_follower4.value);
WRITESINT8(p, (UINT8)cv_followercolor4.value);
SendNetXCmd4(XD_NAMEANDCOLOR, buf, p - buf);
}
@ -1912,7 +2005,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
{
player_t *p = &players[playernum];
char name[MAXPLAYERNAME+1];
UINT8 color, skin;
UINT8 color, skin, followercolor;
SINT8 follower;
#ifdef PARANOIA
if (playernum < 0 || playernum > MAXPLAYERS)
@ -1936,6 +2030,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
READSTRINGN(*cp, name, MAXPLAYERNAME);
color = READUINT8(*cp);
skin = READUINT8(*cp);
follower = READSINT8(*cp);
followercolor = READSINT8(*cp);
// set name
if (strcasecmp(player_names[playernum], name) != 0)
@ -1995,6 +2091,13 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
}
else
SetPlayerSkinByNum(playernum, skin);
// set follower colour:
// Don't bother doing garbage and kicking if we receive None, this is both silly and a waste of time, this will be handled properly in P_HandleFollower.
p->followercolor = followercolor;
// set follower
SetFollower(playernum, follower);
}
void SendWeaponPref(void)
@ -2815,6 +2918,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
}
chmappending++;
if (netgame)
WRITEUINT32(buf_p, M_RandomizedSeed()); // random seed
SendNetXCmd(XD_MAP, buf, buf_p - buf);
@ -6034,6 +6138,198 @@ static void Name4_OnChange(void)
SendNameAndColor4();
}
// sends the follower change for players
static void Follower_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
INT32 num;
char set[10]; // This isn't Lua and mixed declarations in the middle of code make caveman compilers scream.
// there is a slight chance that we will actually use a string instead so...
// let's investigate the string...
strcpy(str, cv_follower.string);
strcpy(cpy, cv_follower.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower, "-1");
if (!Playing())
return; // don't send anything there.
SendNameAndColor();
return;
}
num = R_FollowerAvailable(str);
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower, set); // set it to a number. It's easier for us to send later :)
}
if (!Playing())
return; // don't send anything there.
SendNameAndColor();
}
// About the same as Color_OnChange but for followers.
static void Followercolor_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(consoleplayer))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor();
}
}
// repeat for the 3 other players
static void Follower2_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
if (!Playing() || !splitscreen)
return; // do whatever you want
strcpy(str, cv_follower2.string);
strcpy(cpy, cv_follower2.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower2, "-1");
SendNameAndColor2();
return;
}
{
INT32 num = R_FollowerAvailable(str);
char set[10];
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower2, set); // set it to a number. It's easier for us to send later :)
}
}
SendNameAndColor2();
}
static void Followercolor2_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(g_localplayers[1]))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor2();
}
}
static void Follower3_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
if (!Playing() || !splitscreen)
return; // do whatever you want
strcpy(str, cv_follower3.string);
strcpy(cpy, cv_follower3.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower3, "-1");
SendNameAndColor3();
return;
}
{
INT32 num = R_FollowerAvailable(str);
char set[10];
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower3, set); // set it to a number. It's easier for us to send later :)
}
}
SendNameAndColor3();
}
static void Followercolor3_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(g_localplayers[2]))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor3();
}
}
static void Follower4_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
if (!Playing() || !splitscreen)
return; // do whatever you want
strcpy(str, cv_follower4.string);
strcpy(cpy, cv_follower4.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower4, "-1");
SendNameAndColor4();
return;
}
{
INT32 num = R_FollowerAvailable(str);
char set[10];
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower4, set); // set it to a number. It's easier for us to send later :)
}
}
SendNameAndColor4();
}
static void Followercolor4_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(g_localplayers[3]))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor4();
}
}
/** Sends a skin change for the console player, unless that player is moving.
* \sa cv_skin, Skin2_OnChange, Color_OnChange
* \author Graue <graue@oceanbase.org>

View file

@ -21,18 +21,23 @@
extern consvar_t cv_playername;
extern consvar_t cv_playercolor;
extern consvar_t cv_skin;
extern consvar_t cv_follower;
extern consvar_t cv_showfollowers;
// secondary splitscreen player
extern consvar_t cv_playername2;
extern consvar_t cv_playercolor2;
extern consvar_t cv_skin2;
extern consvar_t cv_follower2;
// third splitscreen player
extern consvar_t cv_playername3;
extern consvar_t cv_playercolor3;
extern consvar_t cv_skin3;
extern consvar_t cv_follower3;
// fourth splitscreen player
extern consvar_t cv_playername4;
extern consvar_t cv_playercolor4;
extern consvar_t cv_skin4;
extern consvar_t cv_follower4;
// preferred number of players
extern consvar_t cv_splitplayers;

View file

@ -513,6 +513,12 @@ typedef struct player_s
// SRB2kart
UINT8 kartspeed; // Kart speed stat between 1 and 9
UINT8 kartweight; // Kart weight stat between 1 and 9
INT32 followerskin; // Kart: This player's follower "skin"
boolean followerready; // Kart: Used to know when we can have a follower or not. (This is set on the first NameAndColor follower update)
UINT8 followercolor; // Kart: Used to store the follower colour the player wishes to use
mobj_t *follower; // Kart: This is the follower object we have. (If any)
//
UINT32 charflags; // Extra abilities/settings for skins (combinable stuff)

View file

@ -34,6 +34,7 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "d_clisrv.h"
#include "r_things.h" // for followers
#include "m_cond.h"
@ -674,6 +675,271 @@ static void readfreeslots(MYFILE *f)
Z_Free(s);
}
// This here is our current only way to make followers.
INT32 numfollowers = 0;
static void readfollower(MYFILE *f)
{
char *s;
char *word, *word2, dname[SKINNAMESIZE+1];
char *tmp;
char testname[SKINNAMESIZE];
boolean nameset;
INT32 fallbackstate = 0;
INT32 res;
INT32 i;
if (numfollowers > MAXSKINS)
{
deh_warning("Error: Too many followers, cannot add anymore.\n");
return;
}
s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
// Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead.
followers[numfollowers].scale = FRACUNIT;
followers[numfollowers].bubblescale = 0; // No bubble by default
followers[numfollowers].atangle = 230;
followers[numfollowers].dist = 32; // changed from 16 to 32 to better account for ogl models
followers[numfollowers].height = 16;
followers[numfollowers].zoffs = 32;
followers[numfollowers].horzlag = 2;
followers[numfollowers].vertlag = 6;
followers[numfollowers].bobspeed = TICRATE*2;
followers[numfollowers].bobamp = 4;
followers[numfollowers].hitconfirmtime = TICRATE;
followers[numfollowers].defaultcolor = 1;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " = ");
if (!word2)
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
if (fastcmp(word, "NAME"))
{
DEH_WriteUndoline(word, va("%s", followers[numfollowers].name), UNDO_NONE);
strcpy(followers[numfollowers].name, word2);
nameset = true;
}
else if (fastcmp(word, "DEFAULTCOLOR"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].defaultcolor), UNDO_NONE);
followers[numfollowers].defaultcolor = (UINT8)get_number(word2);
}
else if (fastcmp(word, "SCALE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].scale), UNDO_NONE);
followers[numfollowers].scale = get_number(word2);
}
else if (fastcmp(word, "BUBBLESCALE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].bubblescale), UNDO_NONE);
followers[numfollowers].bubblescale = get_number(word2);
}
else if (fastcmp(word, "ATANGLE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].atangle), UNDO_NONE);
followers[numfollowers].atangle = (INT32)atoi(word2);
}
else if (fastcmp(word, "HORZLAG"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].horzlag), UNDO_NONE);
followers[numfollowers].horzlag = (INT32)atoi(word2);
}
else if (fastcmp(word, "VERTLAG"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].vertlag), UNDO_NONE);
followers[numfollowers].vertlag = (INT32)atoi(word2);
}
else if (fastcmp(word, "BOBSPEED"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].bobspeed), UNDO_NONE);
followers[numfollowers].bobspeed = (INT32)atoi(word2);
}
else if (fastcmp(word, "BOBAMP"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].bobamp), UNDO_NONE);
followers[numfollowers].bobamp = (INT32)atoi(word2);
}
else if (fastcmp(word, "ZOFFSET") || (fastcmp(word, "ZOFFS")))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].zoffs), UNDO_NONE);
followers[numfollowers].zoffs = (INT32)atoi(word2);
}
else if (fastcmp(word, "DISTANCE") || (fastcmp(word, "DIST")))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].dist), UNDO_NONE);
followers[numfollowers].dist = (INT32)atoi(word2);
}
else if (fastcmp(word, "HEIGHT"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].height), UNDO_NONE);
followers[numfollowers].height = (INT32)atoi(word2);
}
else if (fastcmp(word, "IDLESTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].idlestate), UNDO_NONE);
followers[numfollowers].idlestate = get_number(word2);
fallbackstate = followers[numfollowers].idlestate;
}
else if (fastcmp(word, "FOLLOWSTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].followstate), UNDO_NONE);
followers[numfollowers].followstate = get_number(word2);
}
else if (fastcmp(word, "HURTSTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].hurtstate), UNDO_NONE);
followers[numfollowers].hurtstate = get_number(word2);
}
else if (fastcmp(word, "LOSESTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].losestate), UNDO_NONE);
followers[numfollowers].losestate = get_number(word2);
}
else if (fastcmp(word, "WINSTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].winstate), UNDO_NONE);
followers[numfollowers].winstate = get_number(word2);
}
else if (fastcmp(word, "HITSTATE") || (fastcmp(word, "HITCONFIRMSTATE")))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].hitconfirmstate), UNDO_NONE);
followers[numfollowers].hitconfirmstate = get_number(word2);
}
else if (fastcmp(word, "HITTIME") || (fastcmp(word, "HITCONFIRMTIME")))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].hitconfirmtime), UNDO_NONE);
followers[numfollowers].hitconfirmtime = (INT32)atoi(word2);
}
else
deh_warning("Follower %d: unknown word '%s'", numfollowers, word);
}
} while (!myfeof(f)); // finish when the line is empty
if (!nameset) // well this is problematic.
{
strcpy(followers[numfollowers].name, va("Follower%d", numfollowers)); // this is lazy, so what
}
// set skin name (this is just the follower's name in lowercases):
// but before we do, let's... actually check if another follower isn't doing the same shit...
strcpy(testname, followers[numfollowers].name);
// lower testname for skin checks...
strlwr(testname);
res = R_FollowerAvailable(testname);
if (res > -1) // yikes, someone else has stolen our name already
{
INT32 startlen = strlen(testname);
char cpy[2];
//deh_warning("There was already a follower with the same name. (%s)", testname); This warning probably isn't necessary anymore?
sprintf(cpy, "%d", numfollowers);
memcpy(&testname[startlen], cpy, 2);
// in that case, we'll be very lazy and copy numfollowers to the end of our skin name.
}
strcpy(followers[numfollowers].skinname, testname);
strcpy(dname, followers[numfollowers].skinname); // display name, just used for printing succesful stuff or errors later down the line.
// now that the skin name is ready, post process the actual name to turn the underscores into spaces!
for (i = 0; followers[numfollowers].name[i]; i++)
{
if (followers[numfollowers].name[i] == '_')
followers[numfollowers].name[i] = ' ';
}
// fallbacks for variables
// Print a warning if the variable is on a weird value and set it back to the minimum available if that's the case.
#define FALLBACK(field, field2, threshold, set) \
if (followers[numfollowers].field < threshold) \
{ \
followers[numfollowers].field = set; \
deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, set, set); \
} \
FALLBACK(dist, "DIST", 0, 0);
FALLBACK(height, "HEIGHT", 1, 1);
FALLBACK(zoffs, "ZOFFS", 0, 0);
FALLBACK(horzlag, "HORZLAG", 1, 1);
FALLBACK(vertlag, "VERTLAG", 1, 1);
FALLBACK(bobamp, "BOBAMP", 0, 0);
FALLBACK(bobspeed, "BOBSPEED", 0, 0);
FALLBACK(hitconfirmtime, "HITCONFIRMTIME", 1, 1);
FALLBACK(scale, "SCALE", 1, 1); // No null/negative scale
FALLBACK(bubblescale, "BUBBLESCALE", 0, 0); // No negative scale
// Special case for color I suppose
if (followers[numfollowers].defaultcolor > MAXSKINCOLORS-1)
{
followers[numfollowers].defaultcolor = 1;
deh_warning("Follower \'%s\': Value for 'color' should be between 1 and %d.\n", dname, MAXSKINCOLORS-1);
}
#undef FALLBACK
// also check if we forgot states. If we did, we will set any missing state to the follower's idlestate.
// Print a warning in case we don't have a fallback and set the state to S_INVISIBLE (rather than S_NULL) if unavailable.
#define NOSTATE(field, field2) \
if (!followers[numfollowers].field) \
{ \
followers[numfollowers].field = fallbackstate ? fallbackstate : S_INVISIBLE; \
if (!fallbackstate) \
deh_warning("Follower '%s' is missing state definition for '%s', no idlestate fallback was found", dname, field2); \
} \
NOSTATE(idlestate, "IDLESTATE");
NOSTATE(followstate, "FOLLOWSTATE");
NOSTATE(hurtstate, "HURTSTATE");
NOSTATE(losestate, "LOSESTATE");
NOSTATE(winstate, "WINSTATE");
NOSTATE(hitconfirmstate, "HITCONFIRMSTATE");
#undef NOSTATE
CONS_Printf("Added follower '%s'\n", dname);
numfollowers++; // add 1 follower
Z_Free(s);
}
static void readthing(MYFILE *f, INT32 num)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -3418,6 +3684,13 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad)
// This is not a major mod.
continue;
}
else if (fastcmp(word, "FOLLOWER"))
{
readfollower(f); // at the same time this will be our only way to ADD followers for now. Yikes.
DEH_WriteUndoline(word, "", UNDO_HEADER);
// This is not a major mod either.
continue; // continue so that we don't error.
}
word2 = strtok(NULL, " ");
if (fastcmp(word, "CHARACTER"))
{
@ -6312,6 +6585,39 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_DRIFTEXPLODE2",
"S_DRIFTEXPLODE3",
"S_DRIFTEXPLODE4",
"S_DRIFTEXPLODE5",
"S_DRIFTEXPLODE6",
"S_DRIFTEXPLODE7",
"S_DRIFTEXPLODE8",
// Drift boost clip
"S_DRIFTCLIPA1",
"S_DRIFTCLIPA2",
"S_DRIFTCLIPA3",
"S_DRIFTCLIPA4",
"S_DRIFTCLIPA5",
"S_DRIFTCLIPA6",
"S_DRIFTCLIPA7",
"S_DRIFTCLIPA8",
"S_DRIFTCLIPA9",
"S_DRIFTCLIPA10",
"S_DRIFTCLIPA11",
"S_DRIFTCLIPA12",
"S_DRIFTCLIPA13",
"S_DRIFTCLIPA14",
"S_DRIFTCLIPA15",
"S_DRIFTCLIPA16",
"S_DRIFTCLIPB1",
"S_DRIFTCLIPB2",
"S_DRIFTCLIPB3",
"S_DRIFTCLIPB4",
"S_DRIFTCLIPB5",
"S_DRIFTCLIPB6",
"S_DRIFTCLIPB7",
"S_DRIFTCLIPB8",
// Drift boost clip spark
"S_DRIFTCLIPSPARK",
// Sneaker boost effect
"S_BOOSTFLAME",
@ -7207,6 +7513,31 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_OPAQUESMOKE4",
"S_OPAQUESMOKE5",
"S_FOLLOWERBUBBLE_FRONT",
"S_FOLLOWERBUBBLE_BACK",
"S_GCHAOIDLE",
"S_GCHAOFLY",
"S_GCHAOSAD1",
"S_GCHAOSAD2",
"S_GCHAOSAD3",
"S_GCHAOSAD4",
"S_GCHAOHAPPY1",
"S_GCHAOHAPPY2",
"S_GCHAOHAPPY3",
"S_GCHAOHAPPY4",
"S_CHEESEIDLE",
"S_CHEESEFLY",
"S_CHEESESAD1",
"S_CHEESESAD2",
"S_CHEESESAD3",
"S_CHEESESAD4",
"S_CHEESEHAPPY1",
"S_CHEESEHAPPY2",
"S_CHEESEHAPPY3",
"S_CHEESEHAPPY4",
"S_RINGDEBT",
"S_RINGSPARKS1",
"S_RINGSPARKS2",
@ -7795,6 +8126,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_FASTLINE",
"MT_FASTDUST",
"MT_DRIFTEXPLODE",
"MT_DRIFTCLIP",
"MT_DRIFTCLIPSPARK",
"MT_BOOSTFLAME",
"MT_BOOSTSMOKE",
"MT_SNEAKERTRAIL",
@ -8074,6 +8407,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BATTLECAPSULE",
"MT_BATTLECAPSULE_PIECE",
"MT_FOLLOWER",
"MT_FOLLOWERBUBBLE_FRONT",
"MT_FOLLOWERBUBBLE_BACK",
"MT_WATERTRAIL",
"MT_WATERTRAILUNDERLAY",
@ -8122,7 +8459,7 @@ static const char *const MOBJFLAG2_LIST[] = {
"AXIS", // It's a NiGHTS axis! (For faster checking)
"TWOD", // Moves like it's in a 2D level
"DONTRESPAWN", // Don't respawn this object!
"DONTDRAW", // Don't generate a vissprite
"\x01", // free: 1<<3 (name un-matchable)
"AUTOMATIC", // Thrown ring has automatic properties
"RAILRING", // Thrown ring has rail properties
"BOUNCERING", // Thrown ring has bounce properties
@ -8139,7 +8476,7 @@ static const char *const MOBJFLAG2_LIST[] = {
"JUSTATTACKED", // can be pushed by other moving mobjs
"FIRING", // turret fire
"SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
"SHADOW", // Fuzzy draw, makes targeting harder.
"\x01", // free: 1<<20 (name un-matchable)
"STRONGBOX", // Flag used for "strong" random monitors.
"OBJECTFLIP", // Flag for objects that always have flipped gravity.
"SKULLFLY", // Special handling: skull in flight.
@ -8162,10 +8499,6 @@ static const char *const MOBJEFLAG_LIST[] = {
"JUSTBOUNCEDWALL", // SRB2Kart: Mobj already bounced off a wall this tic
"SPRUNG", // Mobj was already sprung this tic
"APPLYPMOMZ", // Platform movement
"DRAWONLYFORP1", // SRB2Kart: Splitscreen sprite draw flags
"DRAWONLYFORP2",
"DRAWONLYFORP3",
"DRAWONLYFORP4",
NULL
};
@ -9099,6 +9432,29 @@ struct {
{"TC_ALLWHITE",TC_ALLWHITE},
{"TC_RAINBOW",TC_RAINBOW},
{"TC_BLINK",TC_BLINK},
// MFD_ draw flag enum
{"MFD_DONTDRAWP1",MFD_DONTDRAWP1},
{"MFD_DONTDRAWP2",MFD_DONTDRAWP2},
{"MFD_DONTDRAWP3",MFD_DONTDRAWP3},
{"MFD_DONTDRAWP4",MFD_DONTDRAWP4},
{"MFD_TRANS10",MFD_TRANS10},
{"MFD_TRANS20",MFD_TRANS20},
{"MFD_TRANS30",MFD_TRANS30},
{"MFD_TRANS40",MFD_TRANS40},
{"MFD_TRANS50",MFD_TRANS50},
{"MFD_TRANS60",MFD_TRANS60},
{"MFD_TRANS70",MFD_TRANS70},
{"MFD_TRANS80",MFD_TRANS80},
{"MFD_TRANS90",MFD_TRANS90},
{"MFD_TRANSMASK",MFD_TRANSMASK},
{"MFD_FULLBRIGHT",MFD_FULLBRIGHT},
{"MFD_SEMIBRIGHT",MFD_SEMIBRIGHT},
{"MFD_NOBRIGHT",MFD_NOBRIGHT},
{"MFD_BRIGHTMASK",MFD_BRIGHTMASK},
{"MFD_DONTDRAW",MFD_DONTDRAW},
{"MFD_SHADOW",MFD_SHADOW},
{"MFD_TRANSSHIFT",MFD_TRANSSHIFT},
#endif
{NULL,0}

View file

@ -2535,7 +2535,7 @@ static inline void G_PlayerFinishLevel(INT32 player)
memset(p->kartstuff, 0, sizeof (p->kartstuff)); // SRB2kart
p->ringweapons = 0;
p->mo->flags2 &= ~MF2_SHADOW; // cancel invisibility
p->mo->drawflags &= ~(MFD_TRANSMASK|MFD_BRIGHTMASK); // cancel invisibility
P_FlashPal(p, 0, 0); // Resets
p->starpostnum = 0;
@ -2570,6 +2570,10 @@ void G_PlayerReborn(INT32 player)
// SRB2kart
UINT8 kartspeed;
UINT8 kartweight;
boolean followerready;
INT32 followerskin;
UINT8 followercolor;
mobj_t *follower; // old follower, will probably be removed by the time we're dead but you never know.
//
INT32 charflags;
INT32 pflags;
@ -2630,6 +2634,10 @@ void G_PlayerReborn(INT32 player)
// SRB2kart
kartspeed = players[player].kartspeed;
kartweight = players[player].kartweight;
follower = players[player].follower;
followerready = players[player].followerready;
followercolor = players[player].followercolor;
followerskin = players[player].followerskin;
//
charflags = players[player].charflags;
@ -2684,6 +2692,9 @@ void G_PlayerReborn(INT32 player)
wanted = players[player].kartstuff[k_wanted];
}
// Obliterate follower from existence
P_SetTarget(&players[player].follower, NULL);
memcpy(&respawn, &players[player].respawn, sizeof (respawn));
p = &players[player];
@ -2740,6 +2751,16 @@ void G_PlayerReborn(INT32 player)
memcpy(&p->respawn, &respawn, sizeof (p->respawn));
if (follower)
P_RemoveMobj(follower);
p->followerready = followerready;
p->followerskin = followerskin;
p->followercolor = followercolor;
//p->follower = NULL; // respawn a new one with you, it looks better.
// ^ Not necessary anyway since it will be respawned regardless considering it doesn't exist anymore.
// Don't do anything immediately
p->pflags |= PF_USEDOWN;
p->pflags |= PF_ATTACKDOWN;
@ -3207,7 +3228,7 @@ void G_AddPlayer(INT32 playernum)
p->jointime = 0;
p->playerstate = PST_REBORN;
demo_extradata[playernum] |= DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN; // Set everything
demo_extradata[playernum] |= DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER; // Set everything
}
void G_ExitLevel(void)
@ -4936,6 +4957,25 @@ void G_ReadDemoExtraData(void)
// Name
M_Memcpy(player_names[p],demo_p,16);
demo_p += 16;
}
if (extradata & DXD_FOLLOWER)
{
// Set our follower
M_Memcpy(name, demo_p, 16);
demo_p += 16;
SetPlayerFollower(p, name);
// Follower's color
M_Memcpy(name, demo_p, 16);
demo_p += 16;
for (i = 0; i < MAXSKINCOLORS; i++)
if (!stricmp(KartColor_Names[i], name)) // SRB2kart
{
players[p].followercolor = i;
break;
}
}
if (extradata & DXD_PLAYSTATE)
{
@ -5039,6 +5079,7 @@ void G_WriteDemoExtraData(void)
WRITEUINT8(demo_p, skins[players[i].skin].kartspeed);
WRITEUINT8(demo_p, skins[players[i].skin].kartweight);
}
if (demo_extradata[i] & DXD_COLOR)
{
@ -5056,6 +5097,21 @@ void G_WriteDemoExtraData(void)
M_Memcpy(demo_p,name,16);
demo_p += 16;
}
if (demo_extradata[i] & DXD_FOLLOWER)
{
// write follower
memset(name, 0, 16);
strncpy(name, followers[players[i].followerskin].skinname, 16);
M_Memcpy(demo_p, name, 16);
demo_p += 16;
// write follower color
memset(name, 0, 16);
strncpy(name, Followercolor_cons_t[players[i].followercolor].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match"
M_Memcpy(demo_p,name,16);
demo_p += 16;
}
if (demo_extradata[i] & DXD_PLAYSTATE)
{
demo_writerng = 1;
@ -5656,6 +5712,8 @@ void G_GhostTicker(void)
g->p += 16; // Same tbh
if (ziptic & DXD_NAME)
g->p += 16; // yea
if (ziptic & DXD_FOLLOWER)
g->p += 32; // ok (32 because there's both the skin and the colour)
if (ziptic & DXD_PLAYSTATE && READUINT8(g->p) != DXD_PST_PLAYING)
I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this
}
@ -5961,7 +6019,7 @@ void G_PreviewRewind(tic_t previewtime)
if (!info->playerinfo[i].ingame || !info->playerinfo[i].player.mo)
{
if (players[i].mo)
players[i].mo->flags2 |= MF2_DONTDRAW;
players[i].mo->drawflags |= MFD_DONTDRAW;
continue;
}
@ -5969,7 +6027,7 @@ void G_PreviewRewind(tic_t previewtime)
if (!players[i].mo)
continue; //@TODO spawn temp object to act as a player display
players[i].mo->flags2 &= ~MF2_DONTDRAW;
players[i].mo->drawflags &= ~MFD_DONTDRAW;
P_UnsetThingPosition(players[i].mo);
#define TWEEN(pr) info->playerinfo[i].mobj.pr + FixedMul((INT32) (next_info->playerinfo[i].mobj.pr - info->playerinfo[i].mobj.pr), tweenvalue)
@ -6394,6 +6452,12 @@ void G_BeginRecording(void)
CV_SaveNetVars(&demo_p, true);
// Now store some info for each in-game player
// Lat' 12/05/19: Do note that for the first game you load, everything that gets saved here is total garbage;
// The name will always be Player <n>, the skin sonic, the color None and the follower 0. This is only correct on subsequent games.
// In the case of said first game, the skin and the likes are updated with Got_NameAndColor, which are then saved in extradata for the demo with DXD_SKIN in r_things.c for instance.
for (p = 0; p < MAXPLAYERS; p++) {
if (playeringame[p]) {
player = &players[p];
@ -6418,6 +6482,25 @@ void G_BeginRecording(void)
M_Memcpy(demo_p,name,16);
demo_p += 16;
// Save follower's skin name
// PS: We must check for 'follower' to determine if the followerskin is valid. It's going to be 0 if we don't have a follower, but 0 is also absolutely a valid follower!
// Doesn't really matter if the follower mobj is valid so long as it exists in a way or another.
memset(name, 0, 16);
if (player->follower)
strncpy(name, followers[player->followerskin].skinname, 16);
else
strncpy(name, "None", 16); // Say we don't have one, then.
M_Memcpy(demo_p,name,16);
demo_p += 16;
// Save follower's colour
memset(name, 0, 16);
strncpy(name, Followercolor_cons_t[player->followercolor].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match"
M_Memcpy(demo_p, name, 16);
demo_p += 16;
// Score, since Kart uses this to determine where you start on the map
WRITEUINT32(demo_p, player->score);
@ -7017,7 +7100,7 @@ void G_DoPlayDemo(char *defdemoname)
{
UINT8 i, p;
lumpnum_t l;
char skin[17],color[17],*n,*pdemoname;
char skin[17],color[17],follower[17],*n,*pdemoname;
UINT8 version,subversion;
UINT32 randseed;
char msg[1024];
@ -7031,6 +7114,7 @@ void G_DoPlayDemo(char *defdemoname)
skin[16] = '\0';
color[16] = '\0';
follower[16] = '\0';
// No demo name means we're restarting the current demo
if (defdemoname == NULL)
@ -7345,6 +7429,23 @@ void G_DoPlayDemo(char *defdemoname)
break;
}
// Follower
M_Memcpy(follower, demo_p, 16);
demo_p += 16;
SetPlayerFollower(p, follower);
// Follower colour
M_Memcpy(color, demo_p, 16);
demo_p += 16;
for (i = 0; i < MAXSKINCOLORS +2; i++) // +2 because of Match and Opposite
{
if (!stricmp(Followercolor_cons_t[i].strvalue, color))
{
players[p].followercolor = i;
break;
}
}
// Score, since Kart uses this to determine where you start on the map
players[p].score = READUINT32(demo_p);
@ -7574,6 +7675,9 @@ void G_AddGhost(char *defdemoname)
M_Memcpy(color, p, 16);
p += 16;
// Follower data was here, skip it, we don't care about it for ghosts.
p += 32; // followerskin (16) + followercolor (16)
p += 4; // score
p += 2; // powerlevel

View file

@ -226,6 +226,7 @@ extern UINT8 demo_writerng;
#define DXD_NAME 0x04 // name changed
#define DXD_COLOR 0x08 // color changed
#define DXD_PLAYSTATE 0x10 // state changed between playing, spectating, or not in-game
#define DXD_FOLLOWER 0x20 // follower was changed
#define DXD_PST_PLAYING 0x01
#define DXD_PST_SPECTATING 0x02

View file

@ -2973,6 +2973,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
FUINT lightlevel;
FBITFIELD blend = 0;
UINT8 alpha;
UINT8 brightmode = 0;
INT32 i;
float realtop, realbot, top, bot;
@ -3071,16 +3072,8 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
// co-ordinates
memcpy(wallVerts, baseWallVerts, sizeof(baseWallVerts));
if (!cv_translucency.value) // translucency disabled
{
Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|PF_Occlude;
}
else if (spr->mobj->flags2 & MF2_SHADOW)
{
Surf.PolyColor.s.alpha = 0x40;
blend = PF_Translucent;
}
if (spr->mobj->drawflags & MFD_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
@ -3097,15 +3090,30 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
temp = FLOAT_TO_FIXED(realtop);
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
#ifdef ESLOPE
// Start with the lightlevel and colormap from the top of the sprite
lightlevel = 255;
colormap = list[sector->numlights - 1].extra_colormap;
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
{
lightlevel = *list[sector->numlights - 1].lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
}
@ -3115,10 +3123,10 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
: sector->lightlist[i].height;
if (h <= temp)
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
{
lightlevel = *list[i-1].lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
}
colormap = list[i-1].extra_colormap;
@ -3127,10 +3135,10 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
}
#else
i = R_GetPlaneLight(sector, temp, false);
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
{
lightlevel = *list[i].lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
}
colormap = list[i].extra_colormap;
@ -3147,10 +3155,10 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
// even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite
if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES))
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
{
lightlevel = *list[i].lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
}
colormap = list[i].extra_colormap;
@ -3427,12 +3435,28 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
{
sector_t *sector = spr->mobj->subsector->sector;
UINT8 lightlevel = 255;
UINT8 brightmode = 0;
extracolormap_t *colormap = sector->extra_colormap;
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
if (brightmode != 1)
{
lightlevel = sector->lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
}
@ -3441,16 +3465,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
{
FBITFIELD blend = 0;
if (!cv_translucency.value) // translucency disabled
{
Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|PF_Occlude;
}
else if (spr->mobj->flags2 & MF2_SHADOW)
{
Surf.PolyColor.s.alpha = 0x40;
blend = PF_Translucent;
}
if (spr->mobj->drawflags & MFD_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
@ -3519,15 +3536,31 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
{
sector_t *sector = spr->mobj->subsector->sector;
UINT8 lightlevel = 255;
UINT8 brightmode = 0;
extracolormap_t *colormap = sector->extra_colormap;
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
if (sector->numlights)
{
INT32 light;
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
lightlevel = *sector->lightlist[light].lightlevel;
if (sector->lightlist[light].extra_colormap)
@ -3535,24 +3568,21 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
}
else
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
lightlevel = sector->lightlevel;
if (sector->extra_colormap)
colormap = sector->extra_colormap;
}
if (spr->mobj->frame & FF_SEMIBRIGHT)
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
HWR_Lighting(&Surf, lightlevel, colormap);
}
if (spr->mobj->flags2 & MF2_SHADOW)
{
Surf.PolyColor.s.alpha = 0x40;
blend = PF_Translucent;
}
if (spr->mobj->drawflags & MFD_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
@ -3587,8 +3617,14 @@ static int CompareVisSprites(const void *p1, const void *p2)
// make transparent sprites last
// "boolean to int"
int transparency1 = (spr1->mobj->flags2 & MF2_SHADOW) || (spr1->mobj->frame & FF_TRANSMASK);
int transparency2 = (spr2->mobj->flags2 & MF2_SHADOW) || (spr2->mobj->frame & FF_TRANSMASK);
int transparency1 = (spr1->mobj->drawflags & FF_TRANSMASK) ?
((spr1->mobj->drawflags & FF_TRANSMASK)>>MFD_TRANSSHIFT) :
((spr1->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT);
int transparency2 = (spr2->mobj->drawflags & FF_TRANSMASK) ?
((spr2->mobj->drawflags & FF_TRANSMASK)>>MFD_TRANSSHIFT) :
((spr2->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT);
idiff = transparency1 - transparency2;
if (idiff != 0) return idiff;
@ -3962,9 +3998,6 @@ void HWR_AddSprites(sector_t *sec)
precipmobj_t *precipthing;
fixed_t approx_dist, limit_dist;
INT32 splitflags;
boolean split_drawsprite; // drawing with splitscreen flags
// BSP is traversed by subsector.
// A sector might have been split into several
// subsectors during BSP building.
@ -3981,36 +4014,13 @@ void HWR_AddSprites(sector_t *sec)
{
for (thing = sec->thinglist; thing; thing = thing->snext)
{
split_drawsprite = false;
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
if (thing->sprite == SPR_NULL)
continue;
splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
if (r_splitscreen && splitflags)
{
if (thing->eflags & MFE_DRAWONLYFORP1)
if (viewssnum == 0)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP2)
if (viewssnum == 1)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1)
if (viewssnum == 2)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2)
if (viewssnum == 3)
split_drawsprite = true;
}
else
split_drawsprite = true;
if (!split_drawsprite)
if ((viewssnum == 0 && (thing->drawflags & MFD_DONTDRAWP1))
|| (viewssnum == 1 && (thing->drawflags & MFD_DONTDRAWP2))
|| (viewssnum == 2 && (thing->drawflags & MFD_DONTDRAWP3))
|| (viewssnum == 3 && (thing->drawflags & MFD_DONTDRAWP4)))
continue;
approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
@ -4026,36 +4036,13 @@ void HWR_AddSprites(sector_t *sec)
// Draw everything in sector, no checks
for (thing = sec->thinglist; thing; thing = thing->snext)
{
split_drawsprite = false;
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
if (thing->sprite == SPR_NULL)
continue;
splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
if (r_splitscreen && splitflags)
{
if (thing->eflags & MFE_DRAWONLYFORP1)
if (viewssnum == 0)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP2)
if (viewssnum == 1)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1)
if (viewssnum == 2)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2)
if (viewssnum == 3)
split_drawsprite = true;
}
else
split_drawsprite = true;
if (!split_drawsprite)
if ((viewssnum == 0 && (thing->drawflags & MFD_DONTDRAWP1))
|| (viewssnum == 1 && (thing->drawflags & MFD_DONTDRAWP2))
|| (viewssnum == 2 && (thing->drawflags & MFD_DONTDRAWP3))
|| (viewssnum == 3 && (thing->drawflags & MFD_DONTDRAWP4)))
continue;
HWR_ProjectSprite(thing);

View file

@ -1083,6 +1083,22 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
sector_t *sector = spr->mobj->subsector->sector;
extracolormap_t *colormap = sector->extra_colormap;
UINT8 lightlevel = 255;
UINT8 brightmode = 0;
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
if (sector->numlights)
{
@ -1090,7 +1106,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
lightlevel = *sector->lightlist[light].lightlevel;
if (sector->lightlist[light].extra_colormap)
@ -1098,13 +1114,16 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
}
else
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
if (brightmode != 1)
lightlevel = sector->lightlevel;
if (sector->extra_colormap)
colormap = sector->extra_colormap;
}
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
HWR_Lighting(&Surf, lightlevel, colormap);
}
else
@ -1131,8 +1150,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
//if (tics > durs)
//durs = tics;
if (spr->mobj->flags2 & MF2_SHADOW)
Surf.PolyColor.s.alpha = 0x40;
if (spr->mobj->drawflags & MFD_TRANSMASK)
HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else

View file

@ -53,6 +53,7 @@ char sprnames[NUMSPRITES + 1][5] =
"SRBB","SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK",
"SRBL","SRBM","SRBN","SRBO",
//SRB2kart Sprites
"RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE","KINV","KINF",
"WIPD","DRIF","BDRF","DUST","DRWS","RSHE","FITM","BANA","ORBN","JAWZ","SSMN",
"KRBM","BHOG","BHBM","SPBM","THNS","BUBS","BWVE",
@ -69,8 +70,9 @@ char sprnames[NUMSPRITES + 1][5] =
"ICEB","CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS",
"ZTCH","MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH",
"BFRT","OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN",
"FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","EGOO","WTRL","XMS4",
"XMS5","VIEW"
"XMS5","FBUB","GCHA","CHEZ","VIEW","DBCL","DBNC","DBST",
};
// Doesn't work with g++, needs actionf_p1 (don't modify this comment)
@ -2558,10 +2560,42 @@ state_t states[NUMSTATES] =
{SPR_DSHR, FF_PAPERSPRITE|5, 1, {NULL}, 0, 0, S_FASTDUST7}, // S_FASTDUST6
{SPR_DSHR, FF_PAPERSPRITE|6, 1, {NULL}, 0, 0, S_NULL}, // S_FASTDUST7
{SPR_DBOS, FF_FULLBRIGHT, 2, {NULL}, 6, 1, S_DRIFTEXPLODE2}, // S_DRIFTEXPLODE1
{SPR_DBOS, FF_FULLBRIGHT|1, 2, {NULL}, 6, 1, S_DRIFTEXPLODE3}, // S_DRIFTEXPLODE2
{SPR_DBOS, FF_FULLBRIGHT|2, 2, {NULL}, 6, 1, S_DRIFTEXPLODE4}, // S_DRIFTEXPLODE3
{SPR_DBOS, FF_FULLBRIGHT|3, 2, {NULL}, 6, 1, S_DRIFTEXPLODE1}, // S_DRIFTEXPLODE4
{SPR_DBOS, FF_FULLBRIGHT, 1, {NULL}, 6, 1, S_DRIFTEXPLODE2}, // S_DRIFTEXPLODE1
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT, 1, {NULL}, 6, 1, S_DRIFTEXPLODE3}, // S_DRIFTEXPLODE2
{SPR_DBOS, FF_FULLBRIGHT|1, 1, {NULL}, 6, 1, S_DRIFTEXPLODE4}, // S_DRIFTEXPLODE3
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT|1, 1, {NULL}, 6, 1, S_DRIFTEXPLODE5}, // S_DRIFTEXPLODE4
{SPR_DBOS, FF_FULLBRIGHT|2, 1, {NULL}, 6, 1, S_DRIFTEXPLODE6}, // S_DRIFTEXPLODE5
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT|2, 1, {NULL}, 6, 1, S_DRIFTEXPLODE7}, // S_DRIFTEXPLODE6
{SPR_DBOS, FF_FULLBRIGHT|3, 1, {NULL}, 6, 1, S_DRIFTEXPLODE8}, // S_DRIFTEXPLODE7
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT|3, 1, {NULL}, 6, 1, S_DRIFTEXPLODE1}, // S_DRIFTEXPLODE8
{SPR_DBCL, FF_FULLBRIGHT|0x0, 1, {NULL}, 6, 1, S_DRIFTCLIPA2}, // S_DRIFTCLIPA1
{SPR_DBCL, FF_FULLBRIGHT|0x8, 1, {NULL}, 6, 1, S_DRIFTCLIPA3}, // S_DRIFTCLIPA2
{SPR_DBCL, FF_FULLBRIGHT|0x1, 1, {NULL}, 6, 1, S_DRIFTCLIPA4}, // S_DRIFTCLIPA3
{SPR_DBCL, FF_FULLBRIGHT|0x9, 1, {NULL}, 6, 1, S_DRIFTCLIPA5}, // S_DRIFTCLIPA4
{SPR_DBCL, FF_FULLBRIGHT|0x2, 1, {NULL}, 6, 1, S_DRIFTCLIPA6}, // S_DRIFTCLIPA5
{SPR_DBCL, FF_FULLBRIGHT|0xA, 1, {NULL}, 6, 1, S_DRIFTCLIPA7}, // S_DRIFTCLIPA6
{SPR_DBCL, FF_FULLBRIGHT|0x3, 1, {NULL}, 6, 1, S_DRIFTCLIPA8}, // S_DRIFTCLIPA7
{SPR_DBCL, FF_FULLBRIGHT|0xB, 1, {NULL}, 6, 1, S_DRIFTCLIPA9}, // S_DRIFTCLIPA8
{SPR_DBCL, FF_FULLBRIGHT|0x4, 1, {NULL}, 6, 1, S_DRIFTCLIPA10}, // S_DRIFTCLIPA9
{SPR_DBCL, FF_FULLBRIGHT|0xC, 1, {NULL}, 6, 1, S_DRIFTCLIPA11}, // S_DRIFTCLIPA10
{SPR_DBCL, FF_FULLBRIGHT|0x5, 1, {NULL}, 6, 1, S_DRIFTCLIPA12}, // S_DRIFTCLIPA11
{SPR_DBCL, FF_FULLBRIGHT|0xD, 1, {NULL}, 6, 1, S_DRIFTCLIPA13}, // S_DRIFTCLIPA12
{SPR_DBCL, FF_FULLBRIGHT|0x6, 1, {NULL}, 6, 1, S_DRIFTCLIPA14}, // S_DRIFTCLIPA13
{SPR_DBCL, FF_FULLBRIGHT|0xE, 1, {NULL}, 6, 1, S_DRIFTCLIPA15}, // S_DRIFTCLIPA14
{SPR_DBCL, FF_FULLBRIGHT|0x7, 1, {NULL}, 6, 1, S_DRIFTCLIPA16}, // S_DRIFTCLIPA15
{SPR_DBCL, FF_FULLBRIGHT|0xF, 1, {NULL}, 6, 1, S_DRIFTCLIPB1}, // S_DRIFTCLIPA16
{SPR_DBCL, FF_FULLBRIGHT, 2, {NULL}, 6, 1, S_DRIFTCLIPB2}, // S_DRIFTCLIPB1
{SPR_DBCL, FF_FULLBRIGHT|1, 2, {NULL}, 6, 1, S_DRIFTCLIPB3}, // S_DRIFTCLIPB2
{SPR_DBCL, FF_FULLBRIGHT|2, 2, {NULL}, 6, 1, S_DRIFTCLIPB4}, // S_DRIFTCLIPB3
{SPR_DBCL, FF_FULLBRIGHT|3, 2, {NULL}, 6, 1, S_DRIFTCLIPB5}, // S_DRIFTCLIPB4
{SPR_DBCL, FF_FULLBRIGHT|4, 2, {NULL}, 6, 1, S_DRIFTCLIPB6}, // S_DRIFTCLIPB5
{SPR_DBCL, FF_FULLBRIGHT|5, 2, {NULL}, 6, 1, S_DRIFTCLIPB7}, // S_DRIFTCLIPB6
{SPR_DBCL, FF_FULLBRIGHT|6, 2, {NULL}, 6, 1, S_DRIFTCLIPB8}, // S_DRIFTCLIPB7
{SPR_DBCL, FF_FULLBRIGHT|7, 2, {NULL}, 6, 1, S_DRIFTCLIPB1}, // S_DRIFTCLIPB8
{SPR_DBNC, FF_FULLBRIGHT|FF_ANIMATE, 14, {NULL}, 6, 1, S_NULL}, // S_DRIFTCLIPSPARK
{SPR_BOST, FF_FULLBRIGHT|FF_ANIMATE, TICRATE, {NULL}, 6, 1, S_BOOSTSMOKESPAWNER}, // S_BOOSTFLAME
{SPR_NULL, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_BOOSTSMOKESPAWNER
@ -3461,6 +3495,37 @@ state_t states[NUMSTATES] =
{SPR_SMOK, 3, 7, {NULL}, 0, 0, S_OPAQUESMOKE5}, // S_OPAQUESMOKE4
{SPR_SMOK, 4, 8, {NULL}, 0, 0, S_NULL}, // S_OPAQUESMOKE5
// followers:
// bubble
{SPR_FBUB, 11|FF_ANIMATE|FF_TRANS70|FF_FULLBRIGHT, -1, {NULL}, 10, 3, S_FOLLOWERBUBBLE_FRONT}, // S_FOLLOWERBUBBLE_FRONT
{SPR_FBUB, FF_ANIMATE|0|FF_FULLBRIGHT, -1, {NULL}, 10, 3, S_FOLLOWERBUBBLE_BACK}, // S_FOLLOWERBUBBLE_BACK
// generic chao:
{SPR_GCHA, FF_ANIMATE, -1, {NULL}, 1, 4, S_GCHAOIDLE}, //S_GCHAOIDLE
{SPR_GCHA, 2|FF_ANIMATE, -1, {NULL}, 1, 2, S_GCHAOFLY}, //S_GCHAOFLY
{SPR_GCHA, 7, 5, {NULL}, 0, 0, S_GCHAOSAD2}, //S_GCHAOSAD1
{SPR_GCHA, 8, 3, {NULL}, 0, 0, S_GCHAOSAD3}, //S_GCHAOSAD2
{SPR_GCHA, 9, 6, {NULL}, 0, 0, S_GCHAOSAD4}, //S_GCHAOSAD3
{SPR_GCHA, 8, 3, {NULL}, 0, 0, S_GCHAOSAD1}, //S_GCHAOSAD4
{SPR_GCHA, 4, 8, {NULL}, 0, 0, S_GCHAOHAPPY2}, //S_GCHAOHAPPY1
{SPR_GCHA, 5, 4, {NULL}, 0, 0, S_GCHAOHAPPY3}, //S_GCHAOHAPPY2
{SPR_GCHA, 6, 8, {NULL}, 0, 0, S_GCHAOHAPPY4}, //S_GCHAOHAPPY3
{SPR_GCHA, 5, 4, {NULL}, 0, 0, S_GCHAOHAPPY1}, //S_GCHAOHAPPY4
// cheese:
{SPR_CHEZ, FF_ANIMATE, -1, {NULL}, 1, 4, S_CHEESEIDLE}, //S_CHEESEIDLE
{SPR_CHEZ, 2|FF_ANIMATE, -1, {NULL}, 1, 2, S_CHEESEFLY}, //S_CHEESEFLY
{SPR_CHEZ, 7, 5, {NULL}, 0, 0, S_CHEESESAD2}, //S_CHEESESAD1
{SPR_CHEZ, 8, 3, {NULL}, 0, 0, S_CHEESESAD3}, //S_CHEESESAD2
{SPR_CHEZ, 9, 6, {NULL}, 0, 0, S_CHEESESAD4}, //S_CHEESESAD3
{SPR_CHEZ, 8, 3, {NULL}, 0, 0, S_CHEESESAD1}, //S_CHEESESAD4
{SPR_CHEZ, 4, 8, {NULL}, 0, 0, S_CHEESEHAPPY2}, //S_CHEESEHAPPY1
{SPR_CHEZ, 5, 4, {NULL}, 0, 0, S_CHEESEHAPPY3}, //S_CHEESEHAPPY2
{SPR_CHEZ, 6, 8, {NULL}, 0, 0, S_CHEESEHAPPY4}, //S_CHEESEHAPPY3
{SPR_CHEZ, 5, 4, {NULL}, 0, 0, S_CHEESEHAPPY1}, //S_CHEESEHAPPY4
{SPR_MXCL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_RINGDEBT
{SPR_RGSP, FF_PAPERSPRITE|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_RINGSPARKS2}, // S_RINGSPARKS1
@ -15313,6 +15378,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_DRIFTCLIP
-1, // doomednum
S_DRIFTCLIPA1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
105, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_DONTENCOREMAP|MF_GRENADEBOUNCE|MF_BOUNCE, // flags
S_NULL // raisestate
},
{ // MT_DRIFTCLIPSPARK
-1, // doomednum
S_DRIFTCLIPSPARK, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
8, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BOOSTFLAME
-1, // doomednum
S_BOOSTFLAME, // spawnstate
@ -20553,6 +20672,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_RINGSPARKS
-1, // doomednum
S_RINGSPARKS1, // spawnstate
@ -20796,6 +20916,90 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FOLLOWER
-1, // doomednum
S_INVISIBLE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
{ // MT_FOLLOWERBUBBLE_FRONT
-1, // doomednum
S_FOLLOWERBUBBLE_FRONT, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
2, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
{ // MT_FOLLOWERBUBBLE_BACK
-1, // doomednum
S_FOLLOWERBUBBLE_BACK, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
-2, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
{ // MT_WATERTRAIL
-1, // doomednum
S_WATERTRAIL1, // spawnstate

View file

@ -804,9 +804,17 @@ typedef enum sprite
SPR_XMS4,
SPR_XMS5,
SPR_FBUB, // follower bubble
SPR_GCHA, // follower: generic chao
SPR_CHEZ, // follower: cheese
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
SPR_VIEW,
SPR_DBCL, // Drift boost clip
SPR_DBNC, // Drift boost clip's sparks
SPR_DBST, // Drift boost plume
SPR_FIRSTFREESLOT,
SPR_LASTFREESLOT = SPR_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1,
NUMSPRITES
@ -3242,6 +3250,39 @@ typedef enum state
S_DRIFTEXPLODE2,
S_DRIFTEXPLODE3,
S_DRIFTEXPLODE4,
S_DRIFTEXPLODE5,
S_DRIFTEXPLODE6,
S_DRIFTEXPLODE7,
S_DRIFTEXPLODE8,
// Drift boost clip
S_DRIFTCLIPA1,
S_DRIFTCLIPA2,
S_DRIFTCLIPA3,
S_DRIFTCLIPA4,
S_DRIFTCLIPA5,
S_DRIFTCLIPA6,
S_DRIFTCLIPA7,
S_DRIFTCLIPA8,
S_DRIFTCLIPA9,
S_DRIFTCLIPA10,
S_DRIFTCLIPA11,
S_DRIFTCLIPA12,
S_DRIFTCLIPA13,
S_DRIFTCLIPA14,
S_DRIFTCLIPA15,
S_DRIFTCLIPA16,
S_DRIFTCLIPB1,
S_DRIFTCLIPB2,
S_DRIFTCLIPB3,
S_DRIFTCLIPB4,
S_DRIFTCLIPB5,
S_DRIFTCLIPB6,
S_DRIFTCLIPB7,
S_DRIFTCLIPB8,
// Drift boost clip sparks
S_DRIFTCLIPSPARK,
// Sneaker boost effect
S_BOOSTFLAME,
@ -4152,6 +4193,36 @@ typedef enum state
S_OPAQUESMOKE4,
S_OPAQUESMOKE5,
// followers:
// bubble:
S_FOLLOWERBUBBLE_FRONT,
S_FOLLOWERBUBBLE_BACK,
// generic chao:
S_GCHAOIDLE,
S_GCHAOFLY,
S_GCHAOSAD1,
S_GCHAOSAD2,
S_GCHAOSAD3,
S_GCHAOSAD4,
S_GCHAOHAPPY1,
S_GCHAOHAPPY2,
S_GCHAOHAPPY3,
S_GCHAOHAPPY4,
// cheese:
S_CHEESEIDLE,
S_CHEESEFLY,
S_CHEESESAD1,
S_CHEESESAD2,
S_CHEESESAD3,
S_CHEESESAD4,
S_CHEESEHAPPY1,
S_CHEESEHAPPY2,
S_CHEESEHAPPY3,
S_CHEESEHAPPY4,
S_RINGDEBT,
S_RINGSPARKS1,
S_RINGSPARKS2,
@ -4757,6 +4828,8 @@ typedef enum mobj_type
MT_FASTLINE,
MT_FASTDUST,
MT_DRIFTEXPLODE,
MT_DRIFTCLIP,
MT_DRIFTCLIPSPARK,
MT_BOOSTFLAME,
MT_BOOSTSMOKE,
MT_SNEAKERTRAIL,
@ -5036,6 +5109,10 @@ typedef enum mobj_type
MT_BATTLECAPSULE,
MT_BATTLECAPSULE_PIECE,
MT_FOLLOWER,
MT_FOLLOWERBUBBLE_FRONT,
MT_FOLLOWERBUBBLE_BACK,
MT_WATERTRAIL,
MT_WATERTRAILUNDERLAY,

View file

@ -394,7 +394,7 @@ static void K_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjty
//mo->destscale = mo->scale/4;
mo->frame += ((leveltime/4) % 8);
/*if (battleovertime.enabled < 10*TICRATE)
mo->flags2 |= MF2_SHADOW;*/
mo->drawflags |= MFD_SHADOW;*/
mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90;
mo->z += P_RandomRange(0,48) * mo->scale;
break;

View file

@ -469,6 +469,10 @@ boolean K_BHeapPop(bheap_t *const heap, bheapitem_t *const returnitemstorage)
heap->array[0] = heap->array[heap->count];
heap->array[0].heapindex = 0U;
memset(&heap->array[heap->count], 0x00, sizeof(bheapitem_t));
if (heap->array[0].indexchanged != NULL)
{
heap->array[0].indexchanged(heap->array[0].data, heap->array[0].heapindex);
}
K_BHeapSortDown(heap, &heap->array[0]);
popsuccess = true;

View file

@ -40,6 +40,22 @@
// indirectitemcooldown is timer before anyone's allowed another Shrink/SPB
// mapreset is set when enough players fill an empty server
UINT16 K_GetPlayerDontDrawFlag(player_t *player)
{
UINT16 flag = 0;
if (player == &players[displayplayers[0]])
flag = MFD_DONTDRAWP1;
else if (r_splitscreen >= 1 && player == &players[displayplayers[1]])
flag = MFD_DONTDRAWP2;
else if (r_splitscreen >= 2 && player == &players[displayplayers[2]])
flag = MFD_DONTDRAWP3;
else if (r_splitscreen >= 3 && player == &players[displayplayers[3]])
flag = MFD_DONTDRAWP4;
return flag;
}
player_t *K_GetItemBoxPlayer(mobj_t *mobj)
{
fixed_t closest = INT32_MAX;
@ -1330,15 +1346,19 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur
cury + (P_RandomRange(-12,12)*mapobjectscale),
curz + (P_RandomRange(24,48)*mapobjectscale),
MT_SIGNSPARKLE);
P_SetMobjState(band, S_SIGNSPARK1 + (leveltime % 11));
P_SetScale(band, (band->destscale = (3*player->mo->scale)/2));
band->color = colors[c];
band->colorized = true;
band->fuse = 2;
if (transparent)
band->flags2 |= MF2_SHADOW;
if (!P_IsDisplayPlayer(player) && !P_IsDisplayPlayer(victim))
band->flags2 |= MF2_DONTDRAW;
band->drawflags |= MFD_SHADOW;
band->drawflags |= MFD_DONTDRAW & ~(K_GetPlayerDontDrawFlag(player) | K_GetPlayerDontDrawFlag(victim));
}
curx += stepx;
@ -1566,13 +1586,21 @@ void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master)
K_FlipFromObject(mo, master);
// visibility (usually for hyudoro)
mo->flags2 = (mo->flags2 & ~MF2_DONTDRAW)|(master->flags2 & MF2_DONTDRAW);
mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP1)|(master->eflags & MFE_DRAWONLYFORP1);
mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP2)|(master->eflags & MFE_DRAWONLYFORP2);
mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP3)|(master->eflags & MFE_DRAWONLYFORP3);
mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP4)|(master->eflags & MFE_DRAWONLYFORP4);
mo->drawflags = (master->drawflags & MFD_DONTDRAW);
}
// same as above, but does not adjust Z height when flipping
void K_GenericExtraFlagsNoZAdjust(mobj_t *mo, mobj_t *master)
{
// flipping
mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP)|(master->eflags & MFE_VERTICALFLIP);
mo->flags2 = (mo->flags2 & ~MF2_OBJECTFLIP)|(master->flags2 & MF2_OBJECTFLIP);
// visibility (usually for hyudoro)
mo->drawflags = (master->drawflags & MFD_DONTDRAW);
}
void K_SpawnDashDustRelease(player_t *player)
{
fixed_t newx;
@ -1629,7 +1657,54 @@ static void K_SpawnBrakeDriftSparks(player_t *player) // Be sure to update the m
P_SetTarget(&sparks->target, player->mo);
P_SetScale(sparks, (sparks->destscale = player->mo->scale));
K_MatchGenericExtraFlags(sparks, player->mo);
sparks->flags2 |= MF2_DONTDRAW;
sparks->drawflags |= MFD_DONTDRAW;
}
static fixed_t K_RandomFlip(fixed_t f)
{
return ( ( leveltime & 1 ) ? f : -f );
}
void K_SpawnDriftBoostClip(player_t *player)
{
mobj_t *clip;
fixed_t scale = 115*FRACUNIT/100;
fixed_t z;
if (( player->mo->eflags & MFE_VERTICALFLIP ))
z = player->mo->z;
else
z = player->mo->z + player->mo->height;
clip = P_SpawnMobj(player->mo->x, player->mo->y, z, MT_DRIFTCLIP);
P_SetTarget(&clip->target, player->mo);
P_SetScale(clip, ( clip->destscale = FixedMul(scale, player->mo->scale) ));
K_MatchGenericExtraFlags(clip, player->mo);
clip->fuse = 105;
clip->momz = 7 * P_MobjFlip(clip) * clip->scale;
if (player->mo->momz > 0)
clip->momz += player->mo->momz;
P_InstaThrust(clip, player->mo->angle +
K_RandomFlip(P_RandomRange(FRACUNIT/2, FRACUNIT)),
FixedMul(scale, player->speed));
}
void K_SpawnDriftBoostClipSpark(mobj_t *clip)
{
mobj_t *spark;
spark = P_SpawnMobj(clip->x, clip->y, clip->z, MT_DRIFTCLIPSPARK);
P_SetTarget(&spark->target, clip);
P_SetScale(spark, ( spark->destscale = clip->scale ));
K_MatchGenericExtraFlags(spark, clip);
spark->momx = clip->momx/2;
spark->momy = clip->momx/2;
}
/** \brief Handles the state changing for moving players, moved here to eliminate duplicate code
@ -1899,6 +1974,13 @@ void K_PlayPainSound(mobj_t *source)
void K_PlayHitEmSound(mobj_t *source)
{
if (source->player->follower)
{
follower_t fl = followers[source->player->followerskin];
source->player->follower->movecount = fl.hitconfirmtime; // movecount is used to play the hitconfirm animation for followers.
}
if (cv_kartvoices.value)
S_StartSound(source, sfx_khitem);
else
@ -1946,9 +2028,17 @@ static fixed_t K_FlameShieldDashVar(INT32 val)
return (3*FRACUNIT/4) + (((val * FRACUNIT) / TICRATE) / 2);
}
// Light weights have stronger boost stacking -- aka, better metabolism than heavies XD
#define METABOLISM
// sets k_boostpower, k_speedboost, and k_accelboost to whatever we need it to be
static void K_GetKartBoostPower(player_t *player)
{
#ifdef METABOLISM
const fixed_t maxmetabolismincrease = FRACUNIT/2;
const fixed_t metabolism = FRACUNIT - ((9-player->kartweight) * maxmetabolismincrease / 8);
#endif // METABOLISM
fixed_t boostpower = FRACUNIT;
fixed_t speedboost = 0, accelboost = 0;
UINT8 numboosts = 0;
@ -1966,12 +2056,24 @@ static void K_GetKartBoostPower(player_t *player)
if (player->kartstuff[k_bananadrag] > TICRATE)
boostpower = (4*boostpower)/5;
#ifdef METABOLISM
#define ADDBOOST(s,a) { \
numboosts++; \
speedboost += (s) / numboosts; \
accelboost += (a) / numboosts; \
speedboost += FixedDiv(s, FRACUNIT + (metabolism * numboosts-1)); \
accelboost += FixedDiv(a, FRACUNIT + (metabolism * numboosts-1)); \
}
#else
#define ADDBOOST(s,a) { \
numboosts++; \
speedboost += s / numboosts; \
accelboost += a / numboosts; \
}
#endif // METABOLISM
if (player->kartstuff[k_sneakertimer]) // Sneaker
{
UINT8 i;
@ -2098,7 +2200,7 @@ fixed_t K_GetKartAccel(player_t *player)
//k_accel += 3 * (9 - kartspeed); // 36 - 60
k_accel += 4 * (9 - kartspeed); // 32 - 64
if (K_PlayerUsesBotMovement(player))
{
// Rubberbanding acceleration is waekened since it makes hits feel more meaningful
@ -2116,11 +2218,11 @@ UINT16 K_GetKartFlashing(player_t *player)
if (!player)
return tics;
tics += (tics/8) * (player->kartspeed);
if (G_BattleGametype())
tics *= 2;
tics += (flashingtics/8) * (player->kartspeed);
return tics;
}
@ -3086,6 +3188,7 @@ static void K_SpawnDriftSparks(player_t *player)
{
// transition
P_SetScale(spark, (spark->destscale = spark->scale*3/2));
S_StartSound(player->mo, sfx_cock);
}
else
{
@ -3327,7 +3430,7 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent)
}
if (translucent)
dust->flags2 |= MF2_SHADOW;
dust->drawflags |= MFD_SHADOW;
}
void K_SpawnDraftDust(mobj_t *mo)
@ -4003,7 +4106,7 @@ void K_DoSneaker(player_t *player, INT32 type)
{
player->pflags |= PF_ATTACKDOWN;
K_PlayBoostTaunt(player->mo);
}
player->kartstuff[k_sneakertimer] = sneakertime;
@ -4803,9 +4906,9 @@ static void K_MoveHeldObjects(player_t *player)
cur->flags &= ~MF_NOCLIPTHING;
if (player->kartstuff[k_rocketsneakertimer] <= TICRATE && (leveltime & 1))
cur->flags2 |= MF2_DONTDRAW;
cur->drawflags |= MFD_DONTDRAW;
else
cur->flags2 &= ~MF2_DONTDRAW;
cur->drawflags &= ~MFD_DONTDRAW;
if (num & 1)
P_SetMobjStateNF(cur, (vibrate ? S_ROCKETSNEAKER_LVIBRATE : S_ROCKETSNEAKER_L));
@ -5354,7 +5457,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
//ghost->momy = (3*player->mo->momy)/4;
//ghost->momz = (3*player->mo->momz)/4;
if (leveltime & 1)
ghost->flags2 |= MF2_DONTDRAW;
ghost->drawflags |= MFD_DONTDRAW;
}
if (P_IsObjectOnGround(player->mo))
@ -5381,16 +5484,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
{
mobj_t *debtflag = P_SpawnMobj(player->mo->x + player->mo->momx, player->mo->y + player->mo->momy,
player->mo->z + player->mo->momz + player->mo->height + (24*player->mo->scale), MT_THOK);
P_SetMobjState(debtflag, S_RINGDEBT);
P_SetScale(debtflag, (debtflag->destscale = player->mo->scale));
K_MatchGenericExtraFlags(debtflag, player->mo);
debtflag->frame += (leveltime % 4);
if ((leveltime/12) & 1)
debtflag->frame += 4;
debtflag->color = player->skincolor;
debtflag->fuse = 2;
if (P_IsDisplayPlayer(player))
debtflag->flags2 |= MF2_DONTDRAW;
debtflag->drawflags = K_GetPlayerDontDrawFlag(player);
}
if (player->kartstuff[k_springstars] && (leveltime & 1))
@ -6306,6 +6413,45 @@ INT32 K_GetKartDriftSparkValue(player_t *player)
return (26*4 + kartspeed*2 + (9 - player->kartweight))*8;
}
/*
Stage 1: red sparks
Stage 2: blue sparks
Stage 3: big large rainbow sparks
*/
static void K_SpawnDriftBoostExplosion(player_t *player, int stage)
{
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_DRIFTEXPLODE);
P_SetTarget(&overlay->target, player->mo);
P_SetScale(overlay, (overlay->destscale = player->mo->scale));
K_FlipFromObject(overlay, player->mo);
switch (stage)
{
case 1:
overlay->color = SKINCOLOR_KETCHUP;
overlay->fuse = 16;
break;
case 2:
overlay->color = SKINCOLOR_SAPPHIRE;
overlay->fuse = 32;
S_StartSound(player->mo, sfx_kc5b);
break;
case 3:
overlay->color = SKINCOLOR_SILVER;
overlay->fuse = 120;
S_StartSound(player->mo, sfx_kc5b);
S_StartSound(player->mo, sfx_s3kc4l);
break;
}
overlay->extravalue1 = stage;
}
static void K_KartDrift(player_t *player, boolean onground)
{
fixed_t minspeed = (10 * player->mo->scale);
@ -6322,10 +6468,6 @@ static void K_KartDrift(player_t *player, boolean onground)
if (player->kartstuff[k_driftcharge] < 0 || player->kartstuff[k_driftcharge] >= dsone)
{
angle_t pushdir = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
//mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_DRIFTEXPLODE);
//P_SetTarget(&overlay->target, player->mo);
//P_SetScale(overlay, (overlay->destscale = player->mo->scale));
//K_FlipFromObject(overlay, player->mo);
S_StartSound(player->mo, sfx_s23c);
//K_SpawnDashDustRelease(player);
@ -6338,9 +6480,6 @@ static void K_KartDrift(player_t *player, boolean onground)
if (player->kartstuff[k_driftboost] < 15)
player->kartstuff[k_driftboost] = 15;
//overlay->color = SKINCOLOR_GOLD;
//overlay->fuse = 8;
}
else if (player->kartstuff[k_driftcharge] >= dsone && player->kartstuff[k_driftcharge] < dstwo)
{
@ -6351,8 +6490,7 @@ static void K_KartDrift(player_t *player, boolean onground)
if (player->kartstuff[k_driftboost] < 20)
player->kartstuff[k_driftboost] = 20;
//overlay->color = SKINCOLOR_KETCHUP;
//overlay->fuse = 16;
K_SpawnDriftBoostExplosion(player, 1);
}
else if (player->kartstuff[k_driftcharge] < dsthree)
{
@ -6363,8 +6501,7 @@ static void K_KartDrift(player_t *player, boolean onground)
if (player->kartstuff[k_driftboost] < 50)
player->kartstuff[k_driftboost] = 50;
//overlay->color = SKINCOLOR_SAPPHIRE;
//overlay->fuse = 32;
K_SpawnDriftBoostExplosion(player, 2);
}
else if (player->kartstuff[k_driftcharge] >= dsthree)
{
@ -6375,8 +6512,7 @@ static void K_KartDrift(player_t *player, boolean onground)
if (player->kartstuff[k_driftboost] < 125)
player->kartstuff[k_driftboost] = 125;
//overlay->color = SKINCOLOR_SILVER;
//overlay->fuse = 120;
K_SpawnDriftBoostExplosion(player, 3);
}
}
@ -6678,7 +6814,7 @@ static INT32 K_FlameShieldMax(player_t *player)
}
disttofinish = player->distancetofinish - disttofinish;
distv = FixedDiv(distv * FRACUNIT, mapobjectscale) / FRACUNIT;
distv = FixedMul(distv * FRACUNIT, mapobjectscale) / FRACUNIT;
return min(16, 1 + (disttofinish / distv));
}
@ -7408,61 +7544,35 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (G_RaceGametype())
hyu *= 2; // double in race
if (r_splitscreen)
if (leveltime & 1)
{
if (leveltime & 1)
player->mo->flags2 |= MF2_DONTDRAW;
else
player->mo->flags2 &= ~MF2_DONTDRAW;
if (player->kartstuff[k_hyudorotimer] >= (TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyu-(TICRATE/2))
{
if (player == &players[displayplayers[1]])
player->mo->eflags |= MFE_DRAWONLYFORP2;
else if (player == &players[displayplayers[2]] && r_splitscreen > 1)
player->mo->eflags |= MFE_DRAWONLYFORP3;
else if (player == &players[displayplayers[3]] && r_splitscreen > 2)
player->mo->eflags |= MFE_DRAWONLYFORP4;
else if (player == &players[displayplayers[0]])
player->mo->eflags |= MFE_DRAWONLYFORP1;
else
player->mo->flags2 |= MF2_DONTDRAW;
}
else
player->mo->eflags &= ~(MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
player->mo->drawflags |= MFD_DONTDRAW;
}
else
{
if (P_IsDisplayPlayer(player)
|| (!P_IsDisplayPlayer(player) && (player->kartstuff[k_hyudorotimer] < (TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyu-(TICRATE/2))))
{
if (leveltime & 1)
player->mo->flags2 |= MF2_DONTDRAW;
else
player->mo->flags2 &= ~MF2_DONTDRAW;
}
if (player->kartstuff[k_hyudorotimer] >= (TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyu-(TICRATE/2))
player->mo->drawflags &= ~K_GetPlayerDontDrawFlag(player);
else
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags &= ~MFD_DONTDRAW;
}
player->powers[pw_flashing] = player->kartstuff[k_hyudorotimer]; // We'll do this for now, let's people know about the invisible people through subtle hints
}
else if (player->kartstuff[k_hyudorotimer] == 0)
{
player->mo->flags2 &= ~MF2_DONTDRAW;
player->mo->eflags &= ~(MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
player->mo->drawflags &= ~MFD_DONTDRAW;
}
if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) // dead in match? you da bomb
{
K_DropItems(player); //K_StripItems(player);
K_StripOther(player);
player->mo->flags2 |= MF2_SHADOW;
player->mo->drawflags |= MFD_SHADOW;
player->powers[pw_flashing] = player->kartstuff[k_comebacktimer];
}
else if (G_RaceGametype() || player->kartstuff[k_bumper] > 0)
{
player->mo->flags2 &= ~MF2_SHADOW;
player->mo->drawflags &= ~(MFD_TRANSMASK|MFD_BRIGHTMASK);
}
}
@ -9839,7 +9949,8 @@ static void K_ObjectTracking(fixed_t *hud_x, fixed_t *hud_y, vertex_t *campos, a
{
*hud_y /= 2;
if (camnum > 1)
if ((r_splitscreen == 1 && camnum == 1)
|| (r_splitscreen > 1 && camnum > 1))
{
*hud_y += shhalffixed;
}
@ -9953,6 +10064,30 @@ static void K_drawKartPlayerCheck(void)
}
}
static boolean K_ShowPlayerNametag(player_t *p)
{
if (demo.playback == true && demo.freecam == true)
{
return true;
}
if (stplyr == p)
{
return false;
}
if (G_RaceGametype())
{
if ((p->kartstuff[k_position] < stplyr->kartstuff[k_position]-2)
|| (p->kartstuff[k_position] > stplyr->kartstuff[k_position]+2))
{
return false;
}
}
return true;
}
static void K_drawKartNameTags(void)
{
const fixed_t maxdistance = 8192*mapobjectscale;
@ -9998,7 +10133,6 @@ static void K_drawKartNameTags(void)
fixed_t y = -BASEVIDWIDTH * FRACUNIT;
vertex_t v;
UINT8 j;
if (!playeringame[i] || ntplayer->spectator)
{
@ -10018,18 +10152,24 @@ static void K_drawKartNameTags(void)
continue;
}
for (j = 0; j <= r_splitscreen; j++)
if (!(demo.playback == true && demo.freecam == true))
{
if (ntplayer == &players[displayplayers[j]])
{
break;
}
}
UINT8 j;
if (j <= r_splitscreen)
{
// Is a player that's being shown on this computer
continue;
for (j = 0; j <= r_splitscreen; j++)
{
if (ntplayer == &players[displayplayers[j]])
{
break;
}
}
if (j <= r_splitscreen)
{
// This is a player that's being shown on this computer
// (Remove whenever we get splitscreen ABCD indicators)
continue;
}
}
v.x = ntplayer->mo->x;
@ -10065,10 +10205,9 @@ static void K_drawKartNameTags(void)
V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS, kp_rival[blink], NULL);
}
}
else if (netgame)
else if (netgame || demo.playback)
{
if ((ntplayer->kartstuff[k_position] >= stplyr->kartstuff[k_position]-2)
&& (ntplayer->kartstuff[k_position] <= stplyr->kartstuff[k_position]+2))
if (K_ShowPlayerNametag(ntplayer) == true)
{
INT32 namelen = V_ThinStringWidth(player_names[i], V_6WIDTHSPACE|V_ALLOWLOWERCASE);
INT32 clr = K_SkincolorToTextColor(ntplayer->skincolor);
@ -10095,7 +10234,7 @@ static void K_drawKartNameTags(void)
{
bary += (vid.height - (BASEVIDHEIGHT * vid.dupy)) / 2;
}
// Lat: 10/06/2020: colormap can be NULL on the frame you join a game, just arbitrarily use palette indexes 31 and 0 instead of whatever the colormap would give us instead to avoid crashes.
V_DrawFill(barx, bary, barw, (3 * vid.dupy), (colormap ? colormap[31] : 31)|V_NOSCALESTART);
V_DrawFill(barx, bary + vid.dupy, barw, vid.dupy, (colormap ? colormap[0] : 0)|V_NOSCALESTART);
@ -10196,6 +10335,7 @@ static void K_drawKartMinimap(void)
UINT8 *colormap = NULL;
SINT8 localplayers[4];
SINT8 numlocalplayers = 0;
INT32 hyu = hyudorotime;
mobj_t *mobj, *next; // for SPB drawing (or any other item(s) we may wanna draw, I dunno!)
// Draw the HUD only when playing in a level.
@ -10268,6 +10408,9 @@ static void K_drawKartMinimap(void)
for (i = 0; i < 4; i++)
localplayers[i] = -1;
if (G_RaceGametype())
hyu *= 2; // double in race
// Player's tiny icons on the Automap. (drawn opposite direction so player 1 is drawn last in splitscreen)
if (ghosts)
{
@ -10313,8 +10456,8 @@ static void K_drawKartMinimap(void)
if (players[i].kartstuff[k_hyudorotimer] > 0)
{
if (!((players[i].kartstuff[k_hyudorotimer] < 1*TICRATE/2
|| players[i].kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2))
if (!((players[i].kartstuff[k_hyudorotimer] < TICRATE/2
|| players[i].kartstuff[k_hyudorotimer] > hyu-(TICRATE/2))
&& !(leveltime & 1)))
continue;
}
@ -10596,7 +10739,7 @@ static void K_drawKartFirstPerson(void)
UINT8 *colmap = NULL;
ticcmd_t *cmd = &stplyr->cmd;
if (stplyr->spectator || !stplyr->mo || (stplyr->mo->flags2 & MF2_DONTDRAW))
if (stplyr->spectator || !stplyr->mo || (stplyr->mo->drawflags & MFD_DONTDRAW))
return;
if (stplyr == &players[displayplayers[1]] && r_splitscreen)
@ -10618,9 +10761,9 @@ static void K_drawKartFirstPerson(void)
{
if (stplyr->speed < (20*stplyr->mo->scale) && (leveltime & 1) && !r_splitscreen)
y++;
// the following isn't EXPLICITLY right, it just gets the result we want, but i'm too lazy to look up the right way to do it
if (stplyr->mo->flags2 & MF2_SHADOW)
splitflags |= FF_TRANS80;
if (stplyr->mo->drawflags & MFD_TRANSMASK)
splitflags |= ((stplyr->mo->drawflags & MFD_TRANSMASK) >> MFD_TRANSSHIFT) << FF_TRANSSHIFT;
else if (stplyr->mo->frame & FF_TRANSMASK)
splitflags |= (stplyr->mo->frame & FF_TRANSMASK);
}

View file

@ -17,6 +17,7 @@ angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t
void K_RegisterKartStuff(void);
UINT16 K_GetPlayerDontDrawFlag(player_t *player);
boolean K_IsPlayerLosing(player_t *player);
fixed_t K_GetKartGameSpeedScalar(SINT8 value);
@ -28,7 +29,10 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
void K_KartPainEnergyFling(player_t *player);
void K_FlipFromObject(mobj_t *mo, mobj_t *master);
void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master);
void K_GenericExtraFlagsNoZAdjust(mobj_t *mo, mobj_t *master);
void K_SpawnDashDustRelease(player_t *player);
void K_SpawnDriftBoostClip(player_t *player);
void K_SpawnDriftBoostClipSpark(mobj_t *clip);
void K_KartMoveAnimation(player_t *player);
void K_KartPlayerHUDUpdate(player_t *player);
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd);

View file

@ -472,13 +472,44 @@ boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup
// Reallocate nodesarray if it's full
if (nodesarraycount >= pathfindsetup->nodesarraycapacity)
{
pathfindnode_t *nodesarrayrealloc = NULL;
pathfindsetup->nodesarraycapacity = pathfindsetup->nodesarraycapacity * 2;
nodesarray = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
nodesarrayrealloc = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
if (nodesarray == NULL)
if (nodesarrayrealloc == NULL)
{
I_Error("K_PathfindAStar: Out of memory reallocating nodes array.");
}
// Need to update pointers in closedset, openset, and node "camefrom" if nodesarray moved.
if (nodesarray != nodesarrayrealloc)
{
size_t j = 0U;
size_t arrayindex = 0U;
for (j = 0U; j < closedsetcount; j++)
{
arrayindex = closedset[j] - nodesarray;
closedset[j] = &nodesarrayrealloc[arrayindex];
}
for (j = 0U; j < openset.count; j++)
{
arrayindex = ((pathfindnode_t *)(openset.array[j].data)) - nodesarray;
openset.array[j].data = &nodesarrayrealloc[arrayindex];
}
for (j = 0U; j < nodesarraycount; j++)
{
if (nodesarrayrealloc[j].camefrom != NULL)
{
arrayindex = nodesarrayrealloc[j].camefrom - nodesarray;
nodesarrayrealloc[j].camefrom = &nodesarrayrealloc[arrayindex];
}
}
arrayindex = currentnode - nodesarray;
currentnode = &nodesarrayrealloc[arrayindex];
}
nodesarray = nodesarrayrealloc;
}
// Create the new node and add it to the nodes array and open set

View file

@ -51,6 +51,7 @@ enum mobj_e {
mobj_flags,
mobj_flags2,
mobj_eflags,
mobj_drawflags,
mobj_skin,
mobj_color,
mobj_bnext,
@ -119,6 +120,7 @@ static const char *const mobj_opt[] = {
"flags",
"flags2",
"eflags",
"drawflags",
"skin",
"color",
"bnext",
@ -255,6 +257,9 @@ static int mobj_get(lua_State *L)
case mobj_eflags:
lua_pushinteger(L, mo->eflags);
break;
case mobj_drawflags:
lua_pushinteger(L, mo->drawflags);
break;
case mobj_skin: // skin name or nil, not struct
if (!mo->skin)
return 0;
@ -541,7 +546,10 @@ static int mobj_set(lua_State *L)
mo->flags2 = (UINT32)luaL_checkinteger(L, 3);
break;
case mobj_eflags:
mo->eflags = (UINT32)luaL_checkinteger(L, 3);
mo->eflags = (UINT16)luaL_checkinteger(L, 3);
break;
case mobj_drawflags:
mo->drawflags = (UINT16)luaL_checkinteger(L, 3);
break;
case mobj_skin: // set skin by name
{

View file

@ -239,6 +239,14 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->kartspeed);
else if (fastcmp(field,"kartweight"))
lua_pushinteger(L, plr->kartweight);
else if (fastcmp(field,"followerskin"))
lua_pushinteger(L, plr->followerskin);
else if (fastcmp(field,"followerready"))
lua_pushboolean(L, plr->followerready);
else if (fastcmp(field,"followercolor"))
lua_pushinteger(L, plr->followercolor);
else if (fastcmp(field,"follower"))
LUA_PushUserdata(L, plr->follower, META_MOBJ);
//
else if (fastcmp(field,"charflags"))
lua_pushinteger(L, plr->charflags);
@ -368,6 +376,7 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->awayviewtics);
else if (fastcmp(field,"awayviewaiming"))
lua_pushangle(L, plr->awayviewaiming);
else if (fastcmp(field,"spectator"))
lua_pushboolean(L, plr->spectator);
else if (fastcmp(field,"bot"))
@ -483,6 +492,14 @@ static int player_set(lua_State *L)
plr->kartspeed = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"kartweight"))
plr->kartweight = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"followerskin"))
plr->followerskin = luaL_checkinteger(L, 3);
else if (fastcmp(field,"followercolor"))
plr->followercolor = luaL_checkinteger(L, 3);
else if (fastcmp(field,"followerready"))
plr->followerready = luaL_checkboolean(L, 3);
else if (fastcmp(field,"follower")) // it's probably best we don't allow the follower mobj to change.
return NOSET;
//
else if (fastcmp(field,"charflags"))
plr->charflags = (UINT32)luaL_checkinteger(L, 3);

View file

@ -158,6 +158,7 @@ INT16 startmap; // Mario, NiGHTS, or just a plain old normal game?
static INT16 itemOn = 1; // menu item skull is on, Hack by Tails 09-18-2002
static INT16 skullAnimCounter = 10; // skull animation counter
static tic_t followertimer = 0; // Used for smooth follower floating
static UINT8 setupcontrolplayer;
static INT32 (*setupcontrols)[2]; // pointer to the gamecontrols of the player being edited
@ -1032,6 +1033,7 @@ static menuitem_t MP_PlayerSetupMenu[] =
{
{IT_KEYHANDLER | IT_STRING, NULL, "Name", M_HandleSetupMultiPlayer, 0},
{IT_KEYHANDLER | IT_STRING, NULL, "Character", M_HandleSetupMultiPlayer, 16}, // Tails 01-18-2001
{IT_KEYHANDLER | IT_STRING, NULL, "Follower", M_HandleSetupMultiPlayer, 26},
{IT_KEYHANDLER | IT_STRING, NULL, "Color", M_HandleSetupMultiPlayer, 152},
};
@ -1430,24 +1432,27 @@ enum
static menuitem_t OP_HUDOptionsMenu[] =
{
{IT_STRING | IT_CVAR, NULL, "Show HUD (F3)", &cv_showhud, 10},
{IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "HUD Visibility", &cv_translucenthud, 20},
{IT_STRING | IT_SUBMENU, NULL, "Online HUD options...",&OP_ChatOptionsDef, 35},
{IT_STRING | IT_CVAR, NULL, "Background Glass", &cons_backcolor, 45},
{IT_STRING | IT_CVAR, NULL, "Show Followers", &cv_showfollowers, 10},
{IT_STRING | IT_CVAR, NULL, "Show HUD (F3)", &cv_showhud, 20},
{IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "HUD Visibility", &cv_translucenthud, 30},
{IT_STRING | IT_SUBMENU, NULL, "Online HUD options...",&OP_ChatOptionsDef, 45},
{IT_STRING | IT_CVAR, NULL, "Background Glass", &cons_backcolor, 55},
{IT_STRING | IT_CVAR | IT_CV_SLIDER,
NULL, "Minimap Visibility", &cv_kartminimap, 60},
{IT_STRING | IT_CVAR, NULL, "Speedometer Display", &cv_kartspeedometer, 70},
{IT_STRING | IT_CVAR, NULL, "Show \"CHECK\"", &cv_kartcheck, 80},
NULL, "Minimap Visibility", &cv_kartminimap, 70},
{IT_STRING | IT_CVAR, NULL, "Speedometer Display", &cv_kartspeedometer, 80},
{IT_STRING | IT_CVAR, NULL, "Show \"CHECK\"", &cv_kartcheck, 90},
{IT_STRING | IT_CVAR, NULL, "Menu Highlights", &cons_menuhighlight, 95},
{IT_STRING | IT_CVAR, NULL, "Menu Highlights", &cons_menuhighlight, 105},
// highlight info - (GOOD HIGHLIGHT, WARNING HIGHLIGHT) - 105 (see M_DrawHUDOptions)
{IT_STRING | IT_CVAR, NULL, "Console Text Size", &cv_constextsize, 120},
{IT_STRING | IT_CVAR, NULL, "Console Text Size", &cv_constextsize, 130},
{IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 135},
{IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 145},
};
// Ok it's still called chatoptions but we'll put ping display in here to be clean
@ -3336,6 +3341,8 @@ void M_Ticker(void)
if (--skullAnimCounter <= 0)
skullAnimCounter = 8;
followertimer++;
if (currentMenu == &PlaybackMenuDef)
{
if (playback_enterheld > 0)
@ -5693,7 +5700,7 @@ static void M_DrawReplayStartMenu(void)
// Lat: 08/06/2020: For some reason missing skins have their value set to 255 (don't even ask me why I didn't write this)
// and for an even STRANGER reason this passes the first check below, so we're going to make sure that the skin here ISN'T 255 before we do anything stupid.
if (demolist[dir_on[menudepthleft]].standings[0].skin != 0xFF && W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR)
if (demolist[dir_on[menudepthleft]].standings[i].skin != 0xFF && W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR)
{
patch = facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin];
colormap = R_GetTranslationColormap(
@ -9312,9 +9319,15 @@ static void M_HandleConnectIP(INT32 choice)
// ========================
// Tails 03-02-2002
// used for skin display on player setup menu
static INT32 multi_tics;
static state_t *multi_state;
// used for follower display on player setup menu
static INT32 follower_tics;
static UINT32 follower_frame; // used for FF_ANIMATE garbo
static state_t *follower_state;
// this is set before entering the MultiPlayer setup menu,
// for either player 1 or 2
static char setupm_name[MAXPLAYERNAME+1];
@ -9322,8 +9335,10 @@ static player_t *setupm_player;
static consvar_t *setupm_cvskin;
static consvar_t *setupm_cvcolor;
static consvar_t *setupm_cvname;
static consvar_t *setupm_cvfollower;
static INT32 setupm_fakeskin;
static INT32 setupm_fakecolor;
static INT32 setupm_fakefollower; // -1 is for none, our followers start at 0
static void M_DrawSetupMultiPlayerMenu(void)
{
@ -9341,6 +9356,7 @@ static void M_DrawSetupMultiPlayerMenu(void)
UINT8 i;
const UINT8 *flashcol = V_GetStringColormap(highlightflags);
INT32 statx, staty;
char *fname;
mx = MP_PlayerSetupDef.x;
my = MP_PlayerSetupDef.y;
@ -9372,11 +9388,31 @@ static void M_DrawSetupMultiPlayerMenu(void)
'\x1D' | highlightflags, false); // right arrow
}
// draw follower string
fname = malloc(SKINNAMESIZE+1);
if (setupm_fakefollower == -1)
strcpy(fname, "None");
else
strcpy(fname, followers[setupm_fakefollower].name);
st = V_StringWidth(fname, 0);
V_DrawString(BASEVIDWIDTH - mx - st, my + 26,
((MP_PlayerSetupMenu[2].status & IT_TYPE) == IT_SPACE ? V_TRANSLUCENT : 0)|highlightflags|V_ALLOWLOWERCASE,
fname);
if (itemOn == 2)
{
V_DrawCharacter(BASEVIDWIDTH - mx - 10 - st - (skullAnimCounter/5), my + 26,
'\x1C' | highlightflags, false); // left arrow
V_DrawCharacter(BASEVIDWIDTH - mx + 2 + (skullAnimCounter/5), my + 26,
'\x1D' | highlightflags, false); // right arrow
}
// draw the name of the color you have chosen
// Just so people don't go thinking that "Default" is Green.
st = V_StringWidth(KartColor_Names[setupm_fakecolor], 0);
V_DrawString(BASEVIDWIDTH - mx - st, my + 152, highlightflags|V_ALLOWLOWERCASE, KartColor_Names[setupm_fakecolor]); // SRB2kart
if (itemOn == 2)
if (itemOn == 3)
{
V_DrawCharacter(BASEVIDWIDTH - mx - 10 - st - (skullAnimCounter/5), my + 152,
'\x1C' | highlightflags, false); // left arrow
@ -9524,7 +9560,7 @@ static void M_DrawSetupMultiPlayerMenu(void)
sprframe = &sprdef->spriteframes[frame];
patch = W_CachePatchNum(sprframe->lumppat[1], PU_CACHE);
if (sprframe->flip & 1) // Only for first sprite
if (sprframe->flip & 2) // Only for first sprite
flags |= V_FLIP; // This sprite is left/right flipped!
// draw box around guy
@ -9545,9 +9581,88 @@ static void M_DrawSetupMultiPlayerMenu(void)
else
V_DrawMappedPatch(mx+43, my+131, flags, patch, colormap);
}
// draw their follower if there is one
if (setupm_fakefollower > -1 && setupm_fakefollower < numfollowers)
{
// animate the follower
if (--follower_tics <= 0)
{
// FF_ANIMATE; cycle through FRAMES and get back afterwards. This will be prominent amongst followers hence why it's being supported here.
if (follower_state->frame & FF_ANIMATE)
{
follower_frame++;
follower_tics = follower_state->var2;
if (follower_frame > (follower_state->frame & FF_FRAMEMASK) + follower_state->var1) // that's how it works, right?
follower_frame = follower_state->frame & FF_FRAMEMASK;
}
else
{
st = follower_state->nextstate;
if (st != S_NULL)
follower_state = &states[st];
follower_tics = follower_state->tics;
if (follower_tics == -1)
follower_tics = 15; // er, what?
// get spritedef:
follower_frame = follower_state->frame & FF_FRAMEMASK;
}
}
sprdef = &sprites[follower_state->sprite];
// draw the follower
if (follower_frame >= sprdef->numframes)
follower_frame = 0; // frame doesn't exist, we went beyond it... what?
sprframe = &sprdef->spriteframes[follower_frame];
patch = W_CachePatchNum(sprframe->lumppat[1], PU_CACHE);
if (sprframe->flip & 2) // Only for first sprite
flags |= V_FLIP; // This sprite is left/right flipped!
// @TODO: Reminder that followers on the menu right now do NOT support the 'followercolor' command, considering this whole menu is getting remade anyway, I see no point in incorporating it in right now.
// draw follower sprite
if (setupm_fakecolor) // inverse should never happen
{
// Fake the follower's in game appearance by now also applying some of its variables! coolio, eh?
follower_t fl = followers[setupm_fakefollower]; // shortcut for our sanity
// smooth floating, totally not stolen from rocket sneakers.
const fixed_t pi = (22<<FRACBITS) / 7; // loose approximation, this doesn't need to be incredibly precise
fixed_t sine = fl.bobamp * FINESINE((((8*pi*(fl.bobspeed)) * followertimer)>>ANGLETOFINESHIFT) & FINEMASK);
UINT8 *colormap = R_GetTranslationColormap(-1, setupm_fakecolor, 0);
V_DrawFixedPatch((mx+65)*FRACUNIT, (my+131-fl.zoffs)*FRACUNIT+sine, fl.scale, flags, patch, colormap);
Z_Free(colormap);
}
}
#undef charw
}
// follower state update. This is its own function so that it's at least somewhat clean
static void M_GetFollowerState(void)
{
if (setupm_fakefollower <= -1 || setupm_fakefollower > numfollowers-1) // yikes, there's none!
return;
// ^ we don't actually need to set anything since it won't be displayed anyway.
//followertimer = 0; // reset timer. not like it'll overflow anytime soon but whatever.
// set follower state
follower_state = &states[followers[setupm_fakefollower].followstate];
if (follower_state->frame & FF_ANIMATE)
follower_tics = follower_state->var2; // support for FF_ANIMATE
else
follower_tics = follower_state->tics;
follower_frame = follower_state->frame & FF_FRAMEMASK;
}
// Handle 1P/2P MP Setup
static void M_HandleSetupMultiPlayer(INT32 choice)
{
@ -9575,7 +9690,13 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
S_StartSound(NULL,sfx_menu1); // Tails
setupm_fakeskin--;
}
else if (itemOn == 2) // player color
else if (itemOn == 2) // follower
{
S_StartSound(NULL,sfx_menu1);
setupm_fakefollower--;
M_GetFollowerState(); // update follower state
}
else if (itemOn == 3) // player color
{
S_StartSound(NULL,sfx_menu1); // Tails
setupm_fakecolor--;
@ -9587,8 +9708,15 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
{
S_StartSound(NULL,sfx_menu1); // Tails
setupm_fakeskin++;
M_GetFollowerState(); // update follower state
}
else if (itemOn == 2) // player color
else if (itemOn == 2) // follower
{
S_StartSound(NULL,sfx_menu1);
setupm_fakefollower++;
M_GetFollowerState();
}
else if (itemOn == 3) // player color
{
S_StartSound(NULL,sfx_menu1); // Tails
setupm_fakecolor++;
@ -9608,7 +9736,12 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
setupm_name[l-1] =0;
}
}
else if (itemOn == 2)
else if (itemOn == 2) // follower
{
S_StartSound(NULL,sfx_menu1);
setupm_fakefollower = -1;
}
else if (itemOn == 3)
{
UINT8 col = skins[setupm_fakeskin].prefcolor;
if (setupm_fakecolor != col)
@ -9646,6 +9779,18 @@ static void M_HandleSetupMultiPlayer(INT32 choice)
if (setupm_fakeskin > numskins-1)
setupm_fakeskin = 0;
// check followers:
if (setupm_fakefollower < -1)
{
setupm_fakefollower = numfollowers-1;
M_GetFollowerState(); // update follower state
}
if (setupm_fakefollower > numfollowers-1)
{
setupm_fakefollower = -1;
M_GetFollowerState(); // update follower state
}
// check color
if (setupm_fakecolor < 1)
setupm_fakecolor = MAXSKINCOLORS-1;
@ -9668,6 +9813,7 @@ static void M_SetupMultiPlayer(INT32 choice)
multi_state = &states[mobjinfo[MT_PLAYER].seestate];
multi_tics = multi_state->tics;
strcpy(setupm_name, cv_playername.string);
// set for player 1
@ -9675,6 +9821,15 @@ static void M_SetupMultiPlayer(INT32 choice)
setupm_cvskin = &cv_skin;
setupm_cvcolor = &cv_playercolor;
setupm_cvname = &cv_playername;
setupm_cvfollower = &cv_follower;
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
// yikes, we don't want none of that...
if (setupm_fakefollower > numfollowers-1)
setupm_fakefollower = -1;
M_GetFollowerState(); // update follower state
// For whatever reason this doesn't work right if you just use ->value
setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string);
@ -9706,6 +9861,15 @@ static void M_SetupMultiPlayer2(INT32 choice)
setupm_cvskin = &cv_skin2;
setupm_cvcolor = &cv_playercolor2;
setupm_cvname = &cv_playername2;
setupm_cvfollower = &cv_follower2;
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
// yikes, we don't want none of that...
if (setupm_fakefollower > numfollowers-1)
setupm_fakefollower = -1;
M_GetFollowerState(); // update follower state
// For whatever reason this doesn't work right if you just use ->value
setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string);
@ -9737,6 +9901,15 @@ static void M_SetupMultiPlayer3(INT32 choice)
setupm_cvskin = &cv_skin3;
setupm_cvcolor = &cv_playercolor3;
setupm_cvname = &cv_playername3;
setupm_cvfollower = &cv_follower3;
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
// yikes, we don't want none of that...
if (setupm_fakefollower > numfollowers-1)
setupm_fakefollower = -1;
M_GetFollowerState(); // update follower state
// For whatever reason this doesn't work right if you just use ->value
setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string);
@ -9768,6 +9941,15 @@ static void M_SetupMultiPlayer4(INT32 choice)
setupm_cvskin = &cv_skin4;
setupm_cvcolor = &cv_playercolor4;
setupm_cvname = &cv_playername4;
setupm_cvfollower = &cv_follower4;
setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value
// yikes, we don't want none of that...
if (setupm_fakefollower > numfollowers-1)
setupm_fakefollower = -1;
M_GetFollowerState(); // update follower state
// For whatever reason this doesn't work right if you just use ->value
setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string);
@ -9800,6 +9982,7 @@ static boolean M_QuitMultiPlayerMenu(void)
// you know what? always putting these in the buffer won't hurt anything.
COM_BufAddText (va("%s \"%s\"\n",setupm_cvskin->name,skins[setupm_fakeskin].name));
COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor));
COM_BufAddText (va("%s %d\n",setupm_cvfollower->name,setupm_fakefollower));
return true;
}
@ -10683,7 +10866,7 @@ static void M_DrawHUDOptions(void)
const char *str1 = " Warning highlight";
const char *str2 = ",";
const char *str3 = "Good highlight";
INT32 x = BASEVIDWIDTH - currentMenu->x + 2, y = currentMenu->y + 105;
INT32 x = BASEVIDWIDTH - currentMenu->x + 2, y = currentMenu->y + 115;
INT32 w0 = V_StringWidth(str0, 0), w1 = V_StringWidth(str1, 0), w2 = V_StringWidth(str2, 0), w3 = V_StringWidth(str3, 0);
M_DrawGenericMenu();

View file

@ -3412,10 +3412,10 @@ void A_BubbleSpawn(mobj_t *actor)
if (!(actor->eflags & MFE_UNDERWATER))
{
// Don't draw or spawn bubbles above water
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
return;
}
actor->flags2 &= ~MF2_DONTDRAW;
actor->drawflags &= ~MFD_DONTDRAW;
if (!(actor->flags2 & MF2_AMBUSH))
{
@ -3547,9 +3547,9 @@ void A_BubbleCheck(mobj_t *actor)
return;
#endif
if (actor->eflags & MFE_UNDERWATER)
actor->flags2 &= ~MF2_DONTDRAW; // underwater so draw
actor->drawflags &= ~MFD_DONTDRAW; // underwater so draw
else
actor->flags2 |= MF2_DONTDRAW; // above water so don't draw
actor->drawflags |= MFD_DONTDRAW; // above water so don't draw
}
// Function: A_AttractChase
@ -3654,9 +3654,9 @@ void A_AttractChase(mobj_t *actor)
// Rings flicker before disappearing
if (actor->fuse && actor->fuse < 5*TICRATE && (leveltime & 1))
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
else
actor->flags2 &= ~MF2_DONTDRAW;
actor->drawflags &= ~MFD_DONTDRAW;
// spilled rings have ghost trails and get capped to a certain speed
if (actor->type == (mobjtype_t)actor->info->reactiontime)
@ -3877,9 +3877,9 @@ void A_ThrownRing(mobj_t *actor)
// spilled rings (and thrown bounce) flicker before disappearing
if (leveltime & 1 && actor->fuse > 0 && actor->fuse < 2*TICRATE
&& actor->type != MT_THROWNGRENADE)
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
else
actor->flags2 &= ~MF2_DONTDRAW;
actor->drawflags &= ~MFD_DONTDRAW;
if (actor->tracer && actor->tracer->health <= 0)
P_SetTarget(&actor->tracer, NULL);
@ -5342,9 +5342,9 @@ void A_CrawlaCommanderThink(mobj_t *actor)
thefloor = actor->floorz;
if (actor->fuse & 1)
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
else
actor->flags2 &= ~MF2_DONTDRAW;
actor->drawflags &= ~MFD_DONTDRAW;
if (actor->reactiontime > 0)
actor->reactiontime--;
@ -9067,7 +9067,7 @@ void A_RandomShadowFrame(mobj_t *actor)
fake->destscale = FRACUNIT*3/2;
fake->angle = actor->angle;
fake->tics = -1;
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
actor->extravalue1 = 1;
}

View file

@ -2218,7 +2218,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
target->player->score = 0;
}*/
target->flags2 &= ~MF2_DONTDRAW;
target->drawflags &= ~MFD_DONTDRAW;
}
// if killed by a player
@ -2959,7 +2959,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
{
mobj_t *boom;
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags |= MFD_DONTDRAW;
boom = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FZEROBOOM);
boom->scale = player->mo->scale;
boom->angle = player->mo->angle;

View file

@ -2457,6 +2457,17 @@ static boolean P_ZMovement(mobj_t *mo)
mom.z = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale);
else if (mo->type == MT_SPINFIRE) // elemental shield fire is another exception here
;
else if (mo->type == MT_DRIFTCLIP)
{
mom.z = -mom.z/2;
if (abs(mom.z) > 4 * mo->scale / 3)
{
K_SpawnDriftBoostClipSpark(mo);
S_StartSound(mo, sfx_tink);
}
else
mo->flags2 ^= MFD_DONTDRAW;
}
else if (mo->flags & MF_MISSILE)
{
if (!(mo->flags & MF_NOCLIP))
@ -4030,9 +4041,9 @@ static void P_RingThinker(mobj_t *mobj)
if (mobj->fuse < TICRATE*3)
{
if (leveltime & 1)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
}
if (!mobj->fuse)
@ -4041,7 +4052,7 @@ static void P_RingThinker(mobj_t *mobj)
if (!LUAh_MobjFuse(mobj))
#endif
{
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
spark = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SIGNSPARKLE); // Spawn a fancy sparkle
K_MatchGenericExtraFlags(spark, mobj);
spark->colorized = true;
@ -6068,14 +6079,14 @@ static void P_NightsItemChase(mobj_t *thing)
if (thing->info->painstate)
P_SetMobjState(thing,thing->info->painstate);
else
thing->flags2 |= MF2_SHADOW;
thing->drawflags |= MFD_SHADOW;
}
else
{
if (thing->info->painstate)
P_SetMobjState(thing,thing->info->spawnstate);
else
thing->flags2 &= ~MF2_SHADOW;
thing->drawflags &= ~(MFD_TRANSMASK|MFD_BRIGHTMASK);
}
}
@ -6464,7 +6475,7 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->type == MT_GHOST && mobj->fuse > 0 // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
&& (signed)(mobj->frame >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2)
// fade out when nearing the end of fuse...
mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << FF_TRANSSHIFT);
mobj->drawflags = (mobj->drawflags & ~MFD_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << MFD_TRANSSHIFT);
// Special thinker for scenery objects
if (mobj->flags & MF_SCENERY)
@ -6477,6 +6488,27 @@ void P_MobjThinker(mobj_t *mobj)
#endif
switch (mobj->type)
{
case MT_FOLLOWER:
// small thinker for follower:
// We cleanse ourselves from existence if our target player doesn't exist for whatever reason. (generally players leaving)
if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->player || mobj->target->player->spectator || mobj->target->player->followerskin < 0)
{
// Remove possible hnext list (bubble)
mobj_t *bub = mobj->hnext;
mobj_t *tmp;
while (bub && !P_MobjWasRemoved(bub))
{
tmp = bub->hnext;
P_RemoveMobj(bub);
bub = tmp;
}
P_RemoveMobj(mobj);
}
return;
case MT_HOOP:
if (mobj->fuse > 1)
P_MoveHoop(mobj);
@ -6630,30 +6662,7 @@ void P_MobjThinker(mobj_t *mobj)
offz = mobj->target->height / 5;
}
if (mobj->target->eflags & MFE_DRAWONLYFORP1) // groooooaann...
mobj->eflags |= MFE_DRAWONLYFORP1;
else
mobj->eflags &= ~MFE_DRAWONLYFORP1;
if (mobj->target->eflags & MFE_DRAWONLYFORP2)
mobj->eflags |= MFE_DRAWONLYFORP2;
else
mobj->eflags &= ~MFE_DRAWONLYFORP2;
if (mobj->target->eflags & MFE_DRAWONLYFORP3)
mobj->eflags |= MFE_DRAWONLYFORP3;
else
mobj->eflags &= ~MFE_DRAWONLYFORP3;
if (mobj->target->eflags & MFE_DRAWONLYFORP4)
mobj->eflags |= MFE_DRAWONLYFORP4;
else
mobj->eflags &= ~MFE_DRAWONLYFORP4;
if (mobj->target->flags2 & MF2_DONTDRAW)
mobj->flags2 |= MF2_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags = (mobj->target->drawflags & MFD_DONTDRAW);
if (mobj->target->eflags & MFE_VERTICALFLIP)
offz += 4*FRACUNIT;
@ -6716,7 +6725,7 @@ void P_MobjThinker(mobj_t *mobj)
|| (P_IsDisplayPlayer(mobj->target->player))
#endif
)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
P_UnsetThingPosition(mobj);
mobj->x = mobj->target->x;
@ -6766,7 +6775,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->tracer->colorized = false;
}
if (!(mobj->flags2 & MF2_DONTDRAW))
if (!(mobj->drawflags & MFD_DONTDRAW))
{
const INT32 numberdisplaymin = ((mobj->target->player->kartstuff[k_itemtype] == KITEM_ORBINAUT) ? 5 : 2);
@ -6776,7 +6785,7 @@ void P_MobjThinker(mobj_t *mobj)
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|(((mobj->target->player->kartstuff[k_itemroulette] % (13*3)) / 3) + 1);
mobj->tracer->flags2 &= ~MF2_DONTDRAW;
mobj->tracer->drawflags &= ~MFD_DONTDRAW;
}
else if (mobj->target->player->kartstuff[k_stolentimer] > 0)
{
@ -6784,16 +6793,16 @@ void P_MobjThinker(mobj_t *mobj)
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO;
if (leveltime & 2)
mobj->tracer->flags2 &= ~MF2_DONTDRAW;
mobj->tracer->drawflags &= ~MFD_DONTDRAW;
else
mobj->tracer->flags2 |= MF2_DONTDRAW;
mobj->tracer->drawflags |= MFD_DONTDRAW;
}
else if ((mobj->target->player->kartstuff[k_stealingtimer] > 0) && (leveltime & 2))
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO;
mobj->tracer->flags2 &= ~MF2_DONTDRAW;
mobj->tracer->drawflags &= ~MFD_DONTDRAW;
}
else if (mobj->target->player->kartstuff[k_eggmanexplode] > 1)
{
@ -6801,9 +6810,9 @@ void P_MobjThinker(mobj_t *mobj)
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_EGGMAN;
if (leveltime & 1)
mobj->tracer->flags2 &= ~MF2_DONTDRAW;
mobj->tracer->drawflags &= ~MFD_DONTDRAW;
else
mobj->tracer->flags2 |= MF2_DONTDRAW;
mobj->tracer->drawflags |= MFD_DONTDRAW;
}
else if (mobj->target->player->kartstuff[k_rocketsneakertimer] > 1)
{
@ -6812,9 +6821,9 @@ void P_MobjThinker(mobj_t *mobj)
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_ROCKETSNEAKER;
if (leveltime & 1)
mobj->tracer->flags2 &= ~MF2_DONTDRAW;
mobj->tracer->drawflags &= ~MFD_DONTDRAW;
else
mobj->tracer->flags2 |= MF2_DONTDRAW;
mobj->tracer->drawflags |= MFD_DONTDRAW;
}
else if (mobj->target->player->kartstuff[k_itemtype] && mobj->target->player->kartstuff[k_itemamount] > 0)
{
@ -6843,12 +6852,12 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->target->player->kartstuff[k_itemheld])
{
if (leveltime & 1)
mobj->tracer->flags2 &= ~MF2_DONTDRAW;
mobj->tracer->drawflags &= ~MFD_DONTDRAW;
else
mobj->tracer->flags2 |= MF2_DONTDRAW;
mobj->tracer->drawflags |= MFD_DONTDRAW;
}
else
mobj->tracer->flags2 &= ~MF2_DONTDRAW;
mobj->tracer->drawflags &= ~MFD_DONTDRAW;
}
else
{
@ -6889,7 +6898,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->movecount = 0;
}
else
mobj->tracer->flags2 |= MF2_DONTDRAW;
mobj->tracer->drawflags |= MFD_DONTDRAW;
}
else if (mobj->health > 0)
{
@ -6912,10 +6921,10 @@ void P_MobjThinker(mobj_t *mobj)
return;
}
if (mobj->tracer->flags2 & MF2_DONTDRAW)
mobj->flags2 |= MF2_DONTDRAW;
if (mobj->tracer->drawflags & MFD_DONTDRAW)
mobj->drawflags |= MFD_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
P_UnsetThingPosition(mobj);
mobj->x = mobj->target->x;
@ -6966,7 +6975,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->eflags |= MFE_VERTICALFLIP;
if (mobj->tics > 0)
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
break;
//}
case MT_WATERDROP:
@ -7027,9 +7036,10 @@ void P_MobjThinker(mobj_t *mobj)
mobj->z = mobj->target->z + (mobj->target->height) + FixedMul(8*FRACUNIT, mobj->target->scale); // Adjust height for height changes
if (mobj->threshold <= 35)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
if (mobj->threshold <= 30)
mobj->threshold = 40;
mobj->threshold--;
@ -7349,14 +7359,15 @@ void P_MobjThinker(mobj_t *mobj)
break;
case MT_PLAYER:
/// \todo Have the player's dead body completely finish its animation even if they've already respawned.
if (!(mobj->flags2 & MF2_DONTDRAW))
// This feels like it has some serious potential for breakage. Is there anything else we can base this off of instead of a drawing flag?
if (!(mobj->drawflags & MFD_DONTDRAW))
{
if (!mobj->fuse)
{ // Go away.
/// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it.
mobj->momz = 0;
if (mobj->player)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
else // safe to remove, nobody's going to complain!
{
P_RemoveMobj(mobj);
@ -7385,7 +7396,7 @@ void P_MobjThinker(mobj_t *mobj)
case MT_ORBINAUT_SHIELD:
case MT_BANANA_SHIELD:
case MT_EGGMANITEM_SHIELD:
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
break;
case MT_JAWZ:
case MT_JAWZ_DUD:
@ -7393,7 +7404,7 @@ void P_MobjThinker(mobj_t *mobj)
P_SetMobjState(mobj, mobj->info->xdeathstate);
// fallthru
case MT_JAWZ_SHIELD:
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
break;
case MT_SSMINE:
case MT_SPBEXPLOSION:
@ -7413,7 +7424,7 @@ void P_MobjThinker(mobj_t *mobj)
return;
case MT_CDUFO:
if (mobj->fuse > TICRATE)
mobj->flags2 ^= MF2_DONTDRAW; // only by good fortune does this end with it having MF2_DONTDRAW... don't touch!
mobj->drawflags ^= MFD_DONTDRAW; // only by good fortune does this end with it having MFD_DONTDRAW... don't touch!
break;
case MT_SMK_PIPE:
if (mobj->flags2 & MF2_AMBUSH)
@ -7422,7 +7433,7 @@ void P_MobjThinker(mobj_t *mobj)
P_SetMobjStateNF(mobj, mobj->info->spawnstate);
/* FALLTHRU */
case MT_SMK_MOLE:
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
if (P_IsObjectOnGround(mobj))
{
P_RemoveMobj(mobj);
@ -7443,7 +7454,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->frame &= (~FF_FULLBRIGHT);
}
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
if (P_IsObjectOnGround(mobj))
{
P_RemoveMobj(mobj);
@ -7743,7 +7754,7 @@ void P_MobjThinker(mobj_t *mobj)
case MT_NIGHTSDRONE:
if (mobj->state >= &states[S_NIGHTSDRONE_SPARKLING1] && mobj->state <= &states[S_NIGHTSDRONE_SPARKLING16])
{
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
mobj->z = mobj->floorz + mobj->height + (mobj->spawnpoint->options >> ZSHIFT) * FRACUNIT;
mobj->angle = 0;
@ -7769,7 +7780,7 @@ void P_MobjThinker(mobj_t *mobj)
{
mobj->flags &= ~MF_NOGRAVITY;
P_SetMobjState(mobj, S_NIGHTSDRONE1);
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
}
}
else if (mobj->tracer && mobj->tracer->player)
@ -7777,7 +7788,7 @@ void P_MobjThinker(mobj_t *mobj)
if (!(mobj->tracer->player->pflags & PF_NIGHTSMODE))
{
mobj->flags &= ~MF_NOGRAVITY;
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
P_SetMobjState(mobj, S_NIGHTSDRONE1);
}
else if (!mobj->tracer->player->bonustime)
@ -7814,7 +7825,7 @@ void P_MobjThinker(mobj_t *mobj)
P_RemoveMobj(mobj->target);
P_SetTarget(&mobj->target, NULL);
}
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
}
}
else if (mobj->tracer && mobj->tracer->player)
@ -7834,10 +7845,10 @@ void P_MobjThinker(mobj_t *mobj)
mobj->flags |= MF_NOGRAVITY;
}
else
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
}
else // Not NiGHTS
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
}
mobj->angle += ANG10;
if (mobj->z <= mobj->floorz)
@ -8279,15 +8290,62 @@ void P_MobjThinker(mobj_t *mobj)
return;
}
mobj->angle = mobj->target->angle;
P_TeleportMove(mobj, mobj->target->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_180, mobj->target->radius),
mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z);
//mobj->angle = mobj->target->angle;
{
angle_t angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy);
fixed_t nudge;
mobj->angle = angle;
if (( mobj->fuse & 1 ))
{
nudge = 4*mobj->target->radius;
}
else
{
nudge = 2*mobj->target->radius;
/* rotate the papersprite frames to see the flat angle */
mobj->angle += ANGLE_90;
}
P_TeleportMove(mobj,
mobj->target->x + P_ReturnThrustX(mobj, angle + ANGLE_180, nudge),
mobj->target->y + P_ReturnThrustY(mobj, angle + ANGLE_180, nudge),
mobj->target->z);
}
P_SetScale(mobj, mobj->target->scale);
mobj->flags2 ^= MF2_DONTDRAW;
#ifdef HWRENDER
mobj->modeltilt = mobj->target->modeltilt;
#endif
if (mobj->fuse <= 16)
{
mobj->color = SKINCOLOR_KETCHUP;
/* don't draw papersprite frames after blue boost */
mobj->drawflags ^= MFD_DONTDRAW;
}
else if (mobj->fuse <= 32)
mobj->color = SKINCOLOR_SAPPHIRE;
else if (mobj->fuse > 32)
mobj->color = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1)));
switch (mobj->extravalue1)
{
case 3:/* rainbow boost */
/* every 20 tics, bang! */
if (( 120 - mobj->fuse ) % 10 == 0)
{
K_SpawnDriftBoostClip(mobj->target->player);
S_StartSound(mobj->target, sfx_s3k77);
}
break;
case 2:/* blue boost */
if (mobj->fuse == 16)/* to red*/
K_SpawnDriftBoostClip(mobj->target->player);
break;
}
{
player_t *p = NULL;
if (mobj->target->target && mobj->target->target->player)
@ -8402,7 +8460,7 @@ void P_MobjThinker(mobj_t *mobj)
K_MatchGenericExtraFlags(mobj, mobj->target);
if (leveltime & 1)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
}
break;
case MT_PLAYERRETICULE:
@ -8414,7 +8472,7 @@ void P_MobjThinker(mobj_t *mobj)
P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z);
break;
case MT_INSTASHIELDB:
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
K_MatchGenericExtraFlags(mobj, mobj->target);
/* FALLTHRU */
case MT_INSTASHIELDA:
@ -8527,14 +8585,14 @@ void P_MobjThinker(mobj_t *mobj)
mobj->angle = ang;
if (leveltime & 1)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
if (trans >= NUMTRANSMAPS)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
else if (trans == 0)
mobj->frame = (mobj->frame & ~FF_TRANSMASK);
mobj->drawflags = (mobj->drawflags & ~MFD_TRANSMASK);
else
mobj->frame = (mobj->frame & ~FF_TRANSMASK)|(trans << FF_TRANSSHIFT);
mobj->drawflags = (mobj->drawflags & ~MFD_TRANSMASK)|(trans << MFD_TRANSSHIFT);
}
break;
case MT_THUNDERSHIELD:
@ -8601,7 +8659,7 @@ void P_MobjThinker(mobj_t *mobj)
P_SetMobjState(mobj, S_BUBBLESHIELDBLOWUP);
mobj->angle += ANGLE_22h;
mobj->flags2 &= ~MF2_SHADOW;
mobj->drawflags &= ~MFD_SHADOW;
scale += (blow * (3*scale)) / bubbletime;
mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + mobj->extravalue1);
@ -8671,9 +8729,9 @@ void P_MobjThinker(mobj_t *mobj)
else
{
if (mobj->target->player->kartstuff[k_bubblecool] && ((curstate-S_BUBBLESHIELD1) & 1))
mobj->flags2 |= MF2_SHADOW;
mobj->drawflags |= MFD_SHADOW;
else
mobj->flags2 &= ~MF2_SHADOW;
mobj->drawflags &= ~MFD_SHADOW;
}
}
@ -8886,9 +8944,9 @@ void P_MobjThinker(mobj_t *mobj)
if (state < S_PLAYERBOMB1 || state > S_PLAYERBOMB20)
P_SetMobjState(mobj, S_PLAYERBOMB1);
if (mobj->target->player->kartstuff[k_comebacktimer] < TICRATE && (leveltime & 1))
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
else
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
}
else
{
@ -8903,9 +8961,9 @@ void P_MobjThinker(mobj_t *mobj)
P_SetMobjState(mobj, S_PLAYERFAKE1);
if (mobj->target->player->powers[pw_flashing] && (leveltime & 1))
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
}
// Update mobj antigravity status:
@ -8935,10 +8993,10 @@ void P_MobjThinker(mobj_t *mobj)
cur->colorized = true;
K_FlipFromObject(cur, mobj->target);
if (mobj->flags2 & MF2_DONTDRAW)
cur->flags2 |= MF2_DONTDRAW;
if (mobj->drawflags & MFD_DONTDRAW)
cur->drawflags |= MFD_DONTDRAW;
else
cur->flags2 &= ~MF2_DONTDRAW;
cur->drawflags &= ~MFD_DONTDRAW;
cur = cur->hnext;
}
@ -10296,7 +10354,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
P_SpawnMobj(newmobj->x, newmobj->y, newmobj->z, MT_EXPLODE); // poof into existance
// Transfer flags2 (strongbox, objectflip)
newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW;
newmobj->flags2 = mobj->flags2;
if (mobj->threshold == 70)
newmobj->threshold = 70;
}
@ -10348,7 +10406,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
return;
}
else if (((mobj->type == MT_RANDOMITEM && mobj->threshold == 69) || mobj->type == MT_EGGMANITEM || mobj->type == MT_FALLINGROCK) && mobj->fuse <= TICRATE)
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
}
I_Assert(mobj != NULL);
@ -10578,13 +10636,13 @@ void P_SceneryThinker(mobj_t *mobj)
&& mobj->extravalue1 > 0 && mobj->extravalue2 >= 2)
{
if (mobj->extravalue2 == 2) // I don't know why the normal logic doesn't work for this.
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
else
{
if (mobj->fuse == mobj->extravalue2)
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
else
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
}
}
@ -10715,6 +10773,9 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_FLOATINGITEM:
thing->shadowscale = FRACUNIT/2;
break;
case MT_DRIFTCLIP:
thing->shadowscale = FRACUNIT/3;
break;
default:
if (thing->flags & (MF_ENEMY|MF_BOSS))
thing->shadowscale = FRACUNIT;
@ -11711,8 +11772,8 @@ void P_RespawnSpecials(void)
ss->sector->ceilingheight) - (mthing->options >> ZSHIFT) * FRACUNIT;
if (mthing->options & MTF_AMBUSH
&& (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i)))
z -= 24*FRACUNIT;
z -= mobjinfo[i].height; // Don't forget the height!
z -= 24 * mapobjectscale;
z -= FixedMul(mobjinfo[i].height, mapobjectscale); // Don't forget the height!
}
else
{
@ -11723,7 +11784,7 @@ void P_RespawnSpecials(void)
ss->sector->floorheight) + (mthing->options >> ZSHIFT) * FRACUNIT;
if (mthing->options & MTF_AMBUSH
&& (i == MT_RING || i == MT_REDTEAMRING || i == MT_BLUETEAMRING || i == MT_COIN || P_WeaponOrPanel(i)))
z += 24*FRACUNIT;
z += 24 * mapobjectscale;
}
mo = P_SpawnMobj(x, y, z, i);
@ -11852,6 +11913,8 @@ void P_SpawnPlayer(INT32 playernum)
p->awayviewmobj = NULL;
p->awayviewtics = 0;
P_SetTarget(&p->follower, NULL); // cleanse follower from existence
// set the scale to the mobj's destscale so settings get correctly set. if we don't, they sometimes don't.
if (cv_kartdebugshrink.value && !modeattacking && !p->bot)
mobj->destscale = 6*mobj->destscale/8;
@ -11865,7 +11928,7 @@ void P_SpawnPlayer(INT32 playernum)
{
mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + P_GetPlayerHeight(p)+16*FRACUNIT, MT_PLAYERARROW);
P_SetTarget(&overheadarrow->target, mobj);
overheadarrow->flags2 |= MF2_DONTDRAW;
overheadarrow->drawflags |= MFD_DONTDRAW;
P_SetScale(overheadarrow, mobj->destscale);
if (p->spectator && pcount > 1) // HEY! No being cheap...
@ -11891,10 +11954,10 @@ void P_SpawnPlayer(INT32 playernum)
P_SetTarget(&mo->target, mobj);
mo->angle = (diff * (i-1));
mo->color = mobj->color;
if (mobj->flags2 & MF2_DONTDRAW)
mo->flags2 |= MF2_DONTDRAW;
if (mobj->drawflags & MFD_DONTDRAW)
mo->drawflags |= MFD_DONTDRAW;
else
mo->flags2 &= ~MF2_DONTDRAW;
mo->drawflags &= ~MFD_DONTDRAW;
}
}
}

View file

@ -108,7 +108,7 @@ typedef enum
// Don't use the blocklinks (inert but displayable)
MF_NOBLOCKMAP = 1<<4,
// Thin, paper-like collision bound (for visual equivalent, see FF_PAPERSPRITE)
MF_PAPERCOLLISION = 1<<5,
MF_PAPERCOLLISION = 1<<5,
// You can push this object. It can activate switches and things by pushing it on top.
MF_PUSHABLE = 1<<6,
// Object is a boss.
@ -160,7 +160,7 @@ typedef enum
MF_GRENADEBOUNCE = 1<<28,
// Run the action thinker on spawn.
MF_RUNSPAWNFUNC = 1<<29,
// Don't remap in Encore mode.
// Don't remap in Encore mode. (Not a drawflag so that it's settable by mobjinfo.)
MF_DONTENCOREMAP = 1<<30,
// free: 1<<31
} mobjflag_t;
@ -170,7 +170,7 @@ typedef enum
MF2_AXIS = 1, // It's a NiGHTS axis! (For faster checking)
MF2_TWOD = 1<<1, // Moves like it's in a 2D level
MF2_DONTRESPAWN = 1<<2, // Don't respawn this object!
MF2_DONTDRAW = 1<<3, // Don't generate a vissprite
// free: 1<<3
MF2_AUTOMATIC = 1<<4, // Thrown ring has automatic properties
MF2_RAILRING = 1<<5, // Thrown ring has rail properties
MF2_BOUNCERING = 1<<6, // Thrown ring has bounce properties
@ -187,7 +187,7 @@ typedef enum
MF2_JUSTATTACKED = 1<<17, // can be pushed by other moving mobjs
MF2_FIRING = 1<<18, // turret fire
MF2_SUPERFIRE = 1<<19, // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
MF2_SHADOW = 1<<20, // Fuzzy draw, makes targeting harder.
// free: 1<<20
MF2_STRONGBOX = 1<<21, // Flag used for "strong" random monitors.
MF2_OBJECTFLIP = 1<<22, // Flag for objects that always have flipped gravity.
MF2_SKULLFLY = 1<<23, // Special handling: skull in flight.
@ -241,14 +241,43 @@ typedef enum
MFE_SPRUNG = 1<<8,
// Platform movement
MFE_APPLYPMOMZ = 1<<9,
// SRB2Kart: Splitscreen sprite display; very wasteful but I couldn't think of another way to do it...
MFE_DRAWONLYFORP1 = 1<<10,
MFE_DRAWONLYFORP2 = 1<<11,
MFE_DRAWONLYFORP3 = 1<<12,
MFE_DRAWONLYFORP4 = 1<<13,
// free: to and including 1<<15
} mobjeflag_t;
//
// Mobj drawing flags
// Set by hex, to make masking shenanigans easier to keep track of.
//
typedef enum
{
// Don't generate a vissprite for individual screens
MFD_DONTDRAWP1 = 0x0001,
MFD_DONTDRAWP2 = 0x0002,
MFD_DONTDRAWP3 = 0x0004,
MFD_DONTDRAWP4 = 0x0008,
// Transparency override flags
MFD_TRANS10 = 0x0010,
MFD_TRANS20 = 0x0020,
MFD_TRANS30 = 0x0030,
MFD_TRANS40 = 0x0040,
MFD_TRANS50 = 0x0050,
MFD_TRANS60 = 0x0060,
MFD_TRANS70 = 0x0070,
MFD_TRANS80 = 0x0080,
MFD_TRANS90 = 0x0090,
MFD_TRANSMASK = 0x00F0,
// Brightness override flags
MFD_FULLBRIGHT = 0x0100,
MFD_SEMIBRIGHT = 0x0200,
MFD_NOBRIGHT = 0x0300,
MFD_BRIGHTMASK = 0x0F00,
// Shortcuts
MFD_DONTDRAW = MFD_DONTDRAWP1|MFD_DONTDRAWP2|MFD_DONTDRAWP3|MFD_DONTDRAWP4,
MFD_SHADOW = MFD_TRANS80|MFD_FULLBRIGHT,
MFD_TRANSSHIFT = 4,
// free: to and including 0x8000
} mobjdflag_t;
//
// PRECIPITATION flags ?! ?! ?!
//
@ -304,6 +333,7 @@ typedef struct mobj_s
UINT32 flags; // flags from mobjinfo tables
UINT32 flags2; // MF2_ flags
UINT16 eflags; // extra flags
UINT16 drawflags; // Rendering-related flags. These should not be used for game logic.
void *skin; // overrides 'sprite' when non-NULL (for player bodies to 'remember' the skin)
// Player and mobj sprites in multiplayer modes are modified

View file

@ -57,10 +57,11 @@ typedef enum
{
// RFLAGPOINT = 0x01,
// BFLAGPOINT = 0x02,
CAPSULE = 0x04,
AWAYVIEW = 0x08,
FIRSTAXIS = 0x10,
SECONDAXIS = 0x20,
CAPSULE = 4,
AWAYVIEW = 8,
FIRSTAXIS = 16,
SECONDAXIS = 32,
FOLLOWER = 64,
} player_saveflags;
//
@ -218,6 +219,9 @@ static void P_NetArchivePlayers(void)
if (players[i].axis2)
flags |= SECONDAXIS;
if (players[i].follower)
flags |= FOLLOWER;
WRITEINT16(save_p, players[i].lastsidehit);
WRITEINT16(save_p, players[i].lastlinehit);
@ -249,6 +253,14 @@ static void P_NetArchivePlayers(void)
// SRB2kart
WRITEUINT8(save_p, players[i].kartspeed);
WRITEUINT8(save_p, players[i].kartweight);
WRITEUINT8(save_p, players[i].followerskin);
WRITEUINT8(save_p, players[i].followerready); // booleans are really just numbers eh??
WRITEUINT8(save_p, players[i].followercolor);
if (flags & FOLLOWER)
WRITEUINT32(save_p, players[i].follower->mobjnum);
//
for (j = 0; j < NUMKARTSTUFF; j++)
@ -435,6 +447,13 @@ static void P_NetUnArchivePlayers(void)
// SRB2kart
players[i].kartspeed = READUINT8(save_p);
players[i].kartweight = READUINT8(save_p);
players[i].followerskin = READUINT8(save_p);
players[i].followerready = READUINT8(save_p);
players[i].followercolor = READUINT8(save_p);
if (flags & FOLLOWER)
players[i].follower = (mobj_t *)(size_t)READUINT32(save_p);
//
for (j = 0; j < NUMKARTSTUFF; j++)
@ -980,6 +999,7 @@ typedef enum
MD2_SLOPE = 1<<13,
#endif
MD2_SHADOWSCALE = 1<<14,
MD2_DRAWFLAGS = 1<<15,
} mobj_diff2_t;
typedef enum
@ -1178,6 +1198,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
#endif
if (mobj->shadowscale)
diff2 |= MD2_SHADOWSCALE;
if (mobj->drawflags)
diff2 |= MD2_DRAWFLAGS;
if (mobj->colorized)
diff2 |= MD2_COLORIZED;
if (mobj == waypointcap)
@ -1309,6 +1331,17 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
WRITEUINT8(save_p, mobj->colorized);
if (diff2 & MD2_SHADOWSCALE)
WRITEFIXED(save_p, mobj->shadowscale);
if (diff2 & MD2_DRAWFLAGS)
{
UINT16 df = mobj->drawflags;
if ((mobj->drawflags & MFD_DONTDRAW) != MFD_DONTDRAW)
{
df = (mobj->drawflags & ~MFD_DONTDRAW);
}
WRITEUINT16(save_p, df);
}
WRITEUINT32(save_p, mobj->mobjnum);
}
@ -2238,6 +2271,8 @@ static void LoadMobjThinker(actionf_p1 thinker)
mobj->colorized = READUINT8(save_p);
if (diff2 & MD2_SHADOWSCALE)
mobj->shadowscale = READFIXED(save_p);
if (diff2 & MD2_DRAWFLAGS)
mobj->drawflags = READUINT16(save_p);
if (diff & MD_REDFLAG)
{
@ -3130,6 +3165,7 @@ static void P_RelinkPointers(void)
if (!(mobj->itnext = P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type);
}
if (mobj->player)
{
if (mobj->player->capsule)
@ -3160,6 +3196,13 @@ static void P_RelinkPointers(void)
if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type);
}
if (mobj->player->follower)
{
temp = (UINT32)(size_t)mobj->player->follower;
mobj->player->follower = NULL;
if (!P_SetTarget(&mobj->player->follower, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "follower not found on %d\n", mobj->type);
}
if (mobj->player->nextwaypoint)
{
temp = (UINT32)(size_t)mobj->player->nextwaypoint;

View file

@ -1159,11 +1159,9 @@ static inline void P_SpawnEmblems(void)
emblemmobj->flags |= MF_NOCLIP;
emblemmobj->flags &= ~MF_SPECIAL;
emblemmobj->flags |= MF_NOBLOCKMAP;
emblemmobj->frame |= (tr_trans50<<FF_TRANSSHIFT);
emblemmobj->drawflags |= (tr_trans50 << MFD_TRANSSHIFT);
P_SetThingPosition(emblemmobj);
}
else
emblemmobj->frame &= ~FF_TRANSMASK;
}
}
@ -2460,6 +2458,9 @@ static void P_LevelInitStuff(void)
// and this stupid flag as a result
players[i].pflags &= ~PF_TRANSFERTOCLOSEST;
// Wipe follower from existence to avoid crashes
players[i].follower = NULL;
}
// SRB2Kart: map load variables

View file

@ -45,6 +45,7 @@
// SRB2kart
#include "m_cond.h" // M_UpdateUnlockablesAndExtraEmblems
#include "k_kart.h"
#include "k_color.h" // KartColor_Opposite
#include "console.h" // CON_LogMessage
#include "k_respawn.h"
#include "k_bot.h"
@ -653,7 +654,7 @@ static void P_DeNightserizePlayer(player_t *player)
player->mo->flags &= ~MF_NOGRAVITY;
player->mo->flags2 &= ~MF2_DONTDRAW;
player->mo->drawflags &= ~MFD_DONTDRAW;
// Restore aiming angle
if (player == &players[consoleplayer])
@ -728,7 +729,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->mo->flags |= MF_NOGRAVITY;
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags |= MFD_DONTDRAW;
player->nightstime = player->startedtime = nighttime*TICRATE;
player->bonustime = false;
@ -1622,7 +1623,7 @@ void P_SpawnShieldOrb(player_t *player)
if (shieldobj->info->painstate)
P_SetMobjState(shieldobj,shieldobj->info->painstate);
else
shieldobj->flags2 |= MF2_SHADOW;
shieldobj->drawflags |= MFD_SHADOW;
}
}
}
@ -1658,8 +1659,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->sprite = mobj->sprite;
ghost->frame = mobj->frame;
ghost->tics = -1;
ghost->frame &= ~FF_TRANSMASK;
ghost->frame |= tr_trans50<<FF_TRANSSHIFT;
ghost->drawflags |= tr_trans50 << MFD_TRANSSHIFT;
ghost->fuse = ghost->info->damage;
ghost->skin = mobj->skin;
ghost->standingslope = mobj->standingslope;
@ -3410,7 +3410,7 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd) // SRB2kart - unused.
return;
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);
// Rail has no unique thrown object, therefore its sound plays here.
S_StartSound(player->mo, sfx_rail1);
@ -4313,7 +4313,7 @@ static void P_SpectatorMovement(player_t *player)
if (mo)
{
mo->flags2 |= MF2_RAILRING;
mo->flags2 |= MF2_DONTDRAW;
mo->drawflags |= MFD_DONTDRAW;
mo->flags |= MF_NOCLIPHEIGHT;
mo->flags |= MF_NOCLIP;
mo->flags &= ~MF_MISSILE;
@ -5056,7 +5056,7 @@ static void P_NiGHTSMovement(player_t *player)
radius = player->mo->target->radius;
player->mo->flags |= MF_NOGRAVITY;
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags |= MFD_DONTDRAW;
P_SetScale(player->mo->tracer, player->mo->scale);
if (player->mo->eflags & MFE_VERTICALFLIP)
@ -7096,7 +7096,7 @@ static void P_DeathThink(player_t *player)
if (player->mo)
{
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags |= MFD_DONTDRAW;
}
}
else
@ -7454,7 +7454,7 @@ void P_DemoCameraMovement(camera_t *cam)
awayviewmobj_hack = P_SpawnMobj(cam->x, cam->y, cam->z, MT_THOK);
awayviewmobj_hack->tics = 2;
awayviewmobj_hack->flags2 |= MF2_DONTDRAW;
awayviewmobj_hack->drawflags |= MFD_DONTDRAW;
democam.soundmobj = awayviewmobj_hack;
@ -8395,6 +8395,287 @@ void P_DoTimeOver(player_t *player)
exitcountdown = 5*TICRATE;
}
/* set follower state with our weird hacks
the reason we do this is to avoid followers ever using actions (majormods, yikes!)
without having to touch p_mobj.c.
so we give it 1more tic and change the state when tic == 1 instead of 0
cool beans?
cool beans.
*/
static void P_SetFollowerState(mobj_t *f, INT32 state)
{
if (!f || P_MobjWasRemoved(f))
return; // safety net
// No, do NOT set the follower to S_NULL. Set it to S_INVISIBLE.
if (state == S_NULL)
{
state = S_INVISIBLE;
f->threshold = 1; // Threshold = 1 means stop doing anything related to setting states, so that we don't get out of S_INVISIBLE
}
// extravalue2 stores the last "first state" we used.
// because states default to idlestates, if we use an animation that uses an "ongoing" state line, don't reset it!
// this prevents it from looking very dumb
if (state == f->extravalue2)
return;
// we will save the state into extravalue2.
f->extravalue2 = state;
P_SetMobjStateNF(f, state);
if (f->state->tics > 0)
f->tics++;
}
//
//P_HandleFollower
//
//Handle the follower's spawning and moving along with the player. Do note that some of the stuff like the removal if a player doesn't exist anymore is handled in MT_FOLLOWER's thinker.
static void P_HandleFollower(player_t *player)
{
follower_t fl;
angle_t an;
fixed_t zoffs;
fixed_t sx, sy, sz;
UINT8 color;
fixed_t bubble; // bubble scale (0 if no bubble)
mobj_t *bmobj; // temp bubble mobj
if (!player->followerready)
return; // we aren't ready to perform anything follower related yet.
// How about making sure our follower exists and is added before trying to spawn it n' all?
if (player->followerskin > numfollowers-1 || player->followerskin < -1)
{
//CONS_Printf("Follower skin invlaid. Setting to -1.\n");
player->followerskin = -1;
return;
}
// don't do anything if we can't have a follower to begin with. (It gets removed under those conditions)
if (player->spectator)
return;
if (player->followerskin < 0)
return;
// Before we do anything, let's be sure of where we're supposed to be
fl = followers[player->followerskin];
an = player->mo->angle + (fl.atangle)*ANG1; // it's aproximative but it really doesn't matter in the grand scheme of things...
zoffs = (fl.zoffs)*FRACUNIT;
bubble = fl.bubblescale; // 0 if no bubble to spawn.
// do you like angle maths? I certainly don't...
sx = player->mo->x + FixedMul((player->mo->scale*fl.dist), FINECOSINE((an)>>ANGLETOFINESHIFT));
sy = player->mo->y + FixedMul((player->mo->scale*fl.dist), FINESINE((an)>>ANGLETOFINESHIFT));
// for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P
sz = player->mo->z + FixedMul(player->mo->scale, zoffs)*P_MobjFlip(player->mo);
if (player->mo->eflags & MFE_VERTICALFLIP)
sz += fl.height*player->mo->scale;
// finally, add a cool floating effect to the z height.
// not stolen from k_kart I swear!!
{
const fixed_t pi = (22<<FRACBITS) / 7; // loose approximation, this doesn't need to be incredibly precise
fixed_t sine = fl.bobamp * FINESINE((((8*pi*(fl.bobspeed)) * leveltime)>>ANGLETOFINESHIFT) & FINEMASK);
sz += FixedMul(player->mo->scale, sine)*P_MobjFlip(player->mo);
}
// Set follower colour
switch (player->followercolor)
{
case MAXSKINCOLORS: // "Match"
color = player->skincolor;
break;
case MAXSKINCOLORS+1: // "Opposite"
color = KartColor_Opposite[player->skincolor*2];
break;
default:
color = player->followercolor;
if (!color || color > MAXSKINCOLORS+2) // Make sure this isn't garbage
color = player->skincolor; // "Match" as fallback.
break;
}
if (!player->follower) // follower doesn't exist / isn't valid
{
//CONS_Printf("Spawning follower...\n");
// so let's spawn one!
P_SetTarget(&player->follower, P_SpawnMobj(sx, sy, sz, MT_FOLLOWER));
P_SetFollowerState(player->follower, fl.idlestate);
P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear
player->follower->angle = player->mo->angle;
// This is safe to only spawn it here, the follower is removed then respawned when switched.
if (bubble)
{
bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_FRONT);
P_SetTarget(&player->follower->hnext, bmobj);
P_SetTarget(&bmobj->target, player->follower); // Used to know if we have to despawn at some point.
bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_BACK);
P_SetTarget(&player->follower->hnext->hnext, bmobj); // this seems absolutely stupid, I know, but this will make updating the momentums/flags of these a bit easier.
P_SetTarget(&bmobj->target, player->follower); // Ditto
}
player->follower->extravalue1 = 0; // extravalue1 is used to know what "state set" to use.
/*
0 = idle
1 = forwards
2 = hurt
3 = win
4 = lose
5 = hitconfirm (< this one uses ->movecount as timer to know when to end, and goes back to normal states afterwards, unless hurt)
*/
}
else // follower exists, woo!
{
// Safety net (2)
if (P_MobjWasRemoved(player->follower))
{
P_SetTarget(&player->follower, NULL); // Remove this and respawn one, don't crash the game if Lua decides to P_RemoveMobj this thing.
return;
}
// first of all, handle states following the same model as above:
if (player->follower->tics == 1)
P_SetFollowerState(player->follower, player->follower->state->nextstate);
// move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)!
player->follower->momx = (sx - player->follower->x)/fl.horzlag;
player->follower->momy = (sy - player->follower->y)/fl.horzlag;
player->follower->momz = (sz - player->follower->z)/fl.vertlag;
player->follower->angle = player->mo->angle;
if (player->mo->colorized)
player->follower->color = player->mo->color;
else
player->follower->color = color;
player->follower->colorized = player->mo->colorized;
P_SetScale(player->follower, FixedMul(fl.scale, player->mo->scale));
K_GenericExtraFlagsNoZAdjust(player->follower, player->mo); // Not K_MatchGenericExtraFlag because the Z adjust it has only works properly if master & mo have the same Z height.
// Match how the player is being drawn
player->follower->drawflags = player->mo->drawflags;
// Make the follower invisible if we no contest'd rather than removing it. No one will notice the diff seriously.
// Also make the follower invisible if we choose not to have it displayed because it isn't ours. (also quick hacky check for f12)
if (player->pflags & PF_TIMEOVER || (!cv_showfollowers.value && (!P_IsDisplayPlayer(player) || displayplayers[0] != consoleplayer) ))
player->follower->drawflags |= MFD_DONTDRAW;
if (player->speed && (player->follower->momx || player->follower->momy))
player->follower->angle = R_PointToAngle2(0, 0, player->follower->momx, player->follower->momy);
// if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward.
// Make sure the follower itself is also moving however, otherwise we'll be facing angle 0
// Finally, if the follower has bubbles, move them, set their scale, etc....
// This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done!
bmobj = player->follower->hnext; // will be NULL if there's no bubble
while (bmobj && !P_MobjWasRemoved(bmobj))
{
// match follower's momentums and (e)flags(2).
bmobj->momx = player->follower->momx;
bmobj->momy = player->follower->momy;
bmobj->momz = player->follower->momz;
P_SetScale(bmobj, FixedMul(bubble, player->mo->scale));
K_GenericExtraFlagsNoZAdjust(bmobj, player->follower);
bmobj->drawflags = player->mo->drawflags;
if (player->follower->threshold) // threshold means the follower was "despawned" with S_NULL (is actually just set to S_INVISIBLE)
P_SetMobjState(bmobj, S_INVISIBLE); // sooooo... let's do the same!
bmobj = bmobj->hnext; // switch to other bubble layer or exit
}
if (player->follower->threshold)
return; // Threshold means the follower was "despanwed" with S_NULL.
// However with how the code is factored, this is just a special case of S_INVISBLE to avoid having to add other player variables.
// handle follower animations. Could probably be better...
// hurt or dead
if (player->kartstuff[k_spinouttimer] || player->mo->state == &states[S_KART_SPIN] || player->mo->health <= 0)
{
player->follower->movecount = 0; // cancel hit confirm.
player->follower->angle = player->frameangle; // spin out
if (player->follower->extravalue1 != 2)
{
player->follower->extravalue1 = 2;
P_SetFollowerState(player->follower, fl.hurtstate);
}
if (player->mo->health <= 0) // if dead, follow the player's z momentum exactly so they both look like they die at the same speed.
player->follower->momz = player->mo->momz;
}
else if (player->follower->movecount)
{
if (player->follower->extravalue1 != 5)
{
player->follower->extravalue1 = 5;
P_SetFollowerState(player->follower, fl.hitconfirmstate);
}
player->follower->movecount--;
}
else if (player->speed > 10*player->mo->scale) // animation for moving fast enough
{
if (player->follower->extravalue1 != 1)
{
player->follower->extravalue1 = 1;
P_SetFollowerState(player->follower, fl.followstate);
}
}
else // animations when nearly still. This includes winning and losing.
{
if (player->follower->extravalue1 != 0)
{
if (player->exiting) // win/ loss animations
{
if (K_IsPlayerLosing(player)) // L
{
if (player->follower->extravalue1 != 4)
{
player->follower->extravalue1 = 4;
P_SetFollowerState(player->follower, fl.losestate);
}
}
else // W
{
if (player->follower->extravalue1 != 3)
{
player->follower->extravalue1 = 3;
P_SetFollowerState(player->follower, fl.winstate);
}
}
}
else // normal standstill
{
player->follower->extravalue1 = 0;
P_SetFollowerState(player->follower, fl.idlestate);
}
}
}
}
}
//
// P_PlayerThink
//
@ -8449,6 +8730,9 @@ void P_PlayerThink(player_t *player)
player->awayviewtics = 0; // reset to zero
}
// Run followes here. We need them to run even when we're dead to follow through what we're doing.
P_HandleFollower(player);
if (player->flashcount)
player->flashcount--;
@ -8570,9 +8854,9 @@ void P_PlayerThink(player_t *player)
if (player->playerstate == PST_DEAD)
{
if (player->spectator)
player->mo->flags2 |= MF2_SHADOW;
player->mo->drawflags |= MFD_SHADOW;
else
player->mo->flags2 &= ~MF2_SHADOW;
player->mo->drawflags &= ~(MFD_TRANSMASK|MFD_BRIGHTMASK);
P_DeathThink(player);
return;
@ -8719,8 +9003,7 @@ void P_PlayerThink(player_t *player)
gmobj->fuse = 2;
if (leveltime & 1)
{
gmobj->frame &= ~FF_TRANSMASK;
gmobj->frame |= tr_trans70<<FF_TRANSSHIFT;
gmobj->drawflags |= tr_trans70 << MFD_TRANSSHIFT;
}
// Hide the mobj from our sights if we're the displayplayer and chasecam is off.
@ -8730,7 +9013,7 @@ void P_PlayerThink(player_t *player)
{
if (player == &players[displayplayers[i]] && !camera[i].chase)
{
gmobj->flags2 |= MF2_DONTDRAW;
gmobj->drawflags |= MFD_DONTDRAW;
break;
}
}
@ -8870,16 +9153,16 @@ void P_PlayerThink(player_t *player)
{
if (player->powers[pw_flashing] > 0 && player->powers[pw_flashing] < K_GetKartFlashing(player)
&& (leveltime & 1))
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags |= MFD_DONTDRAW;
else
player->mo->flags2 &= ~MF2_DONTDRAW;
player->mo->drawflags &= ~MFD_DONTDRAW;
}
/*else if (player->mo->tracer)
{
if (player->powers[pw_flashing] & 1)
player->mo->tracer->flags2 |= MF2_DONTDRAW;
player->mo->tracer->drawflags |= MFD_DONTDRAW;
else
player->mo->tracer->flags2 &= ~MF2_DONTDRAW;
player->mo->tracer->drawflags &= ~MFD_DONTDRAW;
}*/
player->pflags &= ~PF_SLIDING;
@ -9257,7 +9540,7 @@ void P_PlayerAfterThink(player_t *player)
// spectator invisibility and nogravity.
if ((netgame || multiplayer) && player->spectator)
{
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags |= MFD_DONTDRAW;
player->mo->flags |= MF_NOGRAVITY;
}

View file

@ -60,6 +60,7 @@ extern INT16 color8to16[256]; // remap color index to highcolor
extern INT16 *hicolormaps; // remap high colors to high colors..
extern CV_PossibleValue_t Color_cons_t[];
extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option.
// Load TEXTURE1/TEXTURE2/PNAMES definitions, create lookup tables
void R_LoadTextures(void);

View file

@ -147,6 +147,7 @@ static UINT8** translationtablecache[TT_CACHE_SIZE] = {NULL};
// SKINCOLOR DEFINITIONS HAVE BEEN MOVED TO K_KART.C
CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "Match", "Opposite" & NULL
/** \brief The R_InitTranslationTables

View file

@ -177,8 +177,8 @@ consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NU
consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_drawdist = {"drawdist", "8192", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
//consvar_t cv_drawdist_nights = {"drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
//consvar_t cv_precipdensity = {"precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -1498,7 +1498,6 @@ void R_RegisterEngineStuff(void)
return;
//CV_RegisterVar(&cv_precipdensity);
CV_RegisterVar(&cv_translucency);
CV_RegisterVar(&cv_drawdist);
//CV_RegisterVar(&cv_drawdist_nights);
CV_RegisterVar(&cv_drawdist_precip);

View file

@ -77,7 +77,6 @@ extern consvar_t cv_homremoval;
extern consvar_t cv_chasecam, cv_chasecam2, cv_chasecam3, cv_chasecam4;
extern consvar_t cv_flipcam, cv_flipcam2, cv_flipcam3, cv_flipcam4;
extern consvar_t cv_shadow;
extern consvar_t cv_translucency;
extern consvar_t /*cv_precipdensity,*/ cv_drawdist, /*cv_drawdist_nights,*/ cv_drawdist_precip;
extern consvar_t cv_fov;
extern consvar_t cv_skybox;

View file

@ -179,14 +179,8 @@ static void R_DrawWallSplats(void)
colfunc = basecolfunc;
break;
case SPLATDRAWMODE_TRANS:
if (!cv_translucency.value)
colfunc = basecolfunc;
else
{
dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT);
colfunc = fuzzcolfunc;
}
dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT);
colfunc = fuzzcolfunc;
break;
case SPLATDRAWMODE_SHADE:
colfunc = shadecolfunc;

View file

@ -1132,13 +1132,6 @@ static void R_SplitSprite(vissprite_t *sprite)
newsprite->extra_colormap = sector->lightlist[i].extra_colormap;
/*
if (thing->frame & FF_TRANSMASK)
;
else if (thing->flags2 & MF2_SHADOW)
;
else
*/
if (!((newsprite->cut & SC_FULLBRIGHT)
&& (!newsprite->extra_colormap || !(newsprite->extra_colormap->fog & 1))))
{
@ -1850,19 +1843,27 @@ static void R_ProjectSprite(mobj_t *thing)
vis->transmap = NULL;
// specific translucency
if (!cv_translucency.value)
; // no translucency
else if (thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
vis->transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); // because now the translucency is set through FF_TRANSMASK
if (thing->drawflags & MFD_TRANSMASK) // Object is forcing transparency to a specific value
vis->transmap = transtables + ((((thing->drawflags & MFD_TRANSMASK) - MFD_TRANS10) >> MFD_TRANSSHIFT) << FF_TRANSSHIFT);
else if (thing->frame & FF_TRANSMASK)
vis->transmap = transtables + (thing->frame & FF_TRANSMASK) - 0x10000;
vis->transmap = transtables + ((thing->frame & FF_TRANSMASK) - FF_TRANS10);
if (thing->frame & FF_FULLBRIGHT || thing->flags2 & MF2_SHADOW)
vis->cut |= SC_FULLBRIGHT;
else if (thing->frame & FF_SEMIBRIGHT)
vis->cut |= SC_SEMIBRIGHT;
if (thing->drawflags & MFD_BRIGHTMASK)
{
if (thing->drawflags & MFD_FULLBRIGHT)
vis->cut |= SC_FULLBRIGHT;
else if (thing->drawflags & MFD_SEMIBRIGHT)
vis->cut |= SC_SEMIBRIGHT;
}
else
{
if (thing->frame & FF_FULLBRIGHT)
vis->cut |= SC_FULLBRIGHT;
else if (thing->frame & FF_SEMIBRIGHT)
vis->cut |= SC_SEMIBRIGHT;
}
if (vis->cut & SC_FULLBRIGHT
if ((vis->cut & SC_FULLBRIGHT)
&& (!vis->extra_colormap || !(vis->extra_colormap->fog & 1)))
{
// full bright: goggles
@ -2054,8 +2055,9 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->patch = sprframe->lumppat[0];
// specific translucency
// (no draw flags)
if (thing->frame & FF_TRANSMASK)
vis->transmap = (thing->frame & FF_TRANSMASK) - 0x10000 + transtables;
vis->transmap = ((thing->frame & FF_TRANSMASK) - FF_TRANS10) + transtables;
else
vis->transmap = NULL;
@ -2078,9 +2080,6 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
INT32 lightnum;
fixed_t approx_dist, limit_dist;
INT32 splitflags; // check if a mobj has spliscreen flags
boolean split_drawsprite; // used for splitscreen flags
if (rendermode != render_soft)
return;
@ -2114,35 +2113,13 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
{
for (thing = sec->thinglist; thing; thing = thing->snext)
{
split_drawsprite = false;
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
if (thing->sprite == SPR_NULL)
continue;
splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
if (r_splitscreen && splitflags)
{
if (thing->eflags & MFE_DRAWONLYFORP1)
if (viewssnum == 0)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP2)
if (viewssnum == 1)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1)
if (viewssnum == 2)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2)
if (viewssnum == 3)
split_drawsprite = true;
}
else
split_drawsprite = true;
if (!split_drawsprite)
if ((viewssnum == 0 && (thing->drawflags & MFD_DONTDRAWP1))
|| (viewssnum == 1 && (thing->drawflags & MFD_DONTDRAWP2))
|| (viewssnum == 2 && (thing->drawflags & MFD_DONTDRAWP3))
|| (viewssnum == 3 && (thing->drawflags & MFD_DONTDRAWP4)))
continue;
approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
@ -2158,36 +2135,13 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
// Draw everything in sector, no checks
for (thing = sec->thinglist; thing; thing = thing->snext)
{
split_drawsprite = false;
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
if (thing->sprite == SPR_NULL)
continue;
splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
if (r_splitscreen && splitflags)
{
if (thing->eflags & MFE_DRAWONLYFORP1)
if (viewssnum == 0)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP2)
if (viewssnum == 1)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1)
if (viewssnum == 2)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2)
if (viewssnum == 3)
split_drawsprite = true;
}
else
split_drawsprite = true;
if (!split_drawsprite)
if ((viewssnum == 0 && (thing->drawflags & MFD_DONTDRAWP1))
|| (viewssnum == 1 && (thing->drawflags & MFD_DONTDRAWP2))
|| (viewssnum == 2 && (thing->drawflags & MFD_DONTDRAWP3))
|| (viewssnum == 3 && (thing->drawflags & MFD_DONTDRAWP4)))
continue;
R_ProjectSprite(thing);
@ -2891,7 +2845,12 @@ void R_DrawMasked(void)
//
// ==========================================================================
// We can assume those are tied to skins somewhat, hence why they're defined here.
INT32 numskins = 0;
follower_t followers[MAXSKINS];
// default followers are defined in SOC_FLWR in followers.kart / gfx.kart (depending on what exe this is, at this point)
skin_t skins[MAXSKINS];
// FIXTHIS: don't work because it must be inistilised before the config load
//#define SKINVALUES
@ -2954,6 +2913,19 @@ INT32 R_SkinAvailable(const char *name)
return -1;
}
// same thing but for followers:
INT32 R_FollowerAvailable(const char *name)
{
INT32 i;
for (i = 0; i < numfollowers; i++)
{
if (stricmp(followers[i].skinname,name)==0)
return i;
}
return -1;
}
// network code calls this when a 'skin change' is received
boolean SetPlayerSkin(INT32 playernum, const char *skinname)
{
@ -2979,13 +2951,37 @@ boolean SetPlayerSkin(INT32 playernum, const char *skinname)
return false;
}
// Again, same thing but for followers;
boolean SetPlayerFollower(INT32 playernum, const char *skinname)
{
INT32 i;
player_t *player = &players[playernum];
for (i = 0; i < numfollowers; i++)
{
// search in the skin list
if (stricmp(followers[i].skinname, skinname) == 0)
{
SetFollower(playernum, i);
return true;
}
}
if (P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found.\n"), skinname);
else if(server || IsPlayerAdmin(consoleplayer))
CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) follower '%s' not found\n"), playernum, player_names[playernum], skinname);
SetFollower(playernum, -1); // reminder that -1 is nothing
return false;
}
// Same as SetPlayerSkin, but uses the skin #.
// network code calls this when a 'skin change' is received
void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
{
player_t *player = &players[playernum];
skin_t *skin = &skins[skinnum];
if (skinnum >= 0 && skinnum < numskins) // Make sure it exists!
{
player->skin = skinnum;
@ -3016,6 +3012,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
if (player->mo)
P_SetScale(player->mo, player->mo->scale);
// for replays: We have changed our skin mid-game; let the game know so it can do the same in the replay!
demo_extradata[playernum] |= DXD_SKIN;
return;
@ -3028,6 +3025,53 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin
}
// you get the drill, now we do the same for followers:
void SetFollower(INT32 playernum, INT32 skinnum)
{
player_t *player = &players[playernum];
mobj_t *bub;
mobj_t *tmp;
player->followerready = true; // we are ready to perform follower related actions in the player thinker, now.
if (skinnum >= -1 && skinnum <= numfollowers) // Make sure it exists!
{
/*
We don't spawn the follower here since it'll be easier to handle all of it in the Player thinker itself.
However, we will despawn it right here if there's any to make it easy for the player thinker to replace it or delete it.
*/
if (player->follower && skinnum != player->followerskin) // this is also called when we change colour so don't respawn the follower unless we changed skins
{
// Remove follower's possible hnext list (bubble)
bub = player->follower->hnext;
while (bub && !P_MobjWasRemoved(bub))
{
tmp = bub->hnext;
P_RemoveMobj(bub);
bub = tmp;
}
P_RemoveMobj(player->follower);
P_SetTarget(&player->follower, NULL);
}
player->followerskin = skinnum;
//CONS_Printf("Updated player follower num\n");
// for replays: We have changed our follower mid-game; let the game know so it can do the same in the replay!
demo_extradata[playernum] |= DXD_FOLLOWER;
return;
}
if (P_IsLocalPlayer(player))
CONS_Alert(CONS_WARNING, M_GetText("Follower %d not found\n"), skinnum);
else if(server || IsPlayerAdmin(consoleplayer))
CONS_Alert(CONS_WARNING, "Player %d (%s) follower %d not found\n", playernum, player_names[playernum], skinnum);
SetFollower(playernum, -1); // Not found, then set -1 (nothing) as our follower.
}
//
// Add skins from a pwad, each skin preceded by 'S_SKIN' marker
//

View file

@ -103,6 +103,45 @@ typedef struct
} skin_t;
extern CV_PossibleValue_t Forceskin_cons_t[];
//
// for followers.
//
// We'll define these here because they're really just a mobj that'll follow some rules behind a player
//
typedef struct follower_s
{
char skinname[SKINNAMESIZE+1]; // Skin Name. This is what to refer to when asking the commands anything.
char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this.
UINT8 defaultcolor; // default color for menus.
fixed_t scale; // Scale relative to the player's.
fixed_t bubblescale; // Bubble scale relative to the player scale. If not set, no bubble will spawn (default)
// some position shenanigans:
INT32 atangle; // angle the object will be at around the player. The object itself will always face the same direction as the player.
INT32 dist; // distance relative to the player. (In a circle)
INT32 height; // height of the follower, this is mostly important for Z flipping.
INT32 zoffs; // Z offset relative to the player's height. Cannot be negative.
// movement options
INT32 horzlag; // Lag for X/Y displacement. Default is 2. Must be > 0 because we divide by this number.
INT32 vertlag; // not Vert from Neptunia lagging, this is for Z displacement lag Default is 6. Must be > 0 because we divide by this number.
INT32 bobamp; // Bob amplitude. Default is 4.
INT32 bobspeed; // Arbitrary modifier for bobbing speed, default is TICRATE*2 (70).
// from there on out, everything is STATES to allow customization
// these are only set once when the action is performed and are then free to animate however they want.
INT32 idlestate; // state when the player is at a standstill
INT32 followstate; // state when the player is moving
INT32 hurtstate; // state when the player is being hurt
INT32 winstate; // state when the player has won
INT32 losestate; // state when the player has lost
INT32 hitconfirmstate; // state for hit confirm
INT32 hitconfirmtime; // time to keep the above playing for
} follower_t;
// -----------
// NOT SKINS STUFF !
@ -161,7 +200,7 @@ typedef struct vissprite_s
lighttable_t *colormap; // for color translation and shadow draw
// maxbright frames as well
UINT8 *transmap; // for MF2_SHADOW sprites, which translucency table to use
UINT8 *transmap; // which translucency table to use
INT32 mobjflags;
@ -199,12 +238,18 @@ typedef struct drawnode_s
extern INT32 numskins;
extern skin_t skins[MAXSKINS];
extern INT32 numfollowers;
extern follower_t followers[MAXSKINS]; // again, use the same rules as skins, no reason not to.
boolean SetPlayerSkin(INT32 playernum,const char *skinname);
void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002
INT32 R_SkinAvailable(const char *name);
void R_AddSkins(UINT16 wadnum);
INT32 R_FollowerAvailable(const char *name);
boolean SetPlayerFollower(INT32 playernum,const char *skinname);
void SetFollower(INT32 playernum,INT32 skinnum);
#ifdef DELFILE
void R_DelSkins(UINT16 wadnum);
#endif

View file

@ -820,6 +820,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"sploss", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Down to yellow sparks
{"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // :shitsfree:
{"dbgsal", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Debug notification
{"cock", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Hammer cocks, bang bang
// SRB2Kart - Engine sounds
// Engine class A

View file

@ -897,6 +897,7 @@ typedef enum
sfx_sploss,
sfx_itfree,
sfx_dbgsal,
sfx_cock,
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
// Engine class A - Low Speed, Low Weight

View file

@ -1879,6 +1879,7 @@ void V_DrawStringScaled(
chw <<= FRACBITS;
spacew <<= FRACBITS;
lfh <<= FRACBITS;
#define Mul( id, scale ) ( id = FixedMul (scale, id) )
Mul (chw, scale);