Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into hwr2-twodee

This commit is contained in:
toaster 2023-03-01 12:30:58 +00:00
commit 40271cd128
29 changed files with 500 additions and 326 deletions

View file

@ -2610,15 +2610,6 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting
// don't look through someone's view who isn't there
if (playernum == displayplayers[0] && !demo.playback)
{
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true);
displayplayers[0] = consoleplayer;
}
G_RemovePartyMember(playernum);
// Reset player data
@ -2638,6 +2629,9 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
LUA_InvalidatePlayer(&players[playernum]);
// don't look through someone's view who isn't there
G_ResetViews();
K_CheckBumpers();
P_CheckRacers();
}

View file

@ -359,10 +359,10 @@ struct doomdata_t
UINT8 reserved; // Padding
union
{
clientcmd_pak clientpak; // 145 bytes
client2cmd_pak client2pak; // 202 bytes
client3cmd_pak client3pak; // 258 bytes(?)
client4cmd_pak client4pak; // 316 bytes(?)
clientcmd_pak clientpak; // 147 bytes
client2cmd_pak client2pak; // 206 bytes
client3cmd_pak client3pak; // 264 bytes(?)
client4cmd_pak client4pak; // 324 bytes(?)
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)

View file

@ -548,8 +548,6 @@ static CV_PossibleValue_t perfstats_cons_t[] = {
};
consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NULL);
consvar_t cv_director = CVAR_INIT ("director", "Off", 0, CV_OnOff, NULL);
consvar_t cv_schedule = CVAR_INIT ("schedule", "On", CV_NETVAR|CV_CALL, CV_OnOff, Schedule_OnChange);
consvar_t cv_automate = CVAR_INIT ("automate", "On", CV_NETVAR, CV_OnOff, NULL);
@ -1060,8 +1058,6 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_scr_width);
CV_RegisterVar(&cv_scr_height);
CV_RegisterVar(&cv_director);
CV_RegisterVar(&cv_soundtest);
CV_RegisterVar(&cv_invincmusicfade);
@ -1596,21 +1592,8 @@ static void FinalisePlaystateChange(INT32 playernum)
K_StripItems(&players[playernum]);
}
// Reset away view (some code referenced from P_SpectatorJoinGame)
{
UINT8 i = 0;
INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers);
for (i = 0; i <= r_splitscreen; i++)
{
if (localplayertable[i] == playernum)
{
LUA_HookViewpointSwitch(players+playernum, players+playernum, true);
displayplayers[i] = playernum;
break;
}
}
}
// Reset away view
G_ResetViews();
K_CheckBumpers(); // SRB2Kart
P_CheckRacers(); // also SRB2Kart

View file

@ -128,8 +128,6 @@ extern consvar_t cv_sleep;
extern consvar_t cv_perfstats;
extern consvar_t cv_director;
extern consvar_t cv_schedule;
extern consvar_t cv_livestudioaudience;

View file

@ -71,6 +71,7 @@ struct ticcmd_t
{
SINT8 forwardmove; // -MAXPLMOVE to MAXPLMOVE (50)
INT16 turning; // Turn speed
INT16 angle; // Predicted angle, use me if you can!
INT16 throwdir; // Aiming direction
INT16 aiming; // vertical aiming, see G_BuildTicCmd
UINT16 buttons;

View file

@ -131,6 +131,7 @@ extern char logfilename[1024];
//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
#ifdef DEVELOP
#define PARANOIA // On by default for DEVELOP builds
#define VERSIONSTRING "Development EXE"
#define VERSIONSTRING_RC "Development EXE" "\0"
// most interface strings are ignored in development mode.

View file

@ -136,15 +136,16 @@ demoghost *ghosts = NULL;
#define DEMO_BOT 0x08
// For demos
#define ZT_FWD 0x01
#define ZT_SIDE 0x02
#define ZT_TURNING 0x04
#define ZT_THROWDIR 0x08
#define ZT_BUTTONS 0x10
#define ZT_AIMING 0x20
#define ZT_LATENCY 0x40
#define ZT_FLAGS 0x80
// OUT OF ZIPTICS...
#define ZT_FWD 0x0001
#define ZT_SIDE 0x0002
#define ZT_TURNING 0x0004
#define ZT_ANGLE 0x0008
#define ZT_THROWDIR 0x0010
#define ZT_BUTTONS 0x0020
#define ZT_AIMING 0x0040
#define ZT_LATENCY 0x0080
#define ZT_FLAGS 0x0100
// Ziptics are UINT16 now, go nuts
#define DEMOMARKER 0x80 // demobuf.end
@ -530,17 +531,19 @@ void G_WriteDemoExtraData(void)
void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
{
UINT8 ziptic;
UINT16 ziptic;
if (!demobuf.p || !demo.deferstart)
return;
ziptic = READUINT8(demobuf.p);
ziptic = READUINT16(demobuf.p);
if (ziptic & ZT_FWD)
oldcmd[playernum].forwardmove = READSINT8(demobuf.p);
if (ziptic & ZT_TURNING)
oldcmd[playernum].turning = READINT16(demobuf.p);
if (ziptic & ZT_ANGLE)
oldcmd[playernum].angle = READINT16(demobuf.p);
if (ziptic & ZT_THROWDIR)
oldcmd[playernum].throwdir = READINT16(demobuf.p);
if (ziptic & ZT_BUTTONS)
@ -564,13 +567,14 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
{
char ziptic = 0;
UINT16 ziptic = 0;
UINT8 *ziptic_p;
(void)playernum;
if (!demobuf.p)
return;
ziptic_p = demobuf.p++; // the ziptic, written at the end of this function
ziptic_p = demobuf.p; // the ziptic, written at the end of this function
demobuf.p += 2;
if (cmd->forwardmove != oldcmd[playernum].forwardmove)
{
@ -586,6 +590,13 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
ziptic |= ZT_TURNING;
}
if (cmd->angle != oldcmd[playernum].angle)
{
WRITEINT16(demobuf.p,cmd->angle);
oldcmd[playernum].angle = cmd->angle;
ziptic |= ZT_ANGLE;
}
if (cmd->throwdir != oldcmd[playernum].throwdir)
{
WRITEINT16(demobuf.p,cmd->throwdir);
@ -621,7 +632,7 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
ziptic |= ZT_FLAGS;
}
*ziptic_p = ziptic;
WRITEUINT16(ziptic_p, ziptic);
// attention here for the ticcmd size!
// latest demos with mouse aiming byte in ticcmd
@ -1173,7 +1184,7 @@ void G_GhostTicker(void)
for(g = ghosts, p = NULL; g; g = g->next)
{
// Skip normal demo data.
UINT8 ziptic = READUINT8(g->p);
UINT16 ziptic = READUINT8(g->p);
UINT8 xziptic = 0;
while (ziptic != DW_END) // Get rid of extradata stuff
@ -1214,12 +1225,14 @@ void G_GhostTicker(void)
ziptic = READUINT8(g->p);
}
ziptic = READUINT8(g->p);
ziptic = READUINT16(g->p);
if (ziptic & ZT_FWD)
g->p++;
if (ziptic & ZT_TURNING)
g->p += 2;
if (ziptic & ZT_ANGLE)
g->p += 2;
if (ziptic & ZT_THROWDIR)
g->p += 2;
if (ziptic & ZT_BUTTONS)

View file

@ -61,6 +61,7 @@
#include "k_specialstage.h"
#include "k_bot.h"
#include "doomstat.h"
#include "k_director.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
@ -1080,80 +1081,32 @@ INT32 localaiming[MAXSPLITSCREENPLAYERS];
angle_t localangle[MAXSPLITSCREENPLAYERS];
INT32 localsteering[MAXSPLITSCREENPLAYERS];
INT32 localdelta[MAXSPLITSCREENPLAYERS];
INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
UINT8 locallatency[MAXSPLITSCREENPLAYERS][TICRATE];
UINT8 localtic;
void G_ResetAnglePrediction(player_t *player)
{
UINT16 i, j;
for (i = 0; i <= r_splitscreen; i++)
{
if (&players[displayplayers[i]] == player)
{
localdelta[i] = 0;
for (j = 0; j < TICCMD_LATENCYMASK; j++)
{
localstoredeltas[i][j] = 0;
}
break;
}
}
}
// Turning was removed from G_BuildTiccmd to prevent easy client hacking.
// This brings back the camera prediction that was lost.
static void G_DoAnglePrediction(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer, player_t *player)
{
angle_t angleChange = 0;
angle_t destAngle = player->angleturn;
angle_t diff = 0;
localtic = cmd->latency;
if (player->pflags & PF_DRIFTEND)
while (realtics > 0)
{
// Otherwise, your angle slingshots off to the side violently...
G_ResetAnglePrediction(player);
localsteering[ssplayer - 1] = K_UpdateSteeringValue(localsteering[ssplayer - 1], cmd->turning);
angleChange = K_GetKartTurnValue(player, localsteering[ssplayer - 1]) << TICCMD_REDUCE;
realtics--;
}
#if 0
// Left here in case it needs unsealing later. This tried to replicate an old localcam function, but this behavior was unpopular in tests.
//if (player->pflags & PF_DRIFTEND)
{
localangle[ssplayer - 1] = player->mo->angle;
}
else
#endif
{
while (realtics > 0)
{
localsteering[ssplayer - 1] = K_UpdateSteeringValue(localsteering[ssplayer - 1], cmd->turning);
angleChange = K_GetKartTurnValue(player, localsteering[ssplayer - 1]) << TICCMD_REDUCE;
// Store the angle we applied to this tic, so we can revert it later.
// If we trust the camera to do all of the work, then it can get out of sync fast.
localstoredeltas[ssplayer - 1][cmd->latency] += angleChange;
localdelta[ssplayer - 1] += angleChange;
realtics--;
}
localangle[ssplayer - 1] += angleChange;
}
// We COULD set it to destAngle directly...
// but this causes incredible jittering when the prediction turns out to be wrong. So we ease into it.
// Slight increased camera lag in all scenarios > Mostly lagless camera but with jittering
destAngle = player->angleturn + localdelta[ssplayer - 1];
diff = destAngle - localangle[ssplayer - 1];
if (diff > ANGLE_180)
{
diff = InvAngle(InvAngle(diff) / 2);
}
else
{
diff /= 2;
}
localangle[ssplayer - 1] += diff;
// In case of angle debugging, break glass
// localangle[ssplayer - 1] = destAngle;
}
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
@ -1189,6 +1142,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
break;
}
cmd->angle = localangle[forplayer] >> TICCMD_REDUCE;
// why build a ticcmd if we're paused?
// Or, for that matter, if we're being reborn.
if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN))
@ -1210,6 +1165,28 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
goto aftercmdinput;
}
if (displayplayers[forplayer] != g_localplayers[forplayer])
{
if (M_MenuButtonPressed(forplayer, MBT_A))
{
G_AdjustView(ssplayer, 1, true);
K_ToggleDirector(false);
}
if (M_MenuButtonPressed(forplayer, MBT_X))
{
G_AdjustView(ssplayer, -1, true);
K_ToggleDirector(false);
}
if (M_MenuButtonPressed(forplayer, MBT_R))
{
K_ToggleDirector(true);
}
goto aftercmdinput;
}
if (K_PlayerUsesBotMovement(player))
{
// Bot ticcmd is generated by K_BuildBotTiccmd
@ -1398,16 +1375,6 @@ aftercmdinput:
cmd->throwdir = -KART_FULLTURN;
G_DoAnglePrediction(cmd, realtics, ssplayer, player);
// Reset away view if a command is given.
if ((cmd->forwardmove || cmd->buttons)
&& !r_splitscreen && displayplayers[0] != consoleplayer && ssplayer == 1)
{
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUA_HookViewpointSwitch(player, &players[consoleplayer], true);
displayplayers[0] = consoleplayer;
}
}
ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
@ -1422,6 +1389,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
{
dest[i].forwardmove = src[i].forwardmove;
dest[i].turning = (INT16)SHORT(src[i].turning);
dest[i].angle = (INT16)SHORT(src[i].angle);
dest[i].throwdir = (INT16)SHORT(src[i].throwdir);
dest[i].aiming = (INT16)SHORT(src[i].aiming);
dest[i].buttons = (UINT16)SHORT(src[i].buttons);
@ -1740,44 +1708,8 @@ boolean G_Responder(event_t *ev)
return true; // chat ate the event
}
// allow spy mode changes even during the demo
if (gamestate == GS_LEVEL && ev->type == ev_keydown
&& (ev->data1 == KEY_F12 /*|| ev->data1 == gamecontrol[0][gc_viewpoint][0] || ev->data1 == gamecontrol[0][gc_viewpoint][1]*/))
{
if (!demo.playback && (r_splitscreen || !netgame))
g_localplayers[0] = consoleplayer;
else
{
G_AdjustView(1, 1, true);
// change statusbar also if playing back demo
if (demo.quitafterplaying)
ST_changeDemoView();
return true;
}
}
if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demo.playback && !demo.freecam)
{
/*
if (ev->data1 == gamecontrol[1][gc_viewpoint][0] || ev->data1 == gamecontrol[1][gc_viewpoint][1])
{
G_AdjustView(2, 1, true);
return true;
}
else if (ev->data1 == gamecontrol[2][gc_viewpoint][0] || ev->data1 == gamecontrol[2][gc_viewpoint][1])
{
G_AdjustView(3, 1, true);
return true;
}
else if (ev->data1 == gamecontrol[3][gc_viewpoint][0] || ev->data1 == gamecontrol[3][gc_viewpoint][1])
{
G_AdjustView(4, 1, true);
return true;
}
*/
// Allow pausing
if (
//ev->data1 == gamecontrol[0][gc_pause][0]
@ -1964,7 +1896,7 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive)
INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive, boolean reverse)
{
INT32 i, dir = reverse ? -1 : 1;
startview = min(max(startview, 0), MAXPLAYERS);
startview = min(max(startview, -1), MAXPLAYERS);
for (i = startview; i < MAXPLAYERS && i >= 0; i += dir)
{
if (G_CanView(i, viewnum, onlyactive))
@ -2035,7 +1967,14 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
/* Check if anyone is available to view. */
if (( playernum = G_FindView(playernum, viewnum, onlyactive, playernum < olddisplayplayer) ) == -1)
return;
{
/* Fall back on true self */
playernum = g_localplayers[viewnum-1];
}
// Call ViewpointSwitch hooks here.
// The viewpoint was forcibly changed.
LUA_HookViewpointSwitch(&players[g_localplayers[viewnum - 1]], &players[playernum], true);
/* Focus our target view first so that we don't take its player. */
(*displayplayerp) = playernum;
@ -2043,6 +1982,10 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
{
camerap = &camera[viewnum-1];
P_ResetCamera(&players[(*displayplayerp)], camerap);
// Why does it need to be done twice?
R_ResetViewInterpolation(viewnum);
R_ResetViewInterpolation(viewnum);
}
if (viewnum > splits)
@ -2060,6 +2003,10 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
if (viewnum == 1 && demo.playback)
consoleplayer = displayplayers[0];
// change statusbar also if playing back demo
if (demo.quitafterplaying)
ST_changeDemoView();
}
//
@ -2097,8 +2044,8 @@ void G_ResetViews(void)
/* Demote splits */
if (playersviewable < splits)
{
splits = playersviewable;
r_splitscreen = max(splits-1, 0);
splits = max(playersviewable, splitscreen + 1); // don't delete local players
r_splitscreen = splits - 1;
R_ExecuteSetViewSize();
}

View file

@ -101,7 +101,6 @@ extern consvar_t cv_resume;
const char *G_BuildMapName(INT32 map);
INT32 G_MapNumber(const char *mapname);
void G_ResetAnglePrediction(player_t *player);
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer);
// copy ticcmd_t to and fro the normal way
@ -116,10 +115,6 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming);
extern angle_t localangle[MAXSPLITSCREENPLAYERS];
extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed
extern INT32 localsteering[MAXSPLITSCREENPLAYERS];
extern INT32 localdelta[MAXSPLITSCREENPLAYERS];
extern INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
extern UINT8 locallatency[MAXSPLITSCREENPLAYERS][TICRATE];
extern UINT8 localtic;
INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers);
boolean G_PlayerInputDown(UINT8 p, INT32 gc, UINT8 menuPlayers);

View file

@ -25,6 +25,7 @@ void K_InitDirector(void)
{
INT32 playernum;
directorinfo.active = false;
directorinfo.cooldown = SWITCHTIME;
directorinfo.freeze = 0;
directorinfo.attacker = 0;
@ -109,6 +110,11 @@ static boolean K_CanSwitchDirector(void)
return false;
}
if (!directorinfo.active)
{
return false;
}
return true;
}
@ -218,11 +224,6 @@ void K_UpdateDirector(void)
INT32 *displayplayerp = &displayplayers[0];
INT32 targetposition;
if (!cv_director.value)
{
return;
}
K_UpdateDirectorPositions();
if (directorinfo.cooldown > 0) {
@ -238,6 +239,13 @@ void K_UpdateDirector(void)
return;
}
// if there's only one player left in the list, just switch to that player
if (directorinfo.sortedplayers[0] != -1 && directorinfo.sortedplayers[1] == -1)
{
K_DirectorSwitch(directorinfo.sortedplayers[0], false);
return;
}
// aaight, time to walk through the standings to find the first interesting pair
// NB: targetposition/sortedplayers is 0-indexed, aiming at the "back half" of a given pair by default.
// we adjust for this when comparing to player->position or when looking at the leading player, Don't Freak Out
@ -277,18 +285,40 @@ void K_UpdateDirector(void)
target = directorinfo.sortedplayers[targetposition];
// stop here since we're already viewing this player
if (*displayplayerp == target)
{
break;
}
// if this is a splitscreen player, try next pair
if (P_IsDisplayPlayer(&players[target]))
{
continue;
}
// if we're certain the back half of the pair is actually in this position, try to switch
if (*displayplayerp != target && !players[target].positiondelay)
if (!players[target].positiondelay)
{
K_DirectorSwitch(target, false);
}
// even if we're not certain, if we're certain we're watching the WRONG player, try to switch
if (players[*displayplayerp].position != targetposition+1 && !players[target].positiondelay)
if (players[*displayplayerp].position != targetposition+1 && !players[*displayplayerp].positiondelay)
{
K_DirectorSwitch(target, false);
}
break;
}
}
}
void K_ToggleDirector(boolean active)
{
if (directorinfo.active != active)
{
directorinfo.cooldown = 0; // switch immediately
}
directorinfo.active = active;
}

View file

@ -12,6 +12,7 @@ extern "C" {
extern struct directorinfo
{
boolean active; // is view point switching enabled?
tic_t cooldown; // how long has it been since we last switched?
tic_t freeze; // when nonzero, fixed switch pending, freeze logic!
INT32 attacker; // who to switch to when freeze delay elapses
@ -26,6 +27,7 @@ void K_InitDirector(void);
void K_UpdateDirector(void);
void K_DrawDirectorDebugger(void);
void K_DirectorFollowAttack(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_ToggleDirector(boolean active);
#ifdef __cplusplus
} // extern "C"

View file

@ -4639,6 +4639,33 @@ K_drawMiniPing (void)
}
}
static void K_DrawDirectorButton(INT32 idx, const char *label, patch_t *kp[2])
{
const INT32 flags = V_SNAPTORIGHT | V_SLIDEIN;
const INT32 textflags = flags | V_6WIDTHSPACE | V_ALLOWLOWERCASE;
const UINT8 anim_duration = 16;
const UINT8 anim = (leveltime % (anim_duration * 2)) < anim_duration;
const INT32 x = BASEVIDWIDTH - 60;
const INT32 y = BASEVIDHEIGHT - 70 + (idx * 16);
V_DrawScaledPatch(x, y - 4, flags, kp[anim]);
V_DrawRightAlignedThinString(x - 2, y, textflags, label);
}
static void K_drawDirectorHUD(void)
{
if (!LUA_HudEnabled(hud_textspectator))
{
return;
}
K_DrawDirectorButton(0, "Next Player", kp_button_a[0]);
K_DrawDirectorButton(1, "Prev Player", kp_button_x[0]);
K_DrawDirectorButton(2, "Director", kp_button_r);
}
static void K_drawDistributionDebugger(void)
{
itemroulette_t rouletteData = {0};
@ -4957,6 +4984,11 @@ void K_drawKartHUD(void)
K_drawMiniPing();
}
if (displayplayers[viewnum] != g_localplayers[viewnum])
{
K_drawDirectorHUD();
}
if (cv_kartdebugdistribution.value)
K_drawDistributionDebugger();

View file

@ -7748,12 +7748,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
}
if (player->invincibilitytimer)
if (player->invincibilitytimer && onground == true)
player->invincibilitytimer--;
if ((player->respawn.state == RESPAWNST_NONE) && player->growshrinktimer != 0)
{
if (player->growshrinktimer > 0)
if (player->growshrinktimer > 0 && onground == true)
player->growshrinktimer--;
if (player->growshrinktimer < 0)
player->growshrinktimer++;
@ -7810,7 +7810,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->stealingtimer == 0
&& player->rocketsneakertimer)
&& player->rocketsneakertimer
&& onground == true)
player->rocketsneakertimer--;
if (player->hyudorotimer)
@ -9728,6 +9729,7 @@ static void K_KartSpindash(player_t *player)
player->spindash = 0;
S_ReducedVFXSound(player->mo, sfx_s23c, player);
S_StopSoundByID(player->mo, sfx_kc38);
}
@ -9779,11 +9781,15 @@ static void K_KartSpindash(player_t *player)
UINT8 ringdropframes = 2 + (player->kartspeed + player->kartweight);
boolean spawnOldEffect = true;
if (player->rings <= 0) // Use the damn spindash
player->spindash++; // I am no longer asking
INT16 chargetime = MAXCHARGETIME - ++player->spindash;
if (player->rings <= 0 && chargetime >= 0) // Desperation spindash
{
player->spindash++;
if (!S_SoundPlaying(player->mo, sfx_kc38))
S_StartSound(player->mo, sfx_kc38);
}
if (player->spindash >= SPINDASHTHRUSTTIME)
{
K_KartSpindashDust(player->mo);
@ -10504,40 +10510,43 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
{
if (player->growshrinktimer < 0)
{
// If you're shrunk, then "grow" will just make you normal again.
// Old v1 behavior was to have Grow counter Shrink,
// but Shrink is now so ephemeral that it should just work.
K_RemoveGrowShrink(player);
// So we fall through here.
}
else
K_PlayPowerGloatSound(player->mo);
player->mo->scalespeed = mapobjectscale/TICRATE;
player->mo->destscale = FixedMul(mapobjectscale, GROW_SCALE);
if (K_PlayerShrinkCheat(player) == true)
{
K_PlayPowerGloatSound(player->mo);
player->mo->scalespeed = mapobjectscale/TICRATE;
player->mo->destscale = FixedMul(mapobjectscale, GROW_SCALE);
if (K_PlayerShrinkCheat(player) == true)
{
player->mo->destscale = FixedMul(player->mo->destscale, SHRINK_SCALE);
}
player->growshrinktimer = max(player->growshrinktimer, ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE);
if (player->invincibilitytimer > 0)
{
; // invincibility has priority in P_RestoreMusic, no point in starting here
}
else if (P_IsLocalPlayer(player) == true)
{
S_ChangeMusicSpecial("kgrow");
}
else //used to be "if (P_IsDisplayPlayer(player) == false)"
{
S_StartSound(player->mo, sfx_alarmg);
}
P_RestoreMusic(player);
S_StartSound(player->mo, sfx_kc5a);
player->mo->destscale = FixedMul(player->mo->destscale, SHRINK_SCALE);
}
if (player->invincibilitytimer > 0)
{
; // invincibility has priority in P_RestoreMusic, no point in starting here
}
else if (P_IsLocalPlayer(player) == true)
{
if (player->growshrinktimer < 1)
S_ChangeMusicSpecial("kgrow");
}
else //used to be "if (P_IsDisplayPlayer(player) == false)"
{
S_StartSound(player->mo, sfx_alarmg);
}
P_RestoreMusic(player);
player->growshrinktimer = max(0, player->growshrinktimer);
player->growshrinktimer += ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE;
S_StartSound(player->mo, sfx_kc5a);
player->itemamount--;
}
break;

View file

@ -650,6 +650,7 @@ struct setup_player_t
UINT16 color;
UINT8 mdepth;
boolean hitlag;
boolean showextra;
// Hack, save player 1's original device even if they init charsel with keyboard.
// If they play ALONE, allow them to retain that original device, otherwise, ignore this.
@ -1158,6 +1159,8 @@ extern struct challengesmenu_s {
boolean pending;
boolean requestnew;
boolean requestflip;
UINT8 unlockcount[CC_MAX];
UINT8 fade;

View file

@ -1363,16 +1363,19 @@ static void M_DrawCharSelectPreview(UINT8 num)
M_DrawCharSelectCircle(p, x+32, y+64);
}
V_DrawScaledPatch(x+9, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE));
V_DrawScaledPatch(x, y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE));
if (p->mdepth > CSSTEP_PROFILE)
if (p->showextra == false)
{
profile_t *pr = PR_GetProfile(p->profilen);
V_DrawCenteredFileString(x+16+18, y+2, 0, pr->profilename);
}
else
{
V_DrawFileString(x+16, y+2, 0, "PLAYER");
V_DrawScaledPatch(x+9, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE));
V_DrawScaledPatch(x, y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE));
if (p->mdepth > CSSTEP_PROFILE)
{
profile_t *pr = PR_GetProfile(p->profilen);
V_DrawCenteredFileString(x+16+18, y+2, 0, pr->profilename);
}
else
{
V_DrawFileString(x+16, y+2, 0, "PLAYER");
}
}
if (p->mdepth >= CSSTEP_FOLLOWER)
@ -1471,6 +1474,82 @@ static void M_DrawCharSelectPreview(UINT8 num)
V_DrawThinString(xpos+16, cy, (p->changeselect == i ? highlightflags : 0)|V_6WIDTHSPACE, choices[i]);
}
}
if (p->showextra == true)
{
switch (p->mdepth)
{
case CSSTEP_CHARS: // Character Select grid
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("Speed %u - Weight %u", p->gridx+1, p->gridy+1));
break;
case CSSTEP_ALTS: // Select clone
case CSSTEP_READY:
if (p->clonenum < setup_chargrid[p->gridx][p->gridy].numskins
&& setup_chargrid[p->gridx][p->gridy].skinlist[p->clonenum] < numskins)
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE,
skins[setup_chargrid[p->gridx][p->gridy].skinlist[p->clonenum]].name);
}
else
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("BAD CLONENUM %u", p->clonenum));
}
break;
case CSSTEP_COLORS: // Select color
if (p->color < numskincolors)
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, skincolors[p->color].name);
}
else
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("BAD COLOR %u", p->color));
}
break;
case CSSTEP_FOLLOWERCATEGORY:
if (p->followercategory == -1)
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "None");
}
else
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE,
followercategories[setup_followercategories[p->followercategory][1]].name);
}
break;
case CSSTEP_FOLLOWER:
if (p->followern == -1)
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "None");
}
else
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE,
followers[p->followern].name);
}
break;
case CSSTEP_FOLLOWERCOLORS:
if (p->followercolor == FOLLOWERCOLOR_MATCH)
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "Match");
}
else if (p->followercolor == FOLLOWERCOLOR_OPPOSITE)
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "Opposite");
}
else if (p->followercolor < numskincolors)
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, skincolors[p->followercolor].name);
}
else
{
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("BAD FOLLOWERCOLOR %u", p->followercolor));
}
break;
default:
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "[extrainfo mode]");
break;
}
}
}
static void M_DrawCharSelectExplosions(boolean charsel, INT16 basex, INT16 basey)

View file

@ -175,6 +175,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
if (challengesmenu.pending || desiredmenu == NULL)
{
challengesmenu.ticker = 0;
challengesmenu.requestflip = false;
challengesmenu.requestnew = false;
challengesmenu.currentunlock = MAXUNLOCKABLES;
challengesmenu.unlockcondition = NULL;
@ -287,7 +288,7 @@ void M_ChallengesTick(void)
if (challengesmenu.extradata != NULL)
{
UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
boolean seeeveryone = M_MenuButtonHeld(pid, MBT_R);
boolean seeeveryone = challengesmenu.requestflip;
boolean allthewaythrough;
UINT8 maxflip;
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
@ -479,8 +480,17 @@ boolean M_ChallengesInputs(INT32 ch)
return true;
}
if (M_MenuButtonPressed(pid, MBT_R))
{
challengesmenu.requestflip ^= true;
return true;
}
if (challengesmenu.extradata != NULL && move)
{
challengesmenu.requestflip = false;
// Determine movement around the grid
// For right/down movement, we can pre-determine the number of steps based on extradata.
// For left/up movement, we can't - we have to be ready to iterate twice, and break early if we don't run into a large tile.

View file

@ -7,7 +7,7 @@
menuitem_t OPTIONS_Data[] =
{
{IT_STRING | IT_SUBMENU, "Screenshot Options...", "Set options relative to screenshot and GIF capture.",
{IT_STRING | IT_SUBMENU, "Media Options...", "Set options relative to screenshot and movie capture.",
NULL, {.submenu = &OPTIONS_DataScreenshotDef}, 0, 0},
{IT_STRING | IT_SUBMENU, "Addon Options...", "Set options relative to the addons menu.",

View file

@ -8,7 +8,7 @@ menuitem_t OPTIONS_DataReplay[] =
{IT_STRING | IT_CVAR, "Record Replays", "Select when to save replays.",
NULL, {.cvar = &cv_recordmultiplayerdemos}, 0, 0},
{IT_STRING | IT_CVAR, "Synch. Check Interval", "How often to check for synchronization while playing back a replay.",
{IT_STRING | IT_CVAR, "Net Consistency Quality", "For filesize, how often do we write position data in online replays?",
NULL, {.cvar = &cv_netdemosyncquality}, 0, 0},
};

View file

@ -3,6 +3,7 @@
#include "../k_menu.h"
#include "../m_misc.h" // screenshot cvars
#include "../m_avrecorder.h"
menuitem_t OPTIONS_DataScreenshot[] =
{
@ -19,13 +20,19 @@ menuitem_t OPTIONS_DataScreenshot[] =
{IT_SPACE | IT_NOTHING, NULL, NULL,
NULL, {NULL}, 0, 0},
{IT_HEADER, "GIF RECORDING (F9)", NULL,
{IT_HEADER, "MOVIE RECORDING (F9)", NULL,
NULL, {NULL}, 0, 0},
{IT_STRING | IT_CVAR, "Storage Location", "Sets where to store GIFs",
{IT_STRING | IT_CVAR, "Recording Format", "What file format will movies will be recorded in?",
NULL, {.cvar = &cv_moviemode}, 0, 0},
{IT_STRING | IT_CVAR, "Real-Time Data", "If enabled, shows fps, duration and filesize of recording in real-time.",
NULL, {.cvar = &cv_movie_showfps}, 0, 0},
{IT_STRING | IT_CVAR, "Storage Location", "Sets where to store movies.",
NULL, {.cvar = &cv_movie_option}, 0, 0},
{IT_STRING | IT_CVAR | IT_CV_STRING, "Custom Folder", "Specify which folder to save GIFs in.",
{IT_STRING | IT_CVAR | IT_CV_STRING, "Custom Folder", "Specify which folder to save videos in.",
NULL, {.cvar = &cv_movie_folder}, 24, 0},
};
@ -56,6 +63,10 @@ void Screenshot_option_Onchange(void)
void Moviemode_mode_Onchange(void)
{
// opt 7 in a 0 based array, you get the idea...
OPTIONS_DataScreenshot[6].status =
(cv_moviemode.value == MM_AVRECORDER ? IT_CVAR|IT_STRING : IT_DISABLED);
#if 0
INT32 i, cstart, cend;
for (i = op_screenshot_gif_start; i <= op_screenshot_apng_end; ++i)
@ -81,7 +92,7 @@ void Moviemode_mode_Onchange(void)
void Moviemode_option_Onchange(void)
{
// opt 7 in a 0 based array, you get the idea...
OPTIONS_DataScreenshot[6].status =
// opt 9 in a 0 based array, you get the idea...
OPTIONS_DataScreenshot[8].status =
(cv_movie_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED);
}

View file

@ -7,44 +7,45 @@
menuitem_t OPTIONS_GameplayItems[] =
{
// Mostly handled by the drawing function.
{IT_KEYHANDLER | IT_NOTHING, NULL, "Super Rings", NULL, {.routine = M_HandleItemToggles}, KITEM_SUPERRING, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Self-Propelled Bombs", NULL, {.routine = M_HandleItemToggles}, KITEM_SPB, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Eggman Marks", NULL, {.routine = M_HandleItemToggles}, KITEM_EGGMAN, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Super Ring", NULL, {.routine = M_HandleItemToggles}, KITEM_SUPERRING, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Self-Propelled Bomb", NULL, {.routine = M_HandleItemToggles}, KITEM_SPB, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0}, // maybe KITEM_PUYO eventually?
{IT_KEYHANDLER | IT_NOTHING, NULL, "Toggle All", NULL, {.routine = M_HandleItemToggles}, 0, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers", NULL, {.routine = M_HandleItemToggles}, KITEM_SNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers x2", NULL, {.routine = M_HandleItemToggles}, KRITEM_DUALSNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLESNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Rocket Sneakers", NULL, {.routine = M_HandleItemToggles}, KITEM_ROCKETSNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneaker", NULL, {.routine = M_HandleItemToggles}, KITEM_SNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneaker x2", NULL, {.routine = M_HandleItemToggles}, KRITEM_DUALSNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneaker x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLESNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Rocket Sneaker", NULL, {.routine = M_HandleItemToggles}, KITEM_ROCKETSNEAKER, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas", NULL, {.routine = M_HandleItemToggles}, KITEM_BANANA, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEBANANA, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Proximity Mines", NULL, {.routine = M_HandleItemToggles}, KITEM_MINE, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Banana", NULL, {.routine = M_HandleItemToggles}, KITEM_BANANA, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Banana x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEBANANA, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Eggman Mark", NULL, {.routine = M_HandleItemToggles}, KITEM_EGGMAN, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Gachabom", NULL, {.routine = M_HandleItemToggles}, KITEM_GACHABOM, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts", NULL, {.routine = M_HandleItemToggles}, KITEM_ORBINAUT, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEORBINAUT, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts x4", NULL, {.routine = M_HandleItemToggles}, KRITEM_QUADORBINAUT, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Land Mines", NULL, {.routine = M_HandleItemToggles}, KITEM_LANDMINE, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinaut", NULL, {.routine = M_HandleItemToggles}, KITEM_ORBINAUT, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinaut x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEORBINAUT, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinaut x4", NULL, {.routine = M_HandleItemToggles}, KRITEM_QUADORBINAUT, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Gachabom x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEGACHABOM, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Jawz", NULL, {.routine = M_HandleItemToggles}, KITEM_JAWZ, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Jawz x2", NULL, {.routine = M_HandleItemToggles}, KRITEM_DUALJAWZ, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Ballhogs", NULL, {.routine = M_HandleItemToggles}, KITEM_BALLHOG, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Drop Targets", NULL, {.routine = M_HandleItemToggles}, KITEM_DROPTARGET, sfx_s258},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Proximity Mine", NULL, {.routine = M_HandleItemToggles}, KITEM_MINE, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Ballhog", NULL, {.routine = M_HandleItemToggles}, KITEM_BALLHOG, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Lightning Shields", NULL, {.routine = M_HandleItemToggles}, KITEM_LIGHTNINGSHIELD, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bubble Shields", NULL, {.routine = M_HandleItemToggles}, KITEM_BUBBLESHIELD, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Flame Shields", NULL, {.routine = M_HandleItemToggles}, KITEM_FLAMESHIELD, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Hyudoros", NULL, {.routine = M_HandleItemToggles}, KITEM_HYUDORO, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Hyudoro", NULL, {.routine = M_HandleItemToggles}, KITEM_HYUDORO, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Drop Target", NULL, {.routine = M_HandleItemToggles}, KITEM_DROPTARGET, sfx_s258},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Land Mine", NULL, {.routine = M_HandleItemToggles}, KITEM_LANDMINE, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Pogo Spring", NULL, {.routine = M_HandleItemToggles}, KITEM_POGOSPRING, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Invinciblity", NULL, {.routine = M_HandleItemToggles}, KITEM_INVINCIBILITY, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Grow", NULL, {.routine = M_HandleItemToggles}, KITEM_GROW, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Shrink", NULL, {.routine = M_HandleItemToggles}, KITEM_SHRINK, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Gardentop", NULL, {.routine = M_HandleItemToggles}, KITEM_GARDENTOP, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Pogo Springs", NULL, {.routine = M_HandleItemToggles}, KITEM_POGOSPRING, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Kitchen Sinks", NULL, {.routine = M_HandleItemToggles}, KITEM_KITCHENSINK, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0}
{IT_KEYHANDLER | IT_NOTHING, NULL, "Lightning Shield", NULL, {.routine = M_HandleItemToggles}, KITEM_LIGHTNINGSHIELD, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bubble Shield", NULL, {.routine = M_HandleItemToggles}, KITEM_BUBBLESHIELD, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Flame Shield", NULL, {.routine = M_HandleItemToggles}, KITEM_FLAMESHIELD, 0},
{IT_KEYHANDLER | IT_NOTHING, NULL, "Kitchen Sink", NULL, {.routine = M_HandleItemToggles}, KITEM_KITCHENSINK, 0}
};
menu_t OPTIONS_GameplayItemsDef = {

View file

@ -905,16 +905,6 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num)
if (num == 0 && setup_numplayers == 1 && setup_maxpage && !forceskin) // ONLY one player.
{
if (M_MenuButtonPressed(num, MBT_L))
{
if (setup_page == 0)
setup_page = setup_maxpage;
else
setup_page--;
S_StartSound(NULL, sfx_s3k63);
M_SetMenuDelay(num);
}
else if (M_MenuButtonPressed(num, MBT_R))
{
if (setup_page == setup_maxpage)
setup_page = 0;
@ -1295,6 +1285,11 @@ boolean M_CharacterSelectHandler(INT32 choice)
if (i > 0 && setup_player[i-1].mdepth < CSSTEP_READY)
continue;
}
if (M_MenuButtonPressed(i, MBT_R))
{
p->showextra ^= true;
}
}
switch (p->mdepth)

View file

@ -59,7 +59,7 @@ void M_SetupGametypeMenu(INT32 choice)
if (!anyunlocked)
{
// Only one non-Back entry, let's skip straight to Race.
M_SetupRaceMenu(-1);
M_SetupRaceMenu(0);
return;
}
}

View file

@ -602,6 +602,12 @@ Obj_MonitorGetDamage
damage = HEALTHFACTOR +
(FixedMul(weight, HEALTHFACTOR) / 9);
if (inflictor->player->tiregrease > 0)
{
damage *= 3; // Do 3x the damage if the player is in spring grease state
}
if (inflictor->scale > mapobjectscale)
{
damage = P_ScaleFromMap(damage, inflictor->scale);

View file

@ -542,50 +542,51 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim)
// Take away Shrink.
K_RemoveGrowShrink(victim->player);
}
else
victim->player->growshrinktimer += 3*TICRATE;
S_StartSound(victim, sfx_kc5a);
if (prevTimer <= 0)
{
victim->player->growshrinktimer += 3*TICRATE;
S_StartSound(victim, sfx_kc5a);
victim->scalespeed = mapobjectscale/TICRATE;
victim->destscale = FixedMul(mapobjectscale, GROW_SCALE);
if (prevTimer <= 0)
if (K_PlayerShrinkCheat(victim->player) == true)
{
victim->scalespeed = mapobjectscale/TICRATE;
victim->destscale = FixedMul(mapobjectscale, GROW_SCALE);
if (K_PlayerShrinkCheat(victim->player) == true)
{
victim->destscale = FixedMul(victim->destscale, SHRINK_SCALE);
}
if (victim->player->invincibilitytimer > 0)
{
; // invincibility has priority in P_RestoreMusic, no point in starting here
}
else if (P_IsLocalPlayer(victim->player) == true)
{
S_ChangeMusicSpecial("kgrow");
}
else //used to be "if (P_IsDisplayPlayer(victim->player) == false)"
{
S_StartSound(victim, sfx_alarmg);
}
P_RestoreMusic(victim->player);
victim->destscale = FixedMul(victim->destscale, SHRINK_SCALE);
}
if (victim->player->invincibilitytimer > 0)
{
; // invincibility has priority in P_RestoreMusic, no point in starting here
}
else if (P_IsLocalPlayer(victim->player) == true)
{
S_ChangeMusicSpecial("kgrow");
}
else //used to be "if (P_IsDisplayPlayer(victim->player) == false)"
{
S_StartSound(victim, sfx_alarmg);
}
P_RestoreMusic(victim->player);
}
}
else
{
if (prevTimer > 0)
{
// Take away Grow.
K_RemoveGrowShrink(victim->player);
// Dock some Grow time.
// (Hack-adjacent: Always make sure there's a tic left so standard timer handling can remove the effect properly.)
victim->player->growshrinktimer -= min(3*TICRATE/2, victim->player->growshrinktimer - 1);
S_StartSound(victim, sfx_s3k40);
}
else
{
// Start shrinking!
victim->player->growshrinktimer -= 5*TICRATE;
S_StartSound(victim, sfx_kc59);
S_StartSound(victim, sfx_kc59); // I don't think you ever get to hear this while the pohbee laser is in your teeth, but best effort.
if (prevTimer >= 0)
{

View file

@ -23,6 +23,7 @@
#include "../z_zone.h"
#include "../k_waypoint.h"
#include "../k_specialstage.h"
#include "../r_skins.h"
#define UFO_BASE_SPEED (42 * FRACUNIT) // UFO's slowest speed.
#define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration
@ -671,6 +672,16 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN
return false;
}
if (source->player)
{
UINT32 skinflags = (demo.playback)
? demo.skinlist[demo.currentskinid[(source->player-players)]].flags
: skins[source->player->skin].flags;
if (skinflags & SF_IRONMAN)
SetRandomFakePlayerSkin(source->player, true);
}
// Speed up on damage!
ufo_speed(ufo) += addSpeed;
@ -700,6 +711,7 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN
S_StopSoundByID(ufo, sfx_clawzm);
P_StartQuake(64<<FRACBITS, 10);
ufo->health -= damage;
return true;
}

View file

@ -46,6 +46,7 @@
#include "k_collide.h"
#include "k_objects.h"
#include "k_grandprix.h"
#include "k_director.h"
static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL);
@ -11827,6 +11828,22 @@ void P_SpawnPlayer(INT32 playernum)
K_SpawnPlayerBattleBumpers(p);
}
}
// I'm not refactoring the loop at the top of this file.
pcount = 0;
for (i = 0; i < MAXPLAYERS; ++i)
{
if (G_CouldView(i))
{
pcount++;
}
}
// Spectating when there is literally any other player in
// the level enables director cam.
// TODO: how do we support splitscreen?
K_ToggleDirector(players[consoleplayer].spectator && pcount > 0);
}
void P_AfterPlayerSpawn(INT32 playernum)

View file

@ -9100,15 +9100,17 @@ void T_Pusher(pusher_t *p)
thing->player->carry = CR_SLIDING;
thing->angle = R_PointToAngle2(0, 0, xspeed, yspeed);
if (!demo.playback)
{
angle_t angle = thing->player->angleturn;
angle_t angle = thing->player->boostangle;
if (thing->angle - angle > ANGLE_180)
P_SetPlayerAngle(thing->player, angle - (angle - thing->angle) / 8);
thing->player->boostangle = angle - (angle - thing->angle) / 8;
else
P_SetPlayerAngle(thing->player, angle + (thing->angle - angle) / 8);
thing->player->boostangle = angle + (thing->angle - angle) / 8;
//P_SetPlayerAngle(thing->player, thing->angle);
}
}
if (p->exclusive)

View file

@ -2120,7 +2120,6 @@ static void P_3dMovement(player_t *player)
static void P_UpdatePlayerAngle(player_t *player)
{
angle_t angleChange = ANGLE_MAX;
UINT8 maxlatency;
UINT8 p = UINT8_MAX;
UINT8 i;
@ -2133,8 +2132,58 @@ static void P_UpdatePlayerAngle(player_t *player)
}
}
player->steering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
angleChange = K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE;
// Don't apply steering just yet. If we make a correction, we'll need to adjust it.
INT16 targetsteering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
angleChange = K_GetKartTurnValue(player, targetsteering) << TICCMD_REDUCE;
if (!K_PlayerUsesBotMovement(player))
{
// With a full slam on the analog stick, how far could we steer in either direction?
INT16 steeringRight = K_UpdateSteeringValue(player->steering, KART_FULLTURN);
angle_t maxTurnRight = K_GetKartTurnValue(player, steeringRight) << TICCMD_REDUCE;
INT16 steeringLeft = K_UpdateSteeringValue(player->steering, -KART_FULLTURN);
angle_t maxTurnLeft = K_GetKartTurnValue(player, steeringLeft) << TICCMD_REDUCE;
// Grab local camera angle from ticcmd. Where do we actually want to go?
angle_t targetAngle = (player->cmd.angle) << TICCMD_REDUCE;
angle_t targetDelta = targetAngle - (player->mo->angle);
if (targetDelta == angleChange || player->pflags & PF_DRIFTEND || (maxTurnRight == 0 && maxTurnLeft == 0))
{
// We are where we need to be.
// ...Or we aren't, but shouldn't be able to steer.
player->steering = targetsteering;
// Alternatively, while in DRIFTEND we want to trust inputs for a bit, not camera.
// The game client doesn't know we're DRIFTEND until after a response gets back,
// so we momentarily ignore the camera angle and let the server trust our inputs instead.
// That way, even if you're steering blind, you get the intended "kick-out" effect.
}
else if (targetDelta >= ANGLE_180 && maxTurnLeft >= targetDelta) // Overshot, so just fudge it.
{
angleChange = targetDelta;
player->steering = targetsteering;
}
else if (targetDelta <= ANGLE_180 && maxTurnRight <= targetDelta) // Overshot, so just fudge it.
{
angleChange = targetDelta;
player->steering = targetsteering;
}
else if (targetDelta >= ANGLE_180 && maxTurnLeft < targetDelta) // Undershot, slam the stick.
{
angleChange = maxTurnLeft;
player->steering = steeringLeft;
}
else if (targetDelta <= ANGLE_180 && maxTurnRight > targetDelta) // Undershot, slam the stick.
{
angleChange = maxTurnRight;
player->steering = steeringRight;
}
}
else
{
// You're a bot. Go where you're supposed to go
player->steering = targetsteering;
}
if (p == UINT8_MAX)
{
@ -2144,33 +2193,8 @@ static void P_UpdatePlayerAngle(player_t *player)
}
else
{
// During standard play, our latency can vary by up to 1 tic in either direction, even on a stable connection.
// This probably comes from differences in ticcmd dispatch vs consumption rate. Probably.
// Uncorrected, this 2-tic "wobble" causes camera corrections to sometimes be skipped or batched.
// So just use the highest recent value for the furthest possible search.
// We unset the correction after applying, anyway.
locallatency[p][leveltime%TICRATE] = maxlatency = player->cmd.latency;
for (i = 0; i < TICRATE; i++)
{
maxlatency = max(locallatency[p][i], maxlatency);
}
UINT8 lateTic = ((leveltime - maxlatency) & TICCMD_LATENCYMASK);
UINT8 clearTic = ((localtic + 1) & TICCMD_LATENCYMASK);
player->angleturn += angleChange;
player->mo->angle = player->angleturn;
// Undo the ticcmd's old emulated angle,
// now that we added the actual game logic angle.
while (lateTic != clearTic)
{
localdelta[p] -= localstoredeltas[p][lateTic];
localstoredeltas[p][lateTic] = 0;
lateTic = (lateTic - 1) & TICCMD_LATENCYMASK;
}
}
if (!cv_allowmlook.value || player->spectator == false)
@ -3162,7 +3186,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (demo.playback)
{
focusangle = mo->angle;
// Hack-adjacent.
// Sometimes stale ticcmds send a weird angle at the start of the race.
// P_UpdatePlayerAngle knows to ignore cmd angle when you literally can't turn, so we do the same here.
if (leveltime > introtime)
focusangle = player->cmd.angle << TICCMD_REDUCE;
else
focusangle = mo->angle; // Just use something known sane.
focusaiming = 0;
}
else
@ -4478,7 +4508,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle)
if (player == &players[displayplayers[i]])
{
localangle[i] = angle;
G_ResetAnglePrediction(player);
break;
}
}

View file

@ -1095,6 +1095,8 @@ void ST_preLevelTitleCardDrawer(void)
//
static void ST_overlayDrawer(void)
{
const UINT8 viewnum = R_GetViewNumber();
// hu_showscores = auto hide score/time/rings when tab rankings are shown
if (!(hu_showscores && (netgame || multiplayer)))
{
@ -1135,7 +1137,7 @@ static void ST_overlayDrawer(void)
if (!hu_showscores && netgame && !mapreset)
{
if (stplyr->spectator && LUA_HudEnabled(hud_textspectator))
if (stplyr->spectator && displayplayers[viewnum] == g_localplayers[viewnum] && LUA_HudEnabled(hud_textspectator))
{
const char *itemtxt = M_GetText("Item - Join Game");