mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into separate-spb-attack-records
This commit is contained in:
commit
d87fba3f57
20 changed files with 330 additions and 26 deletions
|
|
@ -72,6 +72,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
r_data.c
|
||||
r_debug.cpp
|
||||
r_debug_parser.cpp
|
||||
r_debug_printer.cpp
|
||||
r_draw.cpp
|
||||
r_fps.c
|
||||
r_main.cpp
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@
|
|||
#include "k_dialogue.h"
|
||||
#include "k_bans.h"
|
||||
#include "k_credits.h"
|
||||
#include "r_debug.hpp"
|
||||
|
||||
#ifdef HWRENDER
|
||||
#include "hardware/hw_main.h" // 3D View Rendering
|
||||
|
|
@ -663,6 +664,7 @@ static bool D_Display(void)
|
|||
{
|
||||
AM_Drawer();
|
||||
ST_Drawer();
|
||||
srb2::r_debug::draw_frame_list();
|
||||
F_TextPromptDrawer();
|
||||
break;
|
||||
}
|
||||
|
|
@ -858,6 +860,7 @@ void D_SRB2Loop(void)
|
|||
|
||||
g_dc = {};
|
||||
Z_Frame_Reset();
|
||||
srb2::r_debug::clear_frame_list();
|
||||
|
||||
{
|
||||
// Casting the return value of a function is bad practice (apparently)
|
||||
|
|
|
|||
|
|
@ -965,6 +965,8 @@ struct player_t
|
|||
mobj_t *hand;
|
||||
mobj_t *flickyAttacker;
|
||||
|
||||
SINT8 pitblame; // Index of last player that hit you, resets after being in control for a bit. If you deathpit, credit the old attacker!
|
||||
|
||||
UINT8 instaWhipCharge;
|
||||
UINT8 defenseLockout; // Committed to universal attack/defense, make 'em vulnerable! No whip/guard.
|
||||
UINT8 instaWhipChargeLockout; // Input safety
|
||||
|
|
@ -978,9 +980,11 @@ struct player_t
|
|||
angle_t besthanddirection;
|
||||
|
||||
INT16 incontrol; // -1 to -175 when spinning out or tumbling, 1 to 175 when not. Use to check for combo hits or emergency inputs.
|
||||
UINT16 progressivethrust; // When getting beat up in GTR_BUMPERS, speed up the longer you've been out of control.
|
||||
|
||||
boolean markedfordeath;
|
||||
boolean dotrickfx;
|
||||
UINT8 bumperinflate;
|
||||
|
||||
UINT8 ringboxdelay; // Delay until Ring Box auto-activates
|
||||
UINT8 ringboxaward; // Where did we stop?
|
||||
|
|
|
|||
71
src/g_demo.c
71
src/g_demo.c
|
|
@ -56,6 +56,7 @@
|
|||
#include "k_follower.h"
|
||||
#include "k_vote.h"
|
||||
#include "k_credits.h"
|
||||
#include "k_grandprix.h"
|
||||
|
||||
boolean nodrawers; // for comparative timing purposes
|
||||
boolean noblit; // for comparative timing purposes
|
||||
|
|
@ -64,7 +65,7 @@ tic_t demostarttime; // for comparative timing purposes
|
|||
static char demoname[MAX_WADPATH];
|
||||
static savebuffer_t demobuf = {0};
|
||||
static UINT8 *demotime_p, *demoinfo_p;
|
||||
static UINT8 demoflags;
|
||||
static UINT16 demoflags;
|
||||
boolean demosynced = true; // console warning message
|
||||
|
||||
struct demovars_s demo;
|
||||
|
|
@ -103,7 +104,7 @@ demoghost *ghosts = NULL;
|
|||
// DEMO RECORDING
|
||||
//
|
||||
|
||||
#define DEMOVERSION 0x0007
|
||||
#define DEMOVERSION 0x0008
|
||||
#define DEMOHEADER "\xF0" "KartReplay" "\x0F"
|
||||
|
||||
#define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP|ATTACKING_SPB) // This demo contains time/lap data
|
||||
|
|
@ -117,6 +118,8 @@ demoghost *ghosts = NULL;
|
|||
#define DF_ENCORE 0x40
|
||||
#define DF_MULTIPLAYER 0x80 // This demo was recorded in multiplayer mode!
|
||||
|
||||
#define DF_GRANDPRIX 0x0100
|
||||
|
||||
#define DEMO_SPECTATOR 0x01
|
||||
#define DEMO_KICKSTART 0x02
|
||||
#define DEMO_SHRINKME 0x04
|
||||
|
|
@ -2126,6 +2129,9 @@ void G_BeginRecording(void)
|
|||
if (multiplayer)
|
||||
demoflags |= DF_LUAVARS;
|
||||
|
||||
if (grandprixinfo.gp)
|
||||
demoflags |= DF_GRANDPRIX;
|
||||
|
||||
// Setup header.
|
||||
M_Memcpy(demobuf.p, DEMOHEADER, 12); demobuf.p += 12;
|
||||
WRITEUINT8(demobuf.p,VERSION);
|
||||
|
|
@ -2148,7 +2154,7 @@ void G_BeginRecording(void)
|
|||
WRITESTRINGN(demobuf.p, mapheaderinfo[gamemap-1]->lumpname, MAXMAPLUMPNAME);
|
||||
M_Memcpy(demobuf.p, mapmd5, 16); demobuf.p += 16;
|
||||
|
||||
WRITEUINT8(demobuf.p, demoflags);
|
||||
WRITEUINT16(demobuf.p, demoflags);
|
||||
|
||||
WRITESTRINGN(demobuf.p, gametypes[gametype]->name, MAXGAMETYPELENGTH);
|
||||
|
||||
|
|
@ -2186,6 +2192,13 @@ void G_BeginRecording(void)
|
|||
// Save netvar data
|
||||
CV_SaveDemoVars(&demobuf.p);
|
||||
|
||||
if ((demoflags & DF_GRANDPRIX))
|
||||
{
|
||||
WRITEUINT8(demobuf.p, grandprixinfo.gamespeed);
|
||||
WRITEUINT8(demobuf.p, grandprixinfo.masterbots == true);
|
||||
WRITEUINT8(demobuf.p, grandprixinfo.eventmode);
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
|
@ -2274,6 +2287,10 @@ void G_BeginRecording(void)
|
|||
|
||||
// And mobjtype_t is best with UINT32 too...
|
||||
WRITEUINT32(demobuf.p, player->followitem);
|
||||
|
||||
// GP
|
||||
WRITESINT8(demobuf.p, player->lives);
|
||||
WRITEINT16(demobuf.p, player->totalring);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2364,7 +2381,7 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap)
|
|||
UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
||||
{
|
||||
UINT8 *buffer,*p;
|
||||
UINT8 flags;
|
||||
UINT16 flags;
|
||||
UINT32 oldtime = UINT32_MAX, newtime = UINT32_MAX;
|
||||
UINT32 oldlap = UINT32_MAX, newlap = UINT32_MAX;
|
||||
UINT16 oldversion;
|
||||
|
|
@ -2395,7 +2412,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
p += 4; // PLAY
|
||||
SKIPSTRING(p); // gamemap
|
||||
p += 16; // map md5
|
||||
flags = READUINT8(p); // demoflags
|
||||
flags = READUINT16(p); // demoflags
|
||||
SKIPSTRING(p); // gametype
|
||||
p++; // numlaps
|
||||
G_SkipDemoExtraFiles(&p);
|
||||
|
|
@ -2454,7 +2471,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
|
|||
} p += 4; // "PLAY"
|
||||
SKIPSTRING(p); // gamemap
|
||||
p += 16; // mapmd5
|
||||
flags = READUINT8(p);
|
||||
flags = READUINT16(p);
|
||||
SKIPSTRING(p); // gametype
|
||||
p++; // numlaps
|
||||
G_SkipDemoExtraFiles(&p);
|
||||
|
|
@ -2498,7 +2515,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
{
|
||||
savebuffer_t info = {0};
|
||||
UINT8 *extrainfo_p;
|
||||
UINT8 version, subversion, pdemoflags, worknumskins, skinid;
|
||||
UINT8 version, subversion, worknumskins, skinid;
|
||||
UINT16 pdemoflags;
|
||||
democharlist_t *skinlist = NULL;
|
||||
UINT16 pdemoversion, count;
|
||||
char mapname[MAXMAPLUMPNAME],gtname[MAXGAMETYPELENGTH];
|
||||
|
|
@ -2578,7 +2596,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
goto corrupt;
|
||||
}
|
||||
|
||||
pdemoflags = READUINT8(info.p);
|
||||
pdemoflags = READUINT16(info.p);
|
||||
|
||||
// temp?
|
||||
if (!(pdemoflags & DF_MULTIPLAYER))
|
||||
|
|
@ -2649,6 +2667,9 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
if (pdemoflags & DF_ENCORE)
|
||||
pdemo->kartspeed |= DF_ENCORE;
|
||||
|
||||
if (pdemoflags & DF_GRANDPRIX)
|
||||
pdemo->gp = true;
|
||||
|
||||
// Read standings!
|
||||
count = 0;
|
||||
|
||||
|
|
@ -2914,7 +2935,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
READSTRINGN(demobuf.p, mapname, sizeof(mapname)); // gamemap
|
||||
demobuf.p += 16; // mapmd5
|
||||
|
||||
demoflags = READUINT8(demobuf.p);
|
||||
demoflags = READUINT16(demobuf.p);
|
||||
|
||||
READSTRINGN(demobuf.p, gtname, sizeof(gtname)); // gametype
|
||||
|
||||
|
|
@ -3041,6 +3062,15 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
// net var data
|
||||
CV_LoadDemoVars(&demobuf.p);
|
||||
|
||||
memset(&grandprixinfo, 0, sizeof grandprixinfo);
|
||||
if ((demoflags & DF_GRANDPRIX))
|
||||
{
|
||||
grandprixinfo.gp = true;
|
||||
grandprixinfo.gamespeed = READUINT8(demobuf.p);
|
||||
grandprixinfo.masterbots = READUINT8(demobuf.p) != 0;
|
||||
grandprixinfo.eventmode = READUINT8(demobuf.p);
|
||||
}
|
||||
|
||||
// Sigh ... it's an empty demo.
|
||||
if (*demobuf.p == DEMOMARKER)
|
||||
{
|
||||
|
|
@ -3216,6 +3246,10 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
// Followitem
|
||||
players[p].followitem = READUINT32(demobuf.p);
|
||||
|
||||
// GP
|
||||
players[p].lives = READSINT8(demobuf.p);
|
||||
players[p].totalring = READINT16(demobuf.p);
|
||||
|
||||
// Look for the next player
|
||||
p = READUINT8(demobuf.p);
|
||||
}
|
||||
|
|
@ -3249,7 +3283,7 @@ void G_DoPlayDemo(const char *defdemoname)
|
|||
P_SetRandSeed(i, randseed[i]);
|
||||
}
|
||||
|
||||
G_InitNew(demoflags & DF_ENCORE, gamemap, true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
|
||||
G_InitNew((demoflags & DF_ENCORE) != 0, gamemap, true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
|
||||
|
||||
for (i = 0; i < numslots; i++)
|
||||
{
|
||||
|
|
@ -3288,7 +3322,7 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
|
|||
INT32 i;
|
||||
char name[17], color[MAXCOLORNAME+1], md5[16];
|
||||
demoghost *gh;
|
||||
UINT8 flags;
|
||||
UINT16 flags;
|
||||
UINT8 *p;
|
||||
mapthing_t *mthing;
|
||||
UINT16 count, ghostversion;
|
||||
|
|
@ -3346,7 +3380,7 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
|
|||
SKIPSTRING(p); // gamemap
|
||||
p += 16; // mapmd5 (possibly check for consistency?)
|
||||
|
||||
flags = READUINT8(p);
|
||||
flags = READUINT16(p);
|
||||
if (!(flags & DF_GHOST))
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: No ghost data in this demo.\n"), defdemoname);
|
||||
|
|
@ -3399,6 +3433,9 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
|
|||
p++;
|
||||
}
|
||||
|
||||
if ((flags & DF_GRANDPRIX))
|
||||
p += 3;
|
||||
|
||||
if (*p == DEMOMARKER)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), defdemoname);
|
||||
|
|
@ -3443,6 +3480,9 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
|
|||
|
||||
p += 4; // followitem (maybe change later)
|
||||
|
||||
p += 1; // lives
|
||||
p += 2; // rings
|
||||
|
||||
if (READUINT8(p) != 0xFF)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), defdemoname);
|
||||
|
|
@ -3534,7 +3574,7 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
|
|||
{
|
||||
UINT8 *p = buffer;
|
||||
UINT16 ghostversion;
|
||||
UINT8 flags;
|
||||
UINT16 flags;
|
||||
INT32 i;
|
||||
staffbrief_t temp = {0};
|
||||
staffbrief_t *ret = NULL;
|
||||
|
|
@ -3575,7 +3615,7 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
|
|||
SKIPSTRING(p); // gamemap
|
||||
p += 16; // mapmd5 (possibly check for consistency?)
|
||||
|
||||
flags = READUINT8(p);
|
||||
flags = READUINT16(p);
|
||||
if (!(flags & DF_GHOST))
|
||||
{
|
||||
goto fail; // we don't NEED to do it here, but whatever
|
||||
|
|
@ -3608,6 +3648,9 @@ staffbrief_t *G_GetStaffGhostBrief(UINT8 *buffer)
|
|||
p++; // stealth
|
||||
}
|
||||
|
||||
if ((flags & DF_GRANDPRIX))
|
||||
p += 3;
|
||||
|
||||
// Assert first player is in and then read name
|
||||
if (READUINT8(p) != 0)
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ struct menudemo_t {
|
|||
INT16 gametype;
|
||||
SINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
|
||||
UINT8 numlaps;
|
||||
UINT8 gp;
|
||||
|
||||
struct {
|
||||
UINT8 ranking;
|
||||
|
|
|
|||
|
|
@ -2398,6 +2398,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
p->ringvolume = 255;
|
||||
p->ringtransparency = 255;
|
||||
|
||||
p->pitblame = -1;
|
||||
|
||||
p->topAccel = MAXTOPACCEL;
|
||||
|
||||
p->botvars.rubberband = FRACUNIT;
|
||||
|
|
|
|||
52
src/k_kart.c
52
src/k_kart.c
|
|
@ -4562,6 +4562,22 @@ static boolean K_LastTumbleBounceCondition(player_t *player)
|
|||
return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 60);
|
||||
}
|
||||
|
||||
// Bumpers give you bonus launch height and speed, strengthening your DI to help evade combos.
|
||||
// bumperinflate visuals are handled by MT_BATTLEBUMPER, but the effects are in K_KartPlayerThink.
|
||||
void K_BumperInflate(player_t *player)
|
||||
{
|
||||
if (!player || P_MobjWasRemoved(player->mo))
|
||||
return;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
return;
|
||||
|
||||
player->bumperinflate = 3;
|
||||
|
||||
if (player->mo->health > 1)
|
||||
S_StartSound(player->mo, sfx_cdpcm9);
|
||||
}
|
||||
|
||||
static void K_HandleTumbleBounce(player_t *player)
|
||||
{
|
||||
player->tumbleBounces++;
|
||||
|
|
@ -4609,6 +4625,8 @@ static void K_HandleTumbleBounce(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
K_BumperInflate(player);
|
||||
|
||||
// A bit of damage hitlag.
|
||||
// This gives a window for DI!!
|
||||
K_AddHitLag(player->mo, 3, true);
|
||||
|
|
@ -8794,6 +8812,33 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
if (player->hyudorotimer)
|
||||
player->hyudorotimer--;
|
||||
|
||||
if (player->bumperinflate && player->mo->hitlag == 0)
|
||||
{
|
||||
fixed_t thrustdelta = MAXCOMBOTHRUST - MINCOMBOTHRUST;
|
||||
fixed_t floatdelta = MAXCOMBOFLOAT - MINCOMBOFLOAT;
|
||||
|
||||
fixed_t thrustpertic = thrustdelta / MAXCOMBOTIME;
|
||||
fixed_t floatpertic = floatdelta / MAXCOMBOTIME;
|
||||
|
||||
fixed_t totalthrust = thrustpertic * player->progressivethrust + MINCOMBOTHRUST;
|
||||
fixed_t totalfloat = floatpertic * player->progressivethrust + MINCOMBOFLOAT;
|
||||
|
||||
if (player->speed > K_GetKartSpeed(player, false, false))
|
||||
totalthrust = 0;
|
||||
|
||||
if (player->tumbleBounces && player->tumbleBounces <= TUMBLEBOUNCES)
|
||||
{
|
||||
player->mo->momz += totalfloat;
|
||||
P_Thrust(player->mo, K_MomentumAngle(player->mo), totalthrust/2);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_Thrust(player->mo, K_MomentumAngle(player->mo), totalthrust);
|
||||
}
|
||||
|
||||
player->bumperinflate--;
|
||||
}
|
||||
|
||||
if (player->ringvolume < MINRINGVOLUME)
|
||||
player->ringvolume = MINRINGVOLUME;
|
||||
else if (MAXRINGVOLUME - player->ringvolume < RINGVOLUMEREGEN)
|
||||
|
|
@ -8900,12 +8945,16 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (player->spinouttimer || player->tumbleBounces)
|
||||
{
|
||||
if (player->progressivethrust < MAXCOMBOTIME)
|
||||
player->progressivethrust++;
|
||||
if (player->incontrol > 0)
|
||||
player->incontrol = 0;
|
||||
player->incontrol--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->progressivethrust)
|
||||
player->progressivethrust--;
|
||||
if (player->incontrol < 0)
|
||||
player->incontrol = 0;
|
||||
player->incontrol++;
|
||||
|
|
@ -8914,6 +8963,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->incontrol = min(player->incontrol, 5*TICRATE);
|
||||
player->incontrol = max(player->incontrol, -5*TICRATE);
|
||||
|
||||
if (player->incontrol == 3*TICRATE)
|
||||
player->pitblame = -1;
|
||||
|
||||
if (P_PlayerInPain(player) || player->respawn.state != RESPAWNST_NONE)
|
||||
{
|
||||
player->lastpickuptype = -1; // got your ass beat, go grab anything
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@ Make sure this matches the actual number of states
|
|||
#define INSTAWHIP_TETHERBLOCK (TICRATE*4)
|
||||
#define PUNISHWINDOW (7*TICRATE/10)
|
||||
|
||||
#define MAXCOMBOTHRUST (mapobjectscale*20)
|
||||
#define MAXCOMBOFLOAT (mapobjectscale*10)
|
||||
#define MINCOMBOTHRUST (mapobjectscale*2)
|
||||
#define MINCOMBOFLOAT (mapobjectscale*1)
|
||||
#define MAXCOMBOTIME (TICRATE*4)
|
||||
|
||||
#define FLAMESHIELD_MAX (120)
|
||||
|
||||
#define RR_PROJECTILE_FUSE (8*TICRATE)
|
||||
|
|
@ -257,6 +263,8 @@ boolean K_IsPlayingDisplayPlayer(player_t *player);
|
|||
boolean K_PlayerCanPunt(player_t *player);
|
||||
void K_MakeObjectReappear(mobj_t *mo);
|
||||
|
||||
void K_BumperInflate(player_t *player);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -257,8 +257,14 @@ static int player_get(lua_State *L)
|
|||
lua_pushboolean(L, plr->flipDI);
|
||||
else if (fastcmp(field,"markedfordeath"))
|
||||
lua_pushboolean(L, plr->markedfordeath);
|
||||
else if (fastcmp(field,"incontrol"))
|
||||
lua_pushboolean(L, plr->incontrol);
|
||||
else if (fastcmp(field,"progressivethrust"))
|
||||
lua_pushboolean(L, plr->progressivethrust);
|
||||
else if (fastcmp(field,"dotrickfx"))
|
||||
lua_pushboolean(L, plr->dotrickfx);
|
||||
else if (fastcmp(field,"bumperinflate"))
|
||||
lua_pushboolean(L, plr->bumperinflate);
|
||||
else if (fastcmp(field,"ringboxdelay"))
|
||||
lua_pushinteger(L, plr->ringboxdelay);
|
||||
else if (fastcmp(field,"ringboxaward"))
|
||||
|
|
@ -351,6 +357,8 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->topAccel);
|
||||
else if (fastcmp(field,"instaWhipCharge"))
|
||||
lua_pushinteger(L, plr->instaWhipCharge);
|
||||
else if (fastcmp(field,"pitblame"))
|
||||
lua_pushinteger(L, plr->pitblame);
|
||||
else if (fastcmp(field,"defenseLockout"))
|
||||
lua_pushinteger(L, plr->defenseLockout);
|
||||
else if (fastcmp(field,"oldGuard"))
|
||||
|
|
@ -781,10 +789,16 @@ static int player_set(lua_State *L)
|
|||
plr->justDI = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"flipDI"))
|
||||
plr->flipDI = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"incontrol"))
|
||||
plr->incontrol = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"progressivethrust"))
|
||||
plr->progressivethrust = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"markedfordeath"))
|
||||
plr->markedfordeath = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"dotrickfx"))
|
||||
plr->dotrickfx = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"bumperinflate"))
|
||||
plr->bumperinflate = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"ringboxdelay"))
|
||||
plr->ringboxdelay = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"ringboxaward"))
|
||||
|
|
@ -877,6 +891,8 @@ static int player_set(lua_State *L)
|
|||
plr->topAccel = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"instaWhipCharge"))
|
||||
plr->instaWhipCharge = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"pitblame"))
|
||||
plr->pitblame = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"defenseLockout"))
|
||||
plr->defenseLockout = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"oldGuard"))
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref)
|
|||
|
||||
if (info.gametype == GT_RACE)
|
||||
{
|
||||
gametype_ = Gametype(GT_RACE, Gametype::Race {
|
||||
gametype_ = Gametype(GT_RACE, info.gp, Gametype::Race {
|
||||
info.numlaps,
|
||||
kartspeed_cons_t[(info.kartspeed & ~(DF_ENCORE)) + 1].strvalue,
|
||||
(info.kartspeed & DF_ENCORE) != 0,
|
||||
|
|
@ -245,7 +245,7 @@ EggTVData::Replay::Replay(Folder::Cache::ReplayRef& ref) : ref_(&ref)
|
|||
}
|
||||
else
|
||||
{
|
||||
gametype_ = Gametype(info.gametype);
|
||||
gametype_ = Gametype(info.gametype, info.gp);
|
||||
}
|
||||
|
||||
for (const auto& data : info.standings)
|
||||
|
|
|
|||
|
|
@ -193,12 +193,12 @@ public:
|
|||
};
|
||||
|
||||
explicit Gametype() {}
|
||||
explicit Gametype(INT16 gt, Race race) : gametype_(get(gt)), var_(race) {}
|
||||
explicit Gametype(INT16 gt) : gametype_(get(gt)) {}
|
||||
explicit Gametype(INT16 gt, bool gp) : gametype_(get(gt)), name_(get_name(gt, gp)) {}
|
||||
explicit Gametype(INT16 gt, bool gp, Race race) : Gametype(gt, gp) { var_ = race; }
|
||||
|
||||
bool valid() const { return gametype_; }
|
||||
|
||||
std::string_view name() const { return valid() ? gametype_->name : "<Unknown gametype>"; }
|
||||
std::string_view name() const { return name_; }
|
||||
UINT32 rules() const { return valid() ? gametype_->rules : 0u; }
|
||||
|
||||
bool ranks_time() const { return !ranks_points(); }
|
||||
|
|
@ -208,8 +208,29 @@ public:
|
|||
|
||||
private:
|
||||
const gametype_t* gametype_ = nullptr;
|
||||
std::string_view name_;
|
||||
std::variant<std::monostate, Race> var_;
|
||||
|
||||
std::string_view get_name(INT16 gt, bool gp) const
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
return "<Unknown gametype>";
|
||||
}
|
||||
|
||||
if (gt == GT_SPECIAL)
|
||||
{
|
||||
return "Sealed Star";
|
||||
}
|
||||
|
||||
if ((rules() & GTR_PRISONS) && gp)
|
||||
{
|
||||
return "Prison Break";
|
||||
}
|
||||
|
||||
return gametype_->name;
|
||||
}
|
||||
|
||||
static gametype_t* get(INT16 gt) { return gt >= 0 && gt < numgametypes ? gametypes[gt] : nullptr; }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -92,10 +92,9 @@ public:
|
|||
std::unordered_map<std::string_view, patch> gametype = {
|
||||
{"Race", "RHGT1"},
|
||||
{"Battle", "RHGT2"},
|
||||
|
||||
// TODO: requires support in the demo format
|
||||
//{"Prisons", "RHGT3"},
|
||||
//{"Special", "RHGT4"},
|
||||
{"Prison Break", "RHGT3"},
|
||||
{"Sealed Star", "RHGT4"},
|
||||
{"Versus", "RHGT5"},
|
||||
};
|
||||
|
||||
patch fav = "RHFAV";
|
||||
|
|
|
|||
|
|
@ -2502,7 +2502,17 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
|
||||
if (gametyperules & (GTR_BUMPERS|GTR_CHECKPOINTS))
|
||||
{
|
||||
player->mo->health--;
|
||||
if ((player->pitblame > -1) && (player->pitblame < MAXPLAYERS)
|
||||
&& (playeringame[player->pitblame]) && (!players[player->pitblame].spectator)
|
||||
&& (players[player->pitblame].mo) && (!P_MobjWasRemoved(players[player->pitblame].mo)))
|
||||
{
|
||||
P_DamageMobj(player->mo, players[player->pitblame].mo, players[player->pitblame].mo, 1, DMG_KARMA);
|
||||
player->pitblame = -1;
|
||||
}
|
||||
else if (player->mo->health > 1 || battleprisons)
|
||||
{
|
||||
player->mo->health--;
|
||||
}
|
||||
}
|
||||
|
||||
if (player->mo->health <= 0)
|
||||
|
|
@ -3134,6 +3144,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
}
|
||||
}
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
if (damagetype != DMG_DEATHPIT)
|
||||
{
|
||||
player->pitblame = source->player - players;
|
||||
}
|
||||
}
|
||||
|
||||
player->sneakertimer = player->numsneakers = 0;
|
||||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
|
|
@ -3143,6 +3161,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
player->preventfailsafe = TICRATE*3;
|
||||
player->pflags &= ~PF_GAINAX;
|
||||
Obj_EndBungee(player);
|
||||
K_BumperInflate(target->player);
|
||||
|
||||
if (player->spectator == false && !(player->charflags & SF_IRONMAN))
|
||||
{
|
||||
|
|
@ -3167,6 +3186,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
//P_KillPlayer(player, inflictor, source, damagetype);
|
||||
}
|
||||
|
||||
// Death save! On your last hit, no matter what, demote to weakest damage type for one last escape chance.
|
||||
if (player->mo->health == 2 && damage && gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
S_StartSound(target, sfx_gshc7);
|
||||
player->flashing = TICRATE;
|
||||
type = DMG_STUMBLE;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DMG_STING:
|
||||
|
|
|
|||
|
|
@ -4064,6 +4064,15 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
|||
P_PlayerHitBounceLine(bestslideline, &result->normal);
|
||||
mo->eflags |= MFE_JUSTBOUNCEDWALL;
|
||||
|
||||
// Combo avoidance!
|
||||
if (mo->player && P_PlayerInPain(mo->player) && gametyperules & GTR_BUMPERS && mo->health == 1)
|
||||
{
|
||||
K_StumblePlayer(mo->player);
|
||||
K_BumperInflate(mo->player);
|
||||
mo->player->tumbleBounces = TUMBLEBOUNCES;
|
||||
mo->hitlag = max(mo->hitlag, 6);
|
||||
}
|
||||
|
||||
mo->momx = tmxmove;
|
||||
mo->momy = tmymove;
|
||||
mo->player->cmomx = tmxmove;
|
||||
|
|
|
|||
12
src/p_mobj.c
12
src/p_mobj.c
|
|
@ -6235,6 +6235,18 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
// Shrink your items if the player shrunk too.
|
||||
P_SetScale(mobj, mobj->target->scale);
|
||||
|
||||
if (mobj->target->player->bumperinflate && bumpers > mobj->threshold)
|
||||
{
|
||||
mobj->frame |= FF_INVERT;
|
||||
// This line sucks. Scale to player, plus up to 1.5x their size based on how long the combo you're in is.
|
||||
P_SetScale(mobj, mobj->target->scale + (mobj->target->player->progressivethrust * 3 * mobj->target->scale / 2 / MAXCOMBOTIME));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mobj->frame &= ~FF_INVERT;
|
||||
}
|
||||
|
||||
P_UnsetThingPosition(mobj);
|
||||
{
|
||||
const angle_t fa = ang >> ANGLETOFINESHIFT;
|
||||
|
|
|
|||
|
|
@ -578,6 +578,8 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
|
||||
WRITEMEM(save->p, players[i].public_key, PUBKEYLENGTH);
|
||||
|
||||
WRITESINT8(save->p, players[i].pitblame);
|
||||
|
||||
WRITEUINT8(save->p, players[i].instaWhipCharge);
|
||||
WRITEUINT8(save->p, players[i].defenseLockout);
|
||||
WRITEUINT8(save->p, players[i].oldGuard);
|
||||
|
|
@ -590,9 +592,11 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEANGLE(save->p, players[i].besthanddirection);
|
||||
|
||||
WRITEINT16(save->p, players[i].incontrol);
|
||||
WRITEUINT16(save->p, players[i].progressivethrust);
|
||||
|
||||
WRITEUINT8(save->p, players[i].markedfordeath);
|
||||
WRITEUINT8(save->p, players[i].dotrickfx);
|
||||
WRITEUINT8(save->p, players[i].bumperinflate);
|
||||
|
||||
WRITEUINT8(save->p, players[i].ringboxdelay);
|
||||
WRITEUINT8(save->p, players[i].ringboxaward);
|
||||
|
|
@ -1153,6 +1157,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
|
||||
READMEM(save->p, players[i].public_key, PUBKEYLENGTH);
|
||||
|
||||
players[i].pitblame = READSINT8(save->p);
|
||||
|
||||
players[i].instaWhipCharge = READUINT8(save->p);
|
||||
players[i].defenseLockout = READUINT8(save->p);
|
||||
players[i].oldGuard = READUINT8(save->p);
|
||||
|
|
@ -1165,9 +1171,11 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].besthanddirection = READANGLE(save->p);
|
||||
|
||||
players[i].incontrol = READINT16(save->p);
|
||||
players[i].progressivethrust = READUINT16(save->p);
|
||||
|
||||
players[i].markedfordeath = READUINT8(save->p);
|
||||
players[i].dotrickfx = READUINT8(save->p);
|
||||
players[i].bumperinflate = READUINT8(save->p);
|
||||
|
||||
players[i].ringboxdelay = READUINT8(save->p);
|
||||
players[i].ringboxaward = READUINT8(save->p);
|
||||
|
|
|
|||
24
src/r_debug.hpp
Normal file
24
src/r_debug.hpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2024 by James Robert Roman.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef r_debug_hpp
|
||||
#define r_debug_hpp
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
namespace srb2::r_debug
|
||||
{
|
||||
|
||||
void add_texture_to_frame_list(INT32 texnum);
|
||||
void clear_frame_list();
|
||||
void draw_frame_list();
|
||||
|
||||
}; // namespace srb2::r_debug
|
||||
|
||||
#endif/*r_debug_hpp*/
|
||||
67
src/r_debug_printer.cpp
Normal file
67
src/r_debug_printer.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2024 by James Robert Roman.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "r_debug.hpp"
|
||||
#include "v_draw.hpp"
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "doomtype.h"
|
||||
#include "r_textures.h"
|
||||
#include "screen.h"
|
||||
|
||||
using srb2::Draw;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::unordered_set<INT32> frame_list;
|
||||
|
||||
}; // namespace
|
||||
|
||||
namespace srb2::r_debug
|
||||
{
|
||||
|
||||
void add_texture_to_frame_list(INT32 texnum)
|
||||
{
|
||||
if (cht_debug & DBG_RENDER)
|
||||
{
|
||||
frame_list.insert(texnum);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_frame_list()
|
||||
{
|
||||
frame_list.clear();
|
||||
}
|
||||
|
||||
void draw_frame_list()
|
||||
{
|
||||
if (!(cht_debug & DBG_RENDER))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Draw line = Draw(4, BASEVIDHEIGHT - 20)
|
||||
.font(Draw::Font::kConsole)
|
||||
.scale(0.5)
|
||||
.flags(V_ORANGEMAP | V_SNAPTOLEFT | V_SNAPTOBOTTOM);
|
||||
|
||||
line.y(-4 * static_cast<int>(frame_list.size() - 1)).size(32, 4 * frame_list.size()).fill(31);
|
||||
|
||||
for (INT32 texnum : frame_list)
|
||||
{
|
||||
line.text("{}", std::string_view {textures[texnum]->name, 8});
|
||||
line = line.y(-4);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace srb2::r_debug
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
#include "core/memory.h"
|
||||
#include "core/thread_pool.h"
|
||||
#include "k_terrain.h"
|
||||
#include "r_debug.hpp"
|
||||
|
||||
extern "C" consvar_t cv_debugfinishline;
|
||||
|
||||
|
|
@ -2064,7 +2065,13 @@ void R_StoreWallRange(INT32 start, INT32 stop)
|
|||
auto get_flat_tex = [](INT32 texnum)
|
||||
{
|
||||
texnum = R_GetTextureNum(texnum);
|
||||
return textures[texnum]->holes ? 0 : texnum; // R_DrawWallColumn cannot render holey textures
|
||||
if (textures[texnum]->holes)
|
||||
{
|
||||
srb2::r_debug::add_texture_to_frame_list(texnum);
|
||||
// R_DrawWallColumn cannot render holey textures
|
||||
return R_GetTextureNum(R_CheckTextureNumForName("TRANSER1"));
|
||||
}
|
||||
return texnum;
|
||||
};
|
||||
|
||||
if (!backsector)
|
||||
|
|
|
|||
|
|
@ -1448,7 +1448,7 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"gshc4", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gshc5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gshc6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gshc7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gshc7", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, //x8away
|
||||
{"gshc8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gshc9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gshca", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue