From c9291b0f61189b89ba0d74721cd8cabeb6b063ab Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 18 Sep 2023 03:24:58 -0400 Subject: [PATCH 01/53] Mobj thinker freeze condition rework - There's a freeze cheat bool to freeze everything except for players. - There's a level freeze bool to freeze literally everything. - There's a frozen bool on mobj_t to explicitly control freeze status on an object. --- src/d_netcmd.c | 8 +++++++ src/k_dialogue.h | 2 ++ src/k_dialogue.hpp | 1 + src/k_follower.c | 2 +- src/m_cheat.c | 8 +++++++ src/m_cheat.h | 2 ++ src/p_local.h | 2 ++ src/p_map.c | 2 +- src/p_mobj.c | 6 ++++- src/p_mobj.h | 2 ++ src/p_saveg.c | 18 ++++++++------- src/p_tick.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++ src/p_tick.h | 6 +++++ src/p_user.c | 6 ++--- 14 files changed, 108 insertions(+), 14 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 45076986f..163c91a78 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -534,6 +534,7 @@ void D_RegisterClientCommands(void) // add cheats COM_AddDebugCommand("noclip", Command_CheatNoClip_f); COM_AddDebugCommand("god", Command_CheatGod_f); + COM_AddDebugCommand("freeze", Command_CheatFreeze_f); COM_AddDebugCommand("setrings", Command_Setrings_f); COM_AddDebugCommand("setspheres", Command_Setspheres_f); COM_AddDebugCommand("setlives", Command_Setlives_f); @@ -5737,6 +5738,13 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum) break; } + case CHEAT_FREEZE: { + const char *status = P_FreezeCheat() ? "off" : "on"; + P_SetFreezeCheat( !P_FreezeCheat() ); + CV_CheaterWarning(targetPlayer, va("freeze %s", status)); + break; + } + case NUMBER_OF_CHEATS: break; } diff --git a/src/k_dialogue.h b/src/k_dialogue.h index 7b4f7437e..4d6c05c79 100644 --- a/src/k_dialogue.h +++ b/src/k_dialogue.h @@ -25,6 +25,8 @@ void K_UnsetDialogue(void); void K_DrawDialogue(void); void K_TickDialogue(void); +boolean K_DialogueFreeze(void); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_dialogue.hpp b/src/k_dialogue.hpp index c3fb8dd5a..8639524fc 100644 --- a/src/k_dialogue.hpp +++ b/src/k_dialogue.hpp @@ -48,6 +48,7 @@ private: bool syllable; bool dismissable; + bool freeze; void Init(void); //void Unset(void); diff --git a/src/k_follower.c b/src/k_follower.c index b1e4261b0..05185212a 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -435,7 +435,7 @@ void K_HandleFollower(player_t *player) } else // follower exists, woo! { - if (player->follower->hitlag != 0) + if (P_MobjIsFrozen(player->follower)) { // Don't update frames in hitlag return; diff --git a/src/m_cheat.c b/src/m_cheat.c index b4cb60d83..e44735eb9 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -303,6 +303,14 @@ void Command_CheatGod_f(void) D_Cheat(consoleplayer, CHEAT_GOD); } +void Command_CheatFreeze_f(void) +{ + REQUIRE_CHEATS; + REQUIRE_INLEVEL; + + D_Cheat(consoleplayer, CHEAT_FREEZE); +} + void Command_Scale_f(void) { const double scaled = atof(COM_Argv(1)); diff --git a/src/m_cheat.h b/src/m_cheat.h index 1c1270e9b..a8d0505cc 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -41,6 +41,7 @@ typedef enum { CHEAT_RESPAWNAT, CHEAT_GIVEPOWERUP, CHEAT_SPHERES, + CHEAT_FREEZE, NUMBER_OF_CHEATS } cheat_t; @@ -74,6 +75,7 @@ void OP_ObjectplaceMovement(player_t *player); // void Command_CheatNoClip_f(void); void Command_CheatGod_f(void); +void Command_CheatFreeze_f(void); void Command_Savecheckpoint_f(void); void Command_Setrings_f(void); void Command_Setspheres_f(void); diff --git a/src/p_local.h b/src/p_local.h index 4c6b44449..c5ab6f37a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -333,6 +333,8 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration); #define PAL_RECYCLE 3 #define PAL_NUKE 4 +boolean P_MobjIsFrozen(mobj_t *mobj); + // // P_ENEMY // diff --git a/src/p_map.c b/src/p_map.c index 92a2a65d4..ff22d543a 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -573,7 +573,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; // Ignore the collision if BOTH things are in hitlag. - if (thing->hitlag > 0 && tm.thing->hitlag > 0) + if (P_MobjIsFrozen(thing) && P_MobjIsFrozen(tm.thing)) return BMIT_CONTINUE; if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) diff --git a/src/p_mobj.c b/src/p_mobj.c index 4f1b97657..c4c61b10f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9937,6 +9937,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->flags2 &= ~(MF2_ALREADYHIT); // Don't run any thinker code while in hitlag + mobj->eflags &= ~(MFE_PAUSED); if ((mobj->player ? mobj->hitlag - mobj->player->nullHitlag : mobj->hitlag) > 0) { mobj->eflags |= MFE_PAUSED; @@ -9971,11 +9972,14 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->type == MT_HITLAG && mobj->hitlag == 0) mobj->renderflags &= ~RF_DONTDRAW; */ + } + if (P_MobjIsFrozen(mobj)) + { return; } - mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED|MFE_PAUSED); + mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED); // sal: what the hell? is there any reason this isn't done, like, literally ANYWHERE else? P_SetTarget(&tm.floorthing, NULL); diff --git a/src/p_mobj.h b/src/p_mobj.h index 61bf62bf7..04344d505 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -433,6 +433,8 @@ struct mobj_t INT32 script_args[NUM_SCRIPT_ARGS]; char *script_stringargs[NUM_SCRIPT_STRINGARGS]; + boolean frozen; + // WARNING: New fields must be added separately to savegame and Lua. }; diff --git a/src/p_saveg.c b/src/p_saveg.c index 7f2410694..be6724ed4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2534,7 +2534,7 @@ typedef enum MD2_WAYPOINTCAP = 1<<25, MD2_KITEMCAP = 1<<26, MD2_ITNEXT = 1<<27, - MD2_LASTMOMZ = 1<<28, + MD2_FROZEN = 1<<28, MD2_TERRAIN = 1<<29, MD2_WATERSKIP = 1<<30, MD2_LIGHTLEVEL = (INT32)(1U<<31), @@ -2725,7 +2725,7 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 } // not the default but the most probable - if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0) + if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0 || mobj->lastmomz != 0) diff |= MD_MOM; if (mobj->radius != mobj->info->radius) diff |= MD_RADIUS; @@ -2847,8 +2847,8 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 diff2 |= MD2_KITEMCAP; if (mobj->itnext) diff2 |= MD2_ITNEXT; - if (mobj->lastmomz) - diff2 |= MD2_LASTMOMZ; + if (mobj->frozen) + diff2 |= MD2_FROZEN; if (mobj->terrain != NULL || mobj->terrainOverlay != NULL) diff2 |= MD2_TERRAIN; @@ -2911,6 +2911,7 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 WRITEFIXED(save->p, mobj->momy); WRITEFIXED(save->p, mobj->momz); WRITEFIXED(save->p, mobj->pmomz); + WRITEFIXED(save->p, mobj->lastmomz); } if (diff & MD_RADIUS) WRITEFIXED(save->p, mobj->radius); @@ -3114,9 +3115,9 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 { WRITEINT32(save->p, mobj->dispoffset); } - if (diff2 & MD2_LASTMOMZ) + if (diff2 & MD2_FROZEN) { - WRITEINT32(save->p, mobj->lastmomz); + WRITEUINT8(save->p, mobj->frozen); } if (diff2 & MD2_TERRAIN) { @@ -4093,6 +4094,7 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) mobj->momy = READFIXED(save->p); mobj->momz = READFIXED(save->p); mobj->pmomz = READFIXED(save->p); + mobj->lastmomz = READFIXED(save->p); } // otherwise they're zero, and the memset took care of it if (diff & MD_RADIUS) @@ -4347,9 +4349,9 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) { mobj->dispoffset = READINT32(save->p); } - if (diff2 & MD2_LASTMOMZ) + if (diff2 & MD2_FROZEN) { - mobj->lastmomz = READINT32(save->p); + mobj->frozen = (boolean)READUINT8(save->p); } if (diff2 & MD2_TERRAIN) { diff --git a/src/p_tick.c b/src/p_tick.c index 737ff9ba2..2ccf6243c 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -52,6 +52,63 @@ tic_t leveltime; boolean thinkersCompleted; +static boolean g_freezeCheat; +static boolean g_freezeLevel; + +boolean P_LevelIsFrozen(void) +{ + return (g_freezeLevel || g_freezeCheat); +} + +boolean P_FreezeCheat(void) +{ + return (g_freezeLevel || g_freezeCheat); +} + +void P_SetFreezeCheat(boolean value) +{ + g_freezeCheat = value; +} + +void P_SetFreezeLevel(boolean value) +{ + g_freezeLevel = value; +} + +boolean P_MobjIsFrozen(mobj_t *mobj) +{ + if (g_freezeCheat == true) + { + // freeze cheat + switch (mobj->type) + { + case MT_PLAYER: + { + break; + } + default: + { + return true; + } + } + } + + if (g_freezeLevel == true) + { + // level totally frozen + return true; + } + + if ((mobj->eflags & MFE_PAUSED) == MFE_PAUSED) + { + // hitlag + return true; + } + + // manual + return mobj->frozen; +} + INT32 P_AltFlip(INT32 n, tic_t tics) { return leveltime % (2 * tics) < tics ? n : -(n); diff --git a/src/p_tick.h b/src/p_tick.h index d05813c1c..58c154a1a 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -27,6 +27,12 @@ extern "C" { extern tic_t leveltime; extern boolean thinkersCompleted; +boolean P_LevelIsFrozen(void); +boolean P_FreezeCheat(void); +void P_SetFreezeCheat(boolean value); +void P_SetFreezeLevel(boolean value); +boolean P_MobjIsFrozen(mobj_t *mobj); + // Called by G_Ticker. Carries out all thinking of enemies and players. void Command_Numthinkers_f(void); void Command_CountMobjs_f(void); diff --git a/src/p_user.c b/src/p_user.c index 8f4dc5090..41708735b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3118,7 +3118,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall mo = player->mo; - if (mo->hitlag > 0 || player->playerstate == PST_DEAD) + if (P_MobjIsFrozen(mo) || player->playerstate == PST_DEAD) { // Do not move the camera while in hitlag! // The camera zooming out after you got hit makes it hard to focus on the vibration. @@ -4212,7 +4212,7 @@ void P_PlayerThink(player_t *player) ALL ABOVE THIS BLOCK OCCURS EVEN WITH HITLAG / ------------------------------------------ */ - if (player->mo->hitlag > 0) + if (P_MobjIsFrozen(player->mo)) { return; } @@ -4550,7 +4550,7 @@ void P_IncrementGriefValue(player_t *player, UINT32 *grief, const UINT32 griefMa INT32 progress = player->distancetofinishprev - player->distancetofinish; boolean exceptions = ( player->flashing != 0 - || player->mo->hitlag != 0 + || P_MobjIsFrozen(player->mo) || player->airtime > 3*TICRATE/2 || (player->justbumped > 0 && player->justbumped < bumptime-1) ); From 0211dc4f34078d2f3298f95cc9eb8b79afabf17e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 23 Sep 2023 15:51:33 -0400 Subject: [PATCH 02/53] Reset freeze on level load --- src/p_setup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_setup.c b/src/p_setup.c index da3f780b7..8b03e3a8a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7536,6 +7536,9 @@ static void P_InitLevelSettings(void) leveltime = 0; modulothing = 0; + P_SetFreezeLevel(false); + P_SetFreezeCheat(false); + K_TimerReset(); nummaprings = 0; From d3ee4d631a214ce7df7e22bcc513b1a571e4c0f8 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 23 Sep 2023 15:54:01 -0400 Subject: [PATCH 03/53] Add "Freeze" ACS function --- src/acs/call-funcs.cpp | 15 +++++++++++++++ src/acs/call-funcs.hpp | 2 ++ src/acs/environment.cpp | 1 + 3 files changed, 18 insertions(+) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 25af308f7..c9967aed1 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -2176,6 +2176,21 @@ bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: return false; } +/*-------------------------------------------------- + bool CallFunc_Freeze(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Updates level freeze. +--------------------------------------------------*/ +bool CallFunc_Freeze(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argV; + (void)argC; + + P_SetFreezeLevel(argV[0] != 0); + + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index 86af95f15..e309ce4f0 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -101,6 +101,8 @@ bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_Freeze(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index 796abeceb..78ac76a00 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -179,6 +179,7 @@ Environment::Environment() addFuncDataACS0( 508, addCallFunc(CallFunc_MusicPlay)); addFuncDataACS0( 509, addCallFunc(CallFunc_MusicStopAll)); addFuncDataACS0( 510, addCallFunc(CallFunc_MusicRemap)); + addFuncDataACS0( 511, addCallFunc(CallFunc_Freeze)); addFuncDataACS0( 600, addCallFunc(CallFunc_DialogueSetSpeaker)); addFuncDataACS0( 601, addCallFunc(CallFunc_DialogueSetCustomSpeaker)); From 7a8bb8ec40cb34f1504c95fc5e448c6f0c975932 Mon Sep 17 00:00:00 2001 From: Lach Date: Sun, 24 Sep 2023 22:29:52 +1000 Subject: [PATCH 04/53] Hardcode Chaos Chute objects --- src/deh_tables.c | 16 +++++++++++ src/info.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 21 +++++++++++++++ src/k_kart.c | 34 +++++++++++++++++++++++- src/k_kart.h | 3 ++- src/p_enemy.c | 41 ++++++++-------------------- src/p_inter.c | 20 ++++++++++++++ 7 files changed, 172 insertions(+), 32 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 7a730b6ce..8cc5a5691 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -289,6 +289,7 @@ actionpointer_t actionpointers[] = {{A_SSMineFlash}, "A_SSMINEFLASH"}, {{A_LandMineExplode}, "A_LANDMINEEXPLODE"}, {{A_BallhogExplode}, "A_BALLHOGEXPLODE"}, + {{A_SpecialStageBombExplode},"A_SPECIALSTAGEBOMBEXPLODE"}, {{A_LightningFollowPlayer}, "A_LIGHTNINGFOLLOWPLAYER"}, {{A_FZBoomFlash}, "A_FZBOOMFLASH"}, {{A_FZBoomSmoke}, "A_FZBOOMSMOKE"}, @@ -4369,6 +4370,17 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_EERIEFOG4", "S_EERIEFOG5", + // Chaos Chute + "S_SPECIALSTAGEARCH", + "S_SPECIALSTAGEBOMB", + "S_SPECIALSTAGEBOMB_DISARM", + "S_SPECIALSTAGEBOMB_EXPLODE", + "S_SPECIALSTAGEBOMB_DISAPPEAR", + "S_SPECIALSTAGEBOMB_FLICKER1", + "S_SPECIALSTAGEBOMB_FLICKER2", + "S_SPECIALSTAGEBOMB_FLICKERLOOP", + "S_SPECIALSTAGEBOMB_RESET", + // SMK ports "S_SMK_PIPE1", // Generic pipes "S_SMK_PIPE2", @@ -5727,6 +5739,10 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_EERIEFOG", "MT_EERIEFOGGEN", + // Chaos Chute + "MT_SPECIALSTAGEARCH", + "MT_SPECIALSTAGEBOMB", + // SMK ports "MT_SMK_PIPE", "MT_SMK_MOLESPAWNER", diff --git a/src/info.c b/src/info.c index 0a311d369..7c8f93e6d 100644 --- a/src/info.c +++ b/src/info.c @@ -797,6 +797,10 @@ char sprnames[NUMSPRITES + 1][5] = // Eerie Grove "EGFG", + // Chaos Chute + "SARC", + "SSBM", + // SMK ports "SMKP", "MTYM", @@ -5088,6 +5092,17 @@ state_t states[NUMSTATES] = {SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|3, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG5}, // S_EERIEFOG4 {SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|4, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG1}, // S_EERIEFOG5 + // Chaos Chute + {SPR_SARC, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIALSTAGEARCH + {SPR_SSBM, FF_GLOBALANIM|FF_ANIMATE|0, -1, {NULL}, 3, 3, S_NULL}, // S_SPECIALSTAGEBOMB + {SPR_SSBM, 0, 1, {A_SetObjectFlags}, MF_NOCLIPTHING, 2, S_SPECIALSTAGEBOMB_EXPLODE}, // S_SPECIALSTAGEBOMB_DISARM + {SPR_NULL, 0, 0, {A_SpecialStageBombExplode}, 0, 0, S_SPECIALSTAGEBOMB_DISAPPEAR}, // S_SPECIALSTAGEBOMB_EXPLODE + {SPR_NULL, 0, 28*TICRATE, {A_Pain}, 0, 0, S_SPECIALSTAGEBOMB_FLICKER1}, // S_SPECIALSTAGEBOMB_DISAPPEAR + {SPR_SSBM, FF_GLOBALANIM|FF_ANIMATE|0, 1, {NULL}, 3, 3, S_SPECIALSTAGEBOMB_FLICKER2}, // S_SPECIALSTAGEBOMB_FLICKER1 + {SPR_NULL, 0, 1, {NULL}, 0, 0, S_SPECIALSTAGEBOMB_FLICKERLOOP}, // S_SPECIALSTAGEBOMB_FLICKER2 + {SPR_NULL, 0, 0, {A_Repeat}, TICRATE, S_SPECIALSTAGEBOMB_FLICKER1, S_SPECIALSTAGEBOMB_RESET}, // S_SPECIALSTAGEBOMB_FLICKERLOOP + {SPR_NULL, 0, 0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_SPECIALSTAGEBOMB}, // S_SPECIALSTAGEBOMB_RESET + // SMK ports {SPR_SMKP, 0, -1, {NULL}, 0, 0, S_SMK_PIPE1}, // S_SMK_PIPE1 {SPR_SMKP, 1, -1, {NULL}, 0, 0, S_SMK_PIPE2}, // S_SMK_PIPE2 @@ -28300,6 +28315,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SPECIALSTAGEARCH + 3889, // doomednum + S_SPECIALSTAGEARCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 16*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_SPECIALSTAGEBOMB + 3890, // doomednum + S_SPECIALSTAGEBOMB, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_SPECIALSTAGEBOMB_DISARM, // painstate + 0, // painchance + sfx_s24b, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 60*FRACUNIT, // radius + 100*FRACUNIT, // height + 0, // dispoffset + 7, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL, // flags + S_SPECIALSTAGEBOMB_EXPLODE // raisestate + }, + { // MT_SMK_PIPE 3970, // doomednum S_SMK_PIPE1, // spawnstate diff --git a/src/info.h b/src/info.h index 1a4054638..e50c5cb60 100644 --- a/src/info.h +++ b/src/info.h @@ -282,6 +282,7 @@ enum actionnum A_SSMINEEXPLODE, A_LANDMINEEXPLODE, A_BALLHOGEXPLODE, + A_SPECIALSTAGEBOMBEXPLODE, A_LIGHTNINGFOLLOWPLAYER, A_FZBOOMFLASH, A_FZBOOMSMOKE, @@ -557,6 +558,7 @@ void A_SSMineFlash(); void A_LandMineExplode(); void A_LandMineExplode(); void A_BallhogExplode(); +void A_SpecialStageBombExplode(); void A_LightningFollowPlayer(); void A_FZBoomFlash(); void A_FZBoomSmoke(); @@ -1351,6 +1353,10 @@ typedef enum sprite // Eerie Grove SPR_EGFG, + // Chaos Chute + SPR_SARC, + SPR_SSBM, + // SMK ports SPR_SMKP, SPR_MTYM, @@ -5526,6 +5532,17 @@ typedef enum state S_EERIEFOG4, S_EERIEFOG5, + // Chaos Chute + S_SPECIALSTAGEARCH, + S_SPECIALSTAGEBOMB, + S_SPECIALSTAGEBOMB_DISARM, + S_SPECIALSTAGEBOMB_EXPLODE, + S_SPECIALSTAGEBOMB_DISAPPEAR, + S_SPECIALSTAGEBOMB_FLICKER1, + S_SPECIALSTAGEBOMB_FLICKER2, + S_SPECIALSTAGEBOMB_FLICKERLOOP, + S_SPECIALSTAGEBOMB_RESET, + // SMK ports S_SMK_PIPE1, // Generic pipes S_SMK_PIPE2, @@ -6919,6 +6936,10 @@ typedef enum mobj_type MT_EERIEFOG, MT_EERIEFOGGEN, + // Chaos Chute + MT_SPECIALSTAGEARCH, + MT_SPECIALSTAGEBOMB, + // SMK ports MT_SMK_PIPE, MT_SMK_MOLESPAWNER, diff --git a/src/k_kart.c b/src/k_kart.c index c4c48c630..848a7acdc 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4524,7 +4524,7 @@ void K_MineFlashScreen(mobj_t *source) } // Spawns the purely visual explosion -void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay) +void K_SpawnMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay) { INT32 i, radius, height; mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING); @@ -4612,6 +4612,38 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay) #undef MINEQUAKEDIST +void K_SpawnLandMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay) +{ + mobj_t *smoldering; + mobj_t *expl; + UINT8 i; + + // Spawn smoke remains: + smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING); + P_SetScale(smoldering, source->scale); + smoldering->tics = TICRATE*3; + smoldering->hitlag = delay; + + // spawn a few physics explosions + for (i = 0; i < 15; i++) + { + expl = P_SpawnMobj(source->x, source->y, source->z + source->scale, MT_BOOMEXPLODE); + expl->color = color; + expl->tics = (i+1); + expl->hitlag = delay; + expl->renderflags |= RF_DONTDRAW; + + //K_MatchGenericExtraFlags(expl, actor); + P_SetScale(expl, source->scale*4); + + expl->momx = P_RandomRange(PR_EXPLOSION, -3, 3)*source->scale/2; + expl->momy = P_RandomRange(PR_EXPLOSION, -3, 3)*source->scale/2; + + // 100/45 = 2.22 fu/t + expl->momz = ((i+1)*source->scale*5/2)*P_MobjFlip(expl); + } +} + fixed_t K_ItemScaleForPlayer(player_t *player) { switch (player->itemscale) diff --git a/src/k_kart.h b/src/k_kart.h index e33580f81..0f310d403 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -120,7 +120,8 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source); void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount); void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount); void K_MineFlashScreen(mobj_t *source); -void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay); +void K_SpawnMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay); +void K_SpawnLandMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay); void K_RunFinishLineBeam(void); UINT16 K_DriftSparkColor(player_t *player, INT32 charge); void K_SpawnBoostTrail(player_t *player); diff --git a/src/p_enemy.c b/src/p_enemy.c index b8bedfc5e..f874e1f1a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -318,6 +318,7 @@ void A_SSMineExplode(mobj_t *actor); void A_SSMineFlash(mobj_t *actor); void A_LandMineExplode(mobj_t *actor); void A_BallhogExplode(mobj_t *actor); +void A_SpecialStageBombExplode(mobj_t *actor); void A_LightningFollowPlayer(mobj_t *actor); void A_FZBoomFlash(mobj_t *actor); void A_FZBoomSmoke(mobj_t *actor); @@ -13068,12 +13069,7 @@ void A_SSMineFlash(mobj_t *actor) void A_LandMineExplode(mobj_t *actor) { - - mobj_t *expl; - INT32 colour = SKINCOLOR_KETCHUP; // we spell words properly here - INT32 i; - mobj_t *smoldering; - + skincolornum_t colour = SKINCOLOR_KETCHUP; // we spell words properly here tic_t delay = actor->reactiontime; if (LUA_CallAction(A_LANDMINEEXPLODE, actor)) @@ -13090,33 +13086,10 @@ void A_LandMineExplode(mobj_t *actor) if (actor->target && !P_MobjWasRemoved(actor->target)) colour = actor->target->color; - // Spawn smoke remains: - smoldering = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOLDERING); - P_SetScale(smoldering, actor->scale); - smoldering->tics = TICRATE*3; - smoldering->hitlag = delay; + K_SpawnLandMineExplosion(actor, colour, delay); actor->fuse = actor->tics; // disappear when this state ends. - // spawn a few physics explosions - for (i = 0; i < 15; i++) - { - expl = P_SpawnMobj(actor->x, actor->y, actor->z + actor->scale, MT_BOOMEXPLODE); - expl->color = colour; - expl->tics = (i+1); - expl->hitlag = delay; - expl->renderflags |= RF_DONTDRAW; - - //K_MatchGenericExtraFlags(expl, actor); - P_SetScale(expl, actor->scale*4); - - expl->momx = P_RandomRange(PR_EXPLOSION, -3, 3)*actor->scale/2; - expl->momy = P_RandomRange(PR_EXPLOSION, -3, 3)*actor->scale/2; - - // 100/45 = 2.22 fu/t - expl->momz = ((i+1)*actor->scale*5/2)*P_MobjFlip(expl); - } - Obj_SpawnBrolyKi(actor, delay); } @@ -13134,6 +13107,14 @@ void A_BallhogExplode(mobj_t *actor) return; } +void A_SpecialStageBombExplode(mobj_t *actor) +{ + if (LUA_CallAction(A_SPECIALSTAGEBOMBEXPLODE, actor)) + return; + + K_SpawnLandMineExplosion(actor, SKINCOLOR_KETCHUP, actor->hitlag); +} + // A_LightningFollowPlayer: // Dumb simple function that gives a mobj its target's momentums without updating its angle. void A_LightningFollowPlayer(mobj_t *actor) diff --git a/src/p_inter.c b/src/p_inter.c index 6176201ec..89654574a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -556,6 +556,26 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetTarget(&special->target, toucher); S_StartSound(special, sfx_s1a2); return; + + case MT_SPECIALSTAGEBOMB: + // only attempt to damage the player if they're not invincible + if (!(player->invincibilitytimer > 0 + || K_IsBigger(toucher, special) == true + || K_PlayerGuard(player) == true + || player->hyudorotimer > 0)) + { + if (P_DamageMobj(toucher, special, special, 1, DMG_STUMBLE)) + { + P_SetMobjState(special, special->info->painstate); + special->eflags |= MFE_DAMAGEHITLAG; + return; + } + } + // if we didn't damage the player, just explode + P_SetMobjState(special, special->info->painstate); + P_SetMobjState(special, special->info->raisestate); // immediately explode visually + return; + case MT_CDUFO: // SRB2kart if (special->fuse || !P_CanPickupItem(player, 1)) return; From 643cf46b61087c00ca481a6cd32d9437d22c96ee Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 26 Sep 2023 08:30:41 -0400 Subject: [PATCH 05/53] Ball switch --- src/deh_tables.c | 8 ++ src/info.c | 61 ++++++++++ src/info.h | 10 ++ src/k_collide.cpp | 8 +- src/k_objects.h | 6 + src/objects/CMakeLists.txt | 1 + src/objects/ball-switch.cpp | 237 ++++++++++++++++++++++++++++++++++++ src/p_inter.c | 12 ++ src/p_mobj.c | 8 ++ 9 files changed, 345 insertions(+), 6 deletions(-) create mode 100644 src/objects/ball-switch.cpp diff --git a/src/deh_tables.c b/src/deh_tables.c index 7a730b6ce..0272e605b 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4671,6 +4671,11 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_CHECKPOINT_SPARK9", "S_CHECKPOINT_SPARK10", "S_CHECKPOINT_SPARK11", + + "S_BALLSWITCH_BALL", + "S_BALLSWITCH_BALL_ACTIVE", + "S_BALLSWITCH_PAD", + "S_BALLSWITCH_PAD_ACTIVE", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -5823,6 +5828,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_CHECKPOINT_END", "MT_SCRIPT_THING", + + "MT_BALLSWITCH_BALL", + "MT_BALLSWITCH_PAD", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 0a311d369..06c9b9ee5 100644 --- a/src/info.c +++ b/src/info.c @@ -892,6 +892,8 @@ char sprnames[NUMSPRITES + 1][5] = "CPT2", // Checkpoint Stick "CPT3", // Checkpoint Base + "SA2S", // SA2-style Ball Switch + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5417,6 +5419,11 @@ state_t states[NUMSTATES] = {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK10}, // S_CHECKPOINT_SPARK9 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK11}, // S_CHECKPOINT_SPARK10 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK1}, // S_CHECKPOINT_SPARK11 + + {SPR_SA2S, FF_SEMIBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_BALL + {SPR_SA2S, FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM|4, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_BALL_ACTIVE + {SPR_SA2S, FF_FLOORSPRITE|FF_SEMIBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_PAD + {SPR_SA2S, FF_FLOORSPRITE|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM|1, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_PAD_ACTIVE }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -30381,6 +30388,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags S_NULL // raisestate }, + + { // MT_BALLSWITCH_BALL + 5000, // doomednum + S_BALLSWITCH_BALL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 36*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_BALLSWITCH_PAD + -1, // doomednum + S_BALLSWITCH_PAD, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 64*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, }; skincolor_t skincolors[MAXSKINCOLORS] = { diff --git a/src/info.h b/src/info.h index 1a4054638..f21e4d359 100644 --- a/src/info.h +++ b/src/info.h @@ -1446,6 +1446,8 @@ typedef enum sprite SPR_CPT2, // Checkpoint Stick SPR_CPT3, // Checkpoint Base + SPR_SA2S, // SA2-style Ball Switch + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -5845,6 +5847,11 @@ typedef enum state S_CHECKPOINT_SPARK10, S_CHECKPOINT_SPARK11, + S_BALLSWITCH_BALL, + S_BALLSWITCH_BALL_ACTIVE, + S_BALLSWITCH_PAD, + S_BALLSWITCH_PAD_ACTIVE, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -7016,6 +7023,9 @@ typedef enum mobj_type MT_CHECKPOINT_END, MT_SCRIPT_THING, + MT_BALLSWITCH_BALL, + MT_BALLSWITCH_PAD, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/k_collide.cpp b/src/k_collide.cpp index b897873a8..e743776bc 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -931,16 +931,12 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) } else { - if (victim->type == MT_ORBINAUT || victim->type == MT_JAWZ || victim->type == MT_GACHABOM - || victim->type == MT_BANANA || victim->type == MT_EGGMANITEM || victim->type == MT_BALLHOG - || victim->type == MT_SSMINE || victim->type == MT_LANDMINE || victim->type == MT_SINK - || victim->type == MT_GARDENTOP || victim->type == MT_DROPTARGET || victim->type == MT_BATTLECAPSULE - || victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO || victim->type == MT_BATTLEUFO) + if (victim->flags & MF_SHOOTABLE) { // Monitor hack. We can hit monitors once per instawhip, no multihit shredding! // Damage values in Obj_MonitorGetDamage. // Apply to UFO also -- steelt 29062023 - if (victim->type == MT_MONITOR || victim->type == MT_BATTLEUFO) + if (victim->type == MT_MONITOR || victim->type == MT_BATTLEUFO || victim->type == MT_BALLSWITCH_BALL) { if (shield->extravalue1 == 1) return false; diff --git a/src/k_objects.h b/src/k_objects.h index d5e06e8e8..78df2bb62 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -233,6 +233,12 @@ boolean Obj_GetCheckpointRespawnPosition(const mobj_t *checkpoint, vector3_t *re angle_t Obj_GetCheckpointRespawnAngle(const mobj_t *checkpoint); void Obj_ActivateCheckpointInstantly(mobj_t* mobj); +/* Ball Switch */ +void Obj_BallSwitchInit(mobj_t *mobj); +void Obj_BallSwitchThink(mobj_t *mobj); +void Obj_BallSwitchTouched(mobj_t *mobj, mobj_t *toucher); +void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 89d5a17c1..694588783 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -30,4 +30,5 @@ target_sources(SRB2SDL2 PRIVATE emerald.c checkpoint.cpp shadow.cpp + ball-switch.cpp ) diff --git a/src/objects/ball-switch.cpp b/src/objects/ball-switch.cpp new file mode 100644 index 000000000..c272452a0 --- /dev/null +++ b/src/objects/ball-switch.cpp @@ -0,0 +1,237 @@ +#include "../k_objects.h" + +#include "../doomdef.h" +#include "../info.h" +#include "../p_local.h" +#include "../r_main.h" +#include "../k_hitlag.h" + +#define ball_pad(o) ((o)->target) +#define ball_instawhipped(o) ((o)->extravalue1) // see instawhip collide + +#define ball_cooldown(o) ((o)->cvmem) + +#define ball_activedefer(o) ((o)->extravalue2) +#define ball_activator(o) ((o)->tracer) + +namespace +{ + +struct BallSwitch_Pad : mobj_t +{ + statenum_t Anim() const { return static_cast(this->state - states); } + void Anim(statenum_t n) + { + if (Anim() != n) + { + P_SetMobjState(this, n); + } + } + + void Spawned() + { + renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE; + } + + void Tick(boolean active) + { + if (active == true) + { + Anim(S_BALLSWITCH_PAD_ACTIVE); + } + else + { + Anim(S_BALLSWITCH_PAD); + } + } +}; + +struct BallSwitch_Ball : mobj_t +{ + BallSwitch_Pad *Pad() const { return static_cast( ball_pad(this) ); } + void Pad(BallSwitch_Pad *n) { P_SetTarget(&ball_pad(this), n); } + + statenum_t Anim() const { return static_cast(this->state - states); } + void Anim(statenum_t n) + { + if (Anim() != n) + { + P_SetMobjState(this, n); + } + } + + INT32 Cooldown() const { return ball_cooldown(this); } + void Cooldown(INT32 n) { ball_cooldown(this) = n; } + boolean Active() const { return (ball_cooldown(this) != 0); } + + boolean DeferActivation() const { return ball_activedefer(this); } + mobj_t *Activator() const { return ball_activator(this); } + + void DeferActivation(boolean n, mobj_t *src) + { + ball_activedefer(this) = n; + P_SetTarget(&ball_activator(this), src); + } + + SINT8 IntSign(int value) const + { + if (value > 0) + { + return 1; + } + + if (value < 0) + { + return -1; + } + + return 0; + } + + void Spawned() + { + Pad( static_cast( P_SpawnMobjFromMobj(this, 0, 0, 0, MT_BALLSWITCH_PAD) ) ); + Pad()->Spawned(); + + this->z += Pad()->height * P_MobjFlip(this); + } + + void Tick() + { + if (P_MobjWasRemoved(Pad()) == true) + { + P_RemoveMobj(this); + return; + } + + ball_instawhipped(this) = 0; + + if (DeferActivation() == true) + { + P_ActivateThingSpecial(this, Activator()); + Cooldown(-1); // maybe later? + DeferActivation(false, nullptr); + } + + fixed_t ourZ = P_GetMobjFeet(this); + fixed_t theirZ = P_GetMobjHead(Pad()); + + fixed_t dist = P_AproxDistance(P_AproxDistance(Pad()->x - this->x, Pad()->y - this->y), theirZ - ourZ); + fixed_t move = P_AproxDistance(P_AproxDistance(this->momx, this->momy), this->momz); + + constexpr INT32 accelScale = 4; + + if (dist < accelScale * this->scale && move < accelScale * this->scale) + { + P_SetOrigin(this, Pad()->x, Pad()->y, theirZ); + this->momx = this->momy = this->momz = 0; + } + else + { + static constexpr const INT32 accel[2] = { FRACUNIT*3/4, FRACUNIT*3/16 }; + constexpr fixed_t frict = FRACUNIT*99/100; + + this->momx = FixedMul(this->momx, frict); + this->momy = FixedMul(this->momy, frict); + this->momz = FixedMul(this->momz, frict); + + SINT8 xSign = IntSign(Pad()->x - this->x); + SINT8 ySign = IntSign(Pad()->y - this->y); + SINT8 zSign = IntSign(theirZ - ourZ); + + boolean xAway = (IntSign(this->momx) == xSign); + boolean yAway = (IntSign(this->momy) == ySign); + boolean zAway = (IntSign(this->momz) == zSign); + + this->momx += FixedMul(accel[xAway], accelScale * this->scale) * xSign; + this->momy += FixedMul(accel[yAway], accelScale * this->scale) * ySign; + this->momz += FixedMul(accel[zAway], accelScale * this->scale) * zSign; + + this->angle += FixedAngle(move * 2); + if (dist > this->radius * 2) + { + P_Thrust(this, this->angle, (move / accelScale) * 2 / 3); + } + } + + if (Active() == true) + { + INT32 cool = Cooldown(); + if (cool > 0) + { + Cooldown(cool - 1); + } + + Anim(S_BALLSWITCH_BALL_ACTIVE); + } + else + { + Anim(S_BALLSWITCH_BALL); + } + + Pad()->Tick(Active()); + } + + void Push(mobj_t *toucher, const fixed_t pushValue, const fixed_t repelValue) + { + fixed_t push = FixedMul(pushValue, toucher->scale); + fixed_t repel = FixedMul(repelValue, this->scale); + + angle_t thrustAngle = R_PointToAngle2(toucher->x, toucher->y, this->x, this->y); + fixed_t thrustAngleCos = FINECOSINE(thrustAngle >> ANGLETOFINESHIFT); + fixed_t thrustAngleSin = FINESINE(thrustAngle >> ANGLETOFINESHIFT); + + fixed_t thisZ = this->z + (this->height / 2); + fixed_t toucherZ = toucher->z + (toucher->height / 2); + + angle_t thrustPitch = R_PointToAngle2(0, toucherZ, R_PointToDist2(toucher->x, toucher->y, this->x, this->y), thisZ); + fixed_t thrustPitchCos = FINECOSINE(thrustPitch >> ANGLETOFINESHIFT); + fixed_t thrustPitchSin = FINESINE(thrustPitch >> ANGLETOFINESHIFT); + + this->momx += FixedMul(FixedMul(push, thrustAngleCos), thrustPitchCos); + this->momy += FixedMul(FixedMul(push, thrustAngleSin), thrustPitchCos); + this->momz += FixedMul(push, thrustPitchSin); + + toucher->momx -= FixedMul(FixedMul(repel, thrustAngleCos), thrustPitchCos); + toucher->momy -= FixedMul(FixedMul(repel, thrustAngleSin), thrustPitchCos); + toucher->momz -= FixedMul(repel, thrustPitchSin); + } + + void Touch(mobj_t *toucher) + { + Push(toucher, 4 << FRACBITS, 6 << FRACBITS); + } + + void Hit(mobj_t *inflictor, mobj_t *source) + { + Push(inflictor, 64 << FRACBITS, 1 << FRACBITS); + K_SetHitLagForObjects(this, inflictor, source, 4, true); + DeferActivation(true, source); + } +}; + +}; // namespace + +void Obj_BallSwitchInit(mobj_t *mobj) +{ + BallSwitch_Ball *ball = static_cast(mobj); + ball->Spawned(); +} + +void Obj_BallSwitchThink(mobj_t *mobj) +{ + BallSwitch_Ball *ball = static_cast(mobj); + ball->Tick(); +} + +void Obj_BallSwitchTouched(mobj_t *mobj, mobj_t *toucher) +{ + BallSwitch_Ball *ball = static_cast(mobj); + ball->Touch(toucher); +} + +void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source) +{ + BallSwitch_Ball *ball = static_cast(mobj); + ball->Hit(inflictor, source); +} diff --git a/src/p_inter.c b/src/p_inter.c index 6176201ec..62f842277 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -817,6 +817,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) Obj_DashRingTouch(special, player); return; + case MT_BALLSWITCH_BALL: + { + Obj_BallSwitchTouched(special, toucher); + return; + } + default: // SOC or script pickup P_SetTarget(&special->target, toucher); break; @@ -2398,6 +2404,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; } + if (target->type == MT_BALLSWITCH_BALL) + { + Obj_BallSwitchDamaged(target, inflictor, source); + return false; + } + if (!force) { if (!spbpop) diff --git a/src/p_mobj.c b/src/p_mobj.c index 599dd37e8..fcb6fa830 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9703,6 +9703,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_RAINBOWDASHRING: Obj_RainbowDashRingThink(mobj); break; + case MT_BALLSWITCH_BALL: + { + Obj_BallSwitchThink(mobj); + break; + } default: // check mobj against possible water content, before movement code P_MobjCheckWater(mobj); @@ -11142,6 +11147,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_SNEAKERPANELSPAWNER: Obj_SneakerPanelSpawnerSpawn(mobj); break; + case MT_BALLSWITCH_BALL: + Obj_BallSwitchInit(mobj); + break; default: break; } From 1fd1cee2e434904eb472f7c78a888adb741a57cf Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 26 Sep 2023 09:06:07 -0400 Subject: [PATCH 06/53] Remove fullbright from ball switch pad Allows brightmap to come through (although I can't get the brightmap to work) --- src/info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/info.c b/src/info.c index 06c9b9ee5..c7f1b52e3 100644 --- a/src/info.c +++ b/src/info.c @@ -5422,8 +5422,8 @@ state_t states[NUMSTATES] = {SPR_SA2S, FF_SEMIBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_BALL {SPR_SA2S, FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM|4, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_BALL_ACTIVE - {SPR_SA2S, FF_FLOORSPRITE|FF_SEMIBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_PAD - {SPR_SA2S, FF_FLOORSPRITE|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM|1, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_PAD_ACTIVE + {SPR_SA2S, FF_FLOORSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_PAD + {SPR_SA2S, FF_FLOORSPRITE|FF_ANIMATE|FF_GLOBALANIM|1, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_PAD_ACTIVE }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = From 288110539a3bae95983b87bea4ad74d04a1e65ff Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 26 Sep 2023 11:40:29 -0400 Subject: [PATCH 07/53] Fix activating more than once --- src/objects/ball-switch.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/objects/ball-switch.cpp b/src/objects/ball-switch.cpp index c272452a0..c2bd5cc76 100644 --- a/src/objects/ball-switch.cpp +++ b/src/objects/ball-switch.cpp @@ -206,7 +206,11 @@ struct BallSwitch_Ball : mobj_t { Push(inflictor, 64 << FRACBITS, 1 << FRACBITS); K_SetHitLagForObjects(this, inflictor, source, 4, true); - DeferActivation(true, source); + + if (Active() == false) + { + DeferActivation(true, source); + } } }; From 9854da9da1a9110ebc3073c9bd825ccb00c897ed Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Sep 2023 23:54:56 +0100 Subject: [PATCH 08/53] IsPlayerAdmin: Do not have non-tester specific DEVELOP behaviour It's easy enough for the host to verify any given player, and this is in fact the only HOSTTESTERS-specific sync change..!? --- src/d_netcmd.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 45076986f..55177cede 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3687,16 +3687,12 @@ static void Command_Login_f(void) boolean IsPlayerAdmin(INT32 playernum) { -#if defined(DEVELOP) && !(defined(HOSTTESTERS) || defined(TESTERS)) - return playernum != serverplayer; -#else INT32 i; for (i = 0; i < MAXPLAYERS; i++) if (playernum == adminplayers[i]) return true; return false; -#endif } void SetAdminPlayer(INT32 playernum) From 0b5fd330e66d75e5598be0ea42646724a0da14e5 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Sep 2023 23:56:35 +0100 Subject: [PATCH 09/53] Remove HOSTTESTERS Now you can host for testers using a bog-standard DEVELOP build. --- src/CMakeLists.txt | 5 ----- src/Makefile.d/features.mk | 2 +- src/d_netcmd.c | 2 -- src/f_finale.c | 5 ----- src/g_game.c | 2 +- 5 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 917020a75..e4b222fe9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -209,8 +209,6 @@ set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL "Compile a development build of Dr Robotnik's Ring Racers.") set(SRB2_CONFIG_TESTERS OFF CACHE BOOL "Compile a build for testers.") -set(SRB2_CONFIG_HOSTTESTERS OFF CACHE BOOL - "Compile a build to host netgames for testers builds.") add_subdirectory(blua) @@ -556,9 +554,6 @@ endif() if(SRB2_CONFIG_TESTERS) target_compile_definitions(SRB2SDL2 PRIVATE -DTESTERS) endif() -if(SRB2_CONFIG_HOSTTESTERS) - target_compile_definitions(SRB2SDL2 PRIVATE -DHOSTTESTERS) -endif() if(SRB2_CONFIG_MOBJCONSISTANCY) target_compile_definitions(SRB2SDL2 PRIVATE -DMOBJCONSISTANCY) endif() diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk index c8e43b6ea..7290de68b 100644 --- a/src/Makefile.d/features.mk +++ b/src/Makefile.d/features.mk @@ -6,7 +6,7 @@ passthru_opts+=\ NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ MOBJCONSISTANCY PACKETDROP ZDEBUG\ HAVE_MINIUPNPC\ - HAVE_DISCORDRPC TESTERS HOSTTESTERS DEVELOP + HAVE_DISCORDRPC TESTERS DEVELOP # build with debugging information ifdef DEBUGMODE diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 55177cede..0663f22e3 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4638,8 +4638,6 @@ static void Command_Version_f(void) // DEVELOP build #if defined(TESTERS) CONS_Printf("\x88" "TESTERS " "\x80"); -#elif defined(HOSTTESTERS) - CONS_Printf("\x82" "HOSTTESTERS " "\x80"); #elif defined(DEVELOP) CONS_Printf("\x87" "DEVELOP " "\x80"); #endif diff --git a/src/f_finale.c b/src/f_finale.c index 4b4c87941..5ded47495 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1565,9 +1565,6 @@ void F_VersionDrawer(void) #if defined(TESTERS) addtext(V_SKYMAP, "Tester client"); addtext(V_TRANSLUCENT, va("%s", compdate)); -#elif defined(HOSTTESTERS) - addtext(V_REDMAP, "Netgame host for testers"); - addtext(V_TRANSLUCENT, va("%s", compdate)); #elif defined(DEVELOP) addtext(V_TRANSLUCENT, va("%s %s", comprevision, compnote)); addtext(V_TRANSLUCENT, D_GetFancyBranchName()); @@ -1711,8 +1708,6 @@ void F_TitleScreenDrawer(void) #ifdef DEVELOP #if defined(TESTERS) V_DrawCenteredString(BASEVIDWIDTH/2, 96, V_SKYMAP, "Tester EXE"); -#elif defined(HOSTTESTERS) - V_DrawCenteredThinString(BASEVIDWIDTH/2, 96, V_REDMAP, "Tester netgame host EXE"); #else V_DrawCenteredString(BASEVIDWIDTH/2, 96, 0, "Development EXE"); #endif diff --git a/src/g_game.c b/src/g_game.c index d78bc3f11..0cce5ff8c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -89,7 +89,7 @@ JoyType_t Joystick[MAXSPLITSCREENPLAYERS]; // SRB2kart char gamedatafilename[64] = -#if defined (TESTERS) || defined (HOSTTESTERS) +#if defined (TESTERS) "test" #elif defined(DEVELOP) "develop" From 47fe8bb9b110f28b6750b827a199b2980fda0f21 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 26 Sep 2023 23:59:14 +0100 Subject: [PATCH 10/53] Move SRB2_CONFIG_DEV_BUILD and SRB2_CONFIG_TESTERS to the root directory CMakeLists.txt Repairs the pre-CMake functionality of TESTERS builds having the format `ringracers_branch-name_TESTERS.exe` --- CMakeLists.txt | 7 +++++++ src/CMakeLists.txt | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cfef6281..d1db16412 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,9 @@ option(SRB2_CONFIG_HWRENDER "Enable hardware render (OpenGL) support" ON) option(SRB2_CONFIG_STATIC_OPENGL "Enable static linking GL (do not do this)" OFF) option(SRB2_CONFIG_ERRORMODE "Compile C code with warnings treated as errors." OFF) option(SRB2_CONFIG_DEBUGMODE "Compile with PARANOIA, ZDEBUG, RANGECHECK and PACKETDROP defined." OFF) +option(SRB2_CONFIG_DEV_BUILD "Compile a development build." OFF) +option(SRB2_CONFIG_TESTERS "Compile a build for testers." OFF) +# SRB2_CONFIG_PROFILEMODE is probably superceded by some CMake setting. option(SRB2_CONFIG_MOBJCONSISTANCY "Compile with MOBJCONSISTANCY defined." OFF) option(SRB2_CONFIG_PACKETDROP "Compile with PACKETDROP defined." OFF) option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF) @@ -202,6 +205,10 @@ if("${SRB2_SDL2_EXE_NAME}" STREQUAL "") if(NOT "${SRB2_GIT_REVISION}" STREQUAL "master") list(APPEND EXE_NAME_PARTS ${SRB2_GIT_REVISION}) endif() + + if (SRB2_CONFIG_TESTERS) + list(APPEND EXE_NAME_PARTS "TESTERS") + endif() else() list(APPEND EXE_NAME_PARTS ${SRB2_SDL2_EXE_NAME}) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e4b222fe9..b7cce51f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -205,10 +205,6 @@ set(SRB2_CONFIG_USEASM OFF CACHE BOOL "Enable NASM tmap implementation for software mode speedup.") set(SRB2_CONFIG_YASM OFF CACHE BOOL "Use YASM in place of NASM.") -set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL - "Compile a development build of Dr Robotnik's Ring Racers.") -set(SRB2_CONFIG_TESTERS OFF CACHE BOOL - "Compile a build for testers.") add_subdirectory(blua) From b698fcfd0fd87485388d5075072e6e03cb0f489d Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 27 Sep 2023 00:14:11 +0100 Subject: [PATCH 11/53] Enable Server Browser access in TESTER builds Does not forbid seeing modded servers even if you haven't unlocked add-ons yet --- src/menus/play-online-1.c | 2 +- src/menus/play-online-room-select.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/menus/play-online-1.c b/src/menus/play-online-1.c index e58490187..7a7b54386 100644 --- a/src/menus/play-online-1.c +++ b/src/menus/play-online-1.c @@ -78,7 +78,7 @@ menuitem_t PLAY_MP_OptSelect[] = {IT_STRING_CALL_NOTESTERS, "Host Game", "Start your own online game!", NULL, {.routine = M_PreMPHostInit}, 0, 0}, - {IT_STRING_CALL_NOTESTERS, "Server Browser", "Search for game servers to play in.", + {IT_STRING | IT_CALL, "Server Browser", "Search for game servers to play in.", NULL, {.routine = M_PreMPRoomSelectInit}, 0, 0}, {IT_STRING | IT_CALL, "Join by IP", "Join an online game by its IP address.", diff --git a/src/menus/play-online-room-select.c b/src/menus/play-online-room-select.c index d0d6b9a58..05c458c4b 100644 --- a/src/menus/play-online-room-select.c +++ b/src/menus/play-online-room-select.c @@ -75,11 +75,13 @@ void M_MPRoomSelectInit(INT32 choice) mpmenu.scrolln = 0; mpmenu.slide = 0; +#ifndef TESTERS if ((modifiedgame == true) || (M_SecretUnlocked(SECRET_ADDONS, true) == false)) { M_ServersMenu(0); return; } +#endif // TESTERS M_SetupNextMenu(&PLAY_MP_RoomSelectDef, false); } From c90eaae4778dc77457bc7685b0c74ff8ad822dae Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 27 Sep 2023 00:25:25 +0100 Subject: [PATCH 12/53] IsPlayerAdmin: Make reimplementing the DEVELOP-specific behaviour at a later date easier --- src/d_netcmd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0663f22e3..2eb9bad65 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3687,12 +3687,16 @@ static void Command_Login_f(void) boolean IsPlayerAdmin(INT32 playernum) { +#if 0 // defined(DEVELOP) + return playernum != serverplayer; +#else INT32 i; for (i = 0; i < MAXPLAYERS; i++) if (playernum == adminplayers[i]) return true; return false; +#endif } void SetAdminPlayer(INT32 playernum) From d3d548ea36fcaca9a90bff2af6e94f005db14cea Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 27 Sep 2023 00:44:21 +0100 Subject: [PATCH 13/53] Copypaste error --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1db16412..c74eaba98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,6 @@ option(SRB2_CONFIG_ERRORMODE "Compile C code with warnings treated as errors." O option(SRB2_CONFIG_DEBUGMODE "Compile with PARANOIA, ZDEBUG, RANGECHECK and PACKETDROP defined." OFF) option(SRB2_CONFIG_DEV_BUILD "Compile a development build." OFF) option(SRB2_CONFIG_TESTERS "Compile a build for testers." OFF) -# SRB2_CONFIG_PROFILEMODE is probably superceded by some CMake setting. option(SRB2_CONFIG_MOBJCONSISTANCY "Compile with MOBJCONSISTANCY defined." OFF) option(SRB2_CONFIG_PACKETDROP "Compile with PACKETDROP defined." OFF) option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF) From f63eb31d5b3ce08bf1680477263e45b6d92019e4 Mon Sep 17 00:00:00 2001 From: SteelT Date: Wed, 27 Sep 2023 19:31:00 -0400 Subject: [PATCH 14/53] Remove host-testers configure preset from CMakePresets.json --- CMakePresets.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 4ff081636..5cdf3d1bd 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -33,14 +33,6 @@ "SRB2_CONFIG_TESTERS": "ON" } }, - { - "name": "host-testers", - "description": "Build to use when hosting, to let testers join", - "inherits": "default", - "cacheVariables": { - "SRB2_CONFIG_HOSTTESTERS": "ON" - } - }, { "name": "release", "description": "Build for game's release", From 1ea5b6759ab0023022e11156e8e4c35cf7e4011c Mon Sep 17 00:00:00 2001 From: Lach Date: Fri, 29 Sep 2023 20:23:18 +1000 Subject: [PATCH 15/53] Add screenshake to MT_SPECIALSTAGEBOMB explosions --- src/p_enemy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_enemy.c b/src/p_enemy.c index f874e1f1a..872fa6d5b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13113,6 +13113,7 @@ void A_SpecialStageBombExplode(mobj_t *actor) return; K_SpawnLandMineExplosion(actor, SKINCOLOR_KETCHUP, actor->hitlag); + P_StartQuakeFromMobj(TICRATE/6, 24 * actor->scale, 512 * mapobjectscale, actor); } // A_LightningFollowPlayer: From abf784cc7972e6ee6e6f5fc1c9540a493cc7a130 Mon Sep 17 00:00:00 2001 From: Lach Date: Fri, 29 Sep 2023 20:25:59 +1000 Subject: [PATCH 16/53] Have bots avoid MT_SPECIALSTAGEBOMB --- src/k_botsearch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/k_botsearch.c b/src/k_botsearch.c index e4227f777..bdc7ecf62 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -458,6 +458,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) case MT_BUBBLESHIELDTRAP: case MT_DUELBOMB: case MT_GACHABOM: + case MT_SPECIALSTAGEBOMB: K_AddDodgeObject(thing, side, 20); break; case MT_SHRINK_GUN: From 2bdc05513938b594498edc182de3556bc6b138ae Mon Sep 17 00:00:00 2001 From: Lach Date: Fri, 29 Sep 2023 20:27:13 +1000 Subject: [PATCH 17/53] Scale Chaos Chute objects --- src/k_kart.c | 22 +++++++++++++++++++++- src/p_local.h | 1 + src/p_mobj.c | 24 +++++++++++++++++++----- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 848a7acdc..14ce6f29e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3802,13 +3802,33 @@ void K_RemoveGrowShrink(player_t *player) boolean K_IsBigger(mobj_t *compare, mobj_t *other) { + fixed_t compareScale, otherScale; + if ((compare == NULL || P_MobjWasRemoved(compare) == true) || (other == NULL || P_MobjWasRemoved(other) == true)) { return false; } - return (compare->scale > other->scale + (mapobjectscale / 4)); + if ((compareScale = P_GetMobjDefaultScale(compare)) != FRACUNIT) + { + compareScale = FixedDiv(compare->scale, compareScale); + } + else + { + compareScale = compare->scale; + } + + if ((otherScale = P_GetMobjDefaultScale(other)) != FRACUNIT) + { + otherScale = FixedDiv(other->scale, otherScale); + } + else + { + otherScale = other->scale; + } + + return (compareScale > otherScale + (mapobjectscale / 4)); } static fixed_t K_TumbleZ(mobj_t *mo, fixed_t input) diff --git a/src/p_local.h b/src/p_local.h index 4c6b44449..12e17178f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -256,6 +256,7 @@ mobjtype_t P_GetMobjtype(UINT16 mthingtype); void P_RespawnSpecials(void); +fixed_t P_GetMobjDefaultScale(mobj_t *mobj); mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); void P_CalculatePrecipFloor(precipmobj_t *mobj); diff --git a/src/p_mobj.c b/src/p_mobj.c index 599dd37e8..c3be0bd2f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10496,6 +10496,20 @@ void P_SceneryThinker(mobj_t *mobj) // GAME SPAWN FUNCTIONS // +fixed_t P_GetMobjDefaultScale(mobj_t *mobj) +{ + switch(mobj->type) + { + case MT_SPECIALSTAGEARCH: + return 5*FRACUNIT; + case MT_SPECIALSTAGEBOMB: + return 3*FRACUNIT/4; + default: + break; + } + return FRACUNIT; +} + static void P_DefaultMobjShadowScale(mobj_t *thing) { thing->shadowscale = 0; @@ -10596,6 +10610,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) SINT8 sc = -1; state_t *st; mobj_t *mobj; + fixed_t scale; if (type == MT_NULL) { @@ -10648,13 +10663,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // All mobjs are created at 100% scale. mobj->scale = FRACUNIT; - mobj->destscale = mobj->scale; - mobj->scalespeed = FRACUNIT/12; + mobj->destscale = mapobjectscale; + mobj->scalespeed = mapobjectscale/12; - if (mapobjectscale != FRACUNIT) //&& !(mobj->type == MT_BLACKEGGMAN) + if ((scale = P_GetMobjDefaultScale(mobj)) != FRACUNIT) { - mobj->destscale = mapobjectscale; - mobj->scalespeed = mapobjectscale/12; + mobj->destscale = FixedMul(mobj->destscale, scale); } // Sprite rendering From 18efb35602e2e9e6348b26dc6f722000ce31d0a9 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sat, 30 Sep 2023 16:07:53 -0700 Subject: [PATCH 18/53] SDLSetMode: render immediately after resolution change to avoid 1-frame of texture presented at wrong size --- src/sdl/i_video.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 84af0eed8..bd47a09c6 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -235,6 +235,11 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool SDL_GetWindowSize(window, &width, &height); vid.realwidth = static_cast(width); vid.realheight = static_cast(height); + + if (graphics_started) + { + I_UpdateNoVsync(); + } } static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code) From 2d9d06e2671fdbc8b98545f3a0c30ff2d7db14cf Mon Sep 17 00:00:00 2001 From: "James R." Date: Sat, 30 Sep 2023 16:09:10 -0700 Subject: [PATCH 19/53] Let window be resizable --- src/sdl/i_video.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index bd47a09c6..329b52476 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -506,6 +506,11 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) case SDL_WINDOWEVENT_MOVED: window_x = evt.data1; window_y = evt.data2; + break; + case SDL_WINDOWEVENT_SIZE_CHANGED: + vid.realwidth = evt.data1; + vid.realheight = evt.data2; + break; } if (FOCUSUNION == oldfocus) // No state change @@ -1540,7 +1545,7 @@ INT32 VID_SetMode(INT32 modeNum) static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) { - int flags = 0; + uint32_t flags = SDL_WINDOW_RESIZABLE; if (rendermode == render_none) // dedicated return SDL_TRUE; // Monster Iestyn -- not sure if it really matters what we return here tbh From 37dc1189bb660f262722feadb5292db6941fde5b Mon Sep 17 00:00:00 2001 From: "James R." Date: Sat, 30 Sep 2023 16:38:56 -0700 Subject: [PATCH 20/53] srb2::hwr2::BlitRectPass::set_output: set x/y as well --- src/f_wipe.cpp | 2 +- src/hwr2/blit_rect.cpp | 4 ++-- src/hwr2/blit_rect.hpp | 8 ++++---- src/i_video_common.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 39a7b2aa4..6a8587586 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -432,7 +432,7 @@ void F_WipeEndScreen(void) dst_region.h = std::min(dst_region.h, backbuf_deets.height); rhi->copy_framebuffer_to_texture(ctx, hw_state->wipe_frames.end, dst_region, dst_region); - hw_state->blit_rect->set_output(dst_region.w, dst_region.h, false, true); + hw_state->blit_rect->set_output(0, 0, dst_region.w, dst_region.h, false, true); rhi::TextureDetails start_deets = rhi->get_texture_details(hw_state->wipe_frames.start); hw_state->blit_rect->set_texture(hw_state->wipe_frames.start, start_deets.width, start_deets.height); hw_state->blit_rect->draw(*rhi, ctx); diff --git a/src/hwr2/blit_rect.cpp b/src/hwr2/blit_rect.cpp index a5101e0f0..df3e791bb 100644 --- a/src/hwr2/blit_rect.cpp +++ b/src/hwr2/blit_rect.cpp @@ -100,7 +100,7 @@ void BlitRectPass::transfer(Rhi& rhi, Handle ctx) if (output_correct_aspect_) { aspect = static_cast(texture_width_) / static_cast(texture_height_); - output_aspect = static_cast(output_width_) / static_cast(output_height_); + output_aspect = static_cast(output_position_.w) / static_cast(output_position_.h); } bool taller = aspect > output_aspect; @@ -137,7 +137,7 @@ void BlitRectPass::transfer(Rhi& rhi, Handle ctx) void BlitRectPass::graphics(Rhi& rhi, Handle ctx) { rhi.bind_pipeline(ctx, pipeline_); - rhi.set_viewport(ctx, {0, 0, output_width_, output_height_}); + rhi.set_viewport(ctx, output_position_); rhi.bind_uniform_set(ctx, 0, uniform_sets_[0]); rhi.bind_uniform_set(ctx, 1, uniform_sets_[1]); rhi.bind_binding_set(ctx, binding_set_); diff --git a/src/hwr2/blit_rect.hpp b/src/hwr2/blit_rect.hpp index 014a876bb..f2acd9887 100644 --- a/src/hwr2/blit_rect.hpp +++ b/src/hwr2/blit_rect.hpp @@ -26,8 +26,7 @@ class BlitRectPass uint32_t texture_width_ = 0; uint32_t texture_height_ = 0; rhi::Handle output_; - uint32_t output_width_ = 0; - uint32_t output_height_ = 0; + rhi::Rect output_position_; bool output_correct_aspect_ = false; bool output_flip_ = false; rhi::Handle quad_vbo_; @@ -63,14 +62,15 @@ public: /// @param width texture width /// @param height texture height void set_output( + int32_t x, + int32_t y, uint32_t width, uint32_t height, bool correct_aspect, bool flip ) noexcept { - output_width_ = width; - output_height_ = height; + output_position_ = {x, y, width, height}; output_correct_aspect_ = correct_aspect; output_flip_ = flip; } diff --git a/src/i_video_common.cpp b/src/i_video_common.cpp index 78eecf3fe..b25eee29e 100644 --- a/src/i_video_common.cpp +++ b/src/i_video_common.cpp @@ -329,7 +329,7 @@ void I_FinishUpdate(void) rhi->begin_default_render_pass(ctx, true); // Upscale draw the backbuffer (with postprocessing maybe?) - g_hw_state.blit_rect->set_output(vid.realwidth, vid.realheight, true, true); + g_hw_state.blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true); g_hw_state.blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast(vid.width), static_cast(vid.height)); g_hw_state.blit_rect->draw(*rhi, ctx); rhi->end_render_pass(ctx); From 2ec5d3e6b03240eaf75b7667cbf57148d5639567 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sat, 30 Sep 2023 16:50:41 -0700 Subject: [PATCH 21/53] Add scr_scale, scr_x, scr_y cvars to scale and adjust viewport position --- src/cvars.cpp | 4 ++++ src/i_video_common.cpp | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/cvars.cpp b/src/cvars.cpp index 2dad5faef..5e56394ef 100644 --- a/src/cvars.cpp +++ b/src/cvars.cpp @@ -421,6 +421,10 @@ consvar_t cv_scr_depth = Player("scr_depth", "16 bits").values({{8, "8 bits"}, { consvar_t cv_scr_width = Player("scr_width", "640").values(CV_Unsigned); consvar_t cv_scr_height = Player("scr_height", "400").values(CV_Unsigned); +consvar_t cv_scr_scale = Player("scr_scale", "1.0").floating_point(); +consvar_t cv_scr_x = Player("scr_x", "0.0").floating_point(); +consvar_t cv_scr_y = Player("scr_y", "0.0").floating_point(); + consvar_t cv_seenames = Player("seenames", "On").on_off(); consvar_t cv_shadow = Player("shadow", "On").on_off(); consvar_t cv_shittyscreen = Player("televisionsignal", "Okay").flags(CV_NOSHOWHELP).values({{0, "Okay"}, {1, "Shitty"}, {2, "Extra Shitty"}}).dont_save(); diff --git a/src/i_video_common.cpp b/src/i_video_common.cpp index b25eee29e..29d7eb37f 100644 --- a/src/i_video_common.cpp +++ b/src/i_video_common.cpp @@ -16,8 +16,10 @@ #include #include +#include "command.h" #include "cxxutil.hpp" #include "f_finale.h" +#include "m_fixed.h" #include "m_misc.h" #include "hwr2/hardware_state.hpp" #include "hwr2/patch_atlas.hpp" @@ -46,6 +48,8 @@ #include "st_stuff.h" #include "v_video.h" +extern "C" consvar_t cv_scr_scale, cv_scr_x, cv_scr_y; + using namespace srb2; using namespace srb2::hwr2; using namespace srb2::rhi; @@ -329,7 +333,20 @@ void I_FinishUpdate(void) rhi->begin_default_render_pass(ctx, true); // Upscale draw the backbuffer (with postprocessing maybe?) - g_hw_state.blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true); + if (cv_scr_scale.value != FRACUNIT) + { + float f = std::max(FixedToFloat(cv_scr_scale.value), 0.f); + float w = vid.realwidth * f; + float h = vid.realheight * f; + float x = (vid.realwidth - w) * (0.5f + (FixedToFloat(cv_scr_x.value) * 0.5f)); + float y = (vid.realheight - h) * (0.5f + (FixedToFloat(cv_scr_y.value) * 0.5f)); + + g_hw_state.blit_rect->set_output(x, y, w, h, true, true); + } + else + { + g_hw_state.blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true); + } g_hw_state.blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast(vid.width), static_cast(vid.height)); g_hw_state.blit_rect->draw(*rhi, ctx); rhi->end_render_pass(ctx); From a7382ca9d00e0a29cda15b222d2abdd7974e2bcd Mon Sep 17 00:00:00 2001 From: "James R." Date: Sat, 30 Sep 2023 19:21:53 -0700 Subject: [PATCH 22/53] UpscaleBackbuffer::begin_pass: use separate renderpass to clear framebuffer if texture was recreated Fixes wipes potentially reading invalid data from the framebuffer if the texture was recreated but not yet rendered to. --- src/hwr2/upscale_backbuffer.cpp | 36 ++++++++++++++++++++++----------- src/hwr2/upscale_backbuffer.hpp | 1 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/hwr2/upscale_backbuffer.cpp b/src/hwr2/upscale_backbuffer.cpp index 0d3666e5c..f7e187388 100644 --- a/src/hwr2/upscale_backbuffer.cpp +++ b/src/hwr2/upscale_backbuffer.cpp @@ -37,6 +37,19 @@ void UpscaleBackbuffer::begin_pass(Rhi& rhi, Handle ctx) remake = true; } + auto new_renderpass = [&rhi = rhi](AttachmentLoadOp load_op, AttachmentStoreOp store_op) + { + RenderPassDesc desc {}; + desc.use_depth_stencil = true; + desc.color_load_op = load_op; + desc.color_store_op = store_op; + desc.depth_load_op = load_op; + desc.depth_store_op = store_op; + desc.stencil_load_op = load_op; + desc.stencil_store_op = store_op; + return rhi.create_render_pass(desc); + }; + if (remake) { if (color_) @@ -63,23 +76,22 @@ void UpscaleBackbuffer::begin_pass(Rhi& rhi, Handle ctx) depth_tex.height = vid_height; depth_ = rhi.create_renderbuffer(depth_tex); - } - if (!renderpass_) + if (!renderpass_clear_) + { + renderpass_clear_ = new_renderpass(AttachmentLoadOp::kClear, AttachmentStoreOp::kStore); + } + } + else { - RenderPassDesc desc {}; - desc.use_depth_stencil = true; - desc.color_load_op = AttachmentLoadOp::kLoad; - desc.color_store_op = AttachmentStoreOp::kStore; - desc.depth_load_op = AttachmentLoadOp::kLoad; - desc.depth_store_op = AttachmentStoreOp::kStore; - desc.stencil_load_op = AttachmentLoadOp::kLoad; - desc.stencil_store_op = AttachmentStoreOp::kStore; - renderpass_ = rhi.create_render_pass(desc); + if (!renderpass_) + { + renderpass_ = new_renderpass(AttachmentLoadOp::kLoad, AttachmentStoreOp::kStore); + } } RenderPassBeginInfo begin_info {}; - begin_info.render_pass = renderpass_; + begin_info.render_pass = remake ? renderpass_clear_ : renderpass_; begin_info.clear_color = {0, 0, 0, 1}; begin_info.color_attachment = color_; begin_info.depth_stencil_attachment = depth_; diff --git a/src/hwr2/upscale_backbuffer.hpp b/src/hwr2/upscale_backbuffer.hpp index d7b34a276..0f6903dd1 100644 --- a/src/hwr2/upscale_backbuffer.hpp +++ b/src/hwr2/upscale_backbuffer.hpp @@ -20,6 +20,7 @@ class UpscaleBackbuffer rhi::Handle color_; rhi::Handle depth_; rhi::Handle renderpass_; + rhi::Handle renderpass_clear_; public: UpscaleBackbuffer(); From 7c4bb65380ceccc19ad10a06be41408377dfe40b Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 18:05:51 -0700 Subject: [PATCH 23/53] MT_SUNBEAMPALM_STEM, MT_SUNBEAMPALM_LEAF: add MF_DRAWFROMFARAWAY --- src/info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/info.c b/src/info.c index 0a311d369..ebff6c8f8 100644 --- a/src/info.c +++ b/src/info.c @@ -29376,7 +29376,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING, // flags + MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_DRAWFROMFARAWAY, // flags S_NULL // raisestate }, @@ -29403,7 +29403,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_DRAWFROMFARAWAY, // flags S_NULL // raisestate }, From 2f01c6fa161fa8af16cdbcc1ffd18e525ca52422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustaf=20Alh=C3=A4ll?= Date: Sun, 1 Oct 2023 17:34:13 +0200 Subject: [PATCH 24/53] Avoid branch prediction slowdowns in R_PointOnSide # Conflicts: # src/r_main.c --- src/r_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index 929175e1c..3dc986b4a 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -218,7 +218,7 @@ void ChaseCam4_OnChange(void) // // killough 5/2/98: reformatted // -INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) +INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *restrict node) { if (!node->dx) return x <= node->x ? node->dy > 0 : node->dy < 0; @@ -230,9 +230,10 @@ INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) y -= node->y; // Try to quickly decide by looking at sign bits. - if ((node->dy ^ node->dx ^ x ^ y) < 0) - return (node->dy ^ x) < 0; // (left is negative) - return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x); + // also use a mask to avoid branch prediction + INT32 mask = (node->dy ^ node->dx ^ x ^ y) >> 31; + return (mask & ((node->dy ^ x) < 0)) | // (left is negative) + (~mask & (FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x))); } // killough 5/2/98: reformatted From f13871ddbf58894b830da744d1fe93b7a743790c Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Sep 2023 11:44:55 -0500 Subject: [PATCH 25/53] Conditionally randomize precip height --- src/p_mobj.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 504077f99..984a9bfa8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11640,6 +11640,9 @@ static void P_SpawnPrecipitationAt(fixed_t basex, fixed_t basey) for (j = 0; j < numparticles; j++) { + INT32 floorz; + INT32 ceilingz; + rainmo = P_SpawnPrecipMobj(x, y, z, type); if (randomstates > 0) @@ -11658,8 +11661,19 @@ static void P_SpawnPrecipitationAt(fixed_t basex, fixed_t basey) } } - // Randomly assign a height, now that floorz is set. - rainmo->z = M_RandomRange(rainmo->floorz >> FRACBITS, rainmo->ceilingz >> FRACBITS) << FRACBITS; + floorz = rainmo->floorz >> FRACBITS; + ceilingz = rainmo->ceilingz >> FRACBITS; + + if (floorz < ceilingz) + { + // Randomly assign a height, now that floorz is set. + rainmo->z = M_RandomRange(floorz, ceilingz) << FRACBITS; + } + else + { + // ...except if the floor is above the ceiling. + rainmo->z = ceilingz << FRACBITS; + } } } } From bcd4963f2ee5eb0370f7ec88ce0fc5e457227427 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 15:48:05 -0700 Subject: [PATCH 26/53] Always set starting bumpers in P_SpawnPlayer --- src/k_battle.c | 18 ------------------ src/p_mobj.c | 9 ++------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index 64673953d..8b8918d3d 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -801,24 +801,6 @@ void K_BattleInit(boolean singleplayercontext) battleprisons = true; } - if (gametyperules & GTR_BUMPERS) - { - const INT32 startingHealth = K_BumpersToHealth(K_StartingBumperCount()); - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (players[i].mo) - { - players[i].mo->health = startingHealth; - } - - K_SpawnPlayerBattleBumpers(players+i); - } - } - g_battleufo.due = starttime; g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID(); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 0bcda4ad5..a7e486038 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12090,13 +12090,8 @@ void P_SpawnPlayer(INT32 playernum) if ((gametyperules & GTR_BUMPERS) && !p->spectator) { - // At leveltime == 2, K_TimerInit will get called and reset - // the bumpers to the initial value for the level. - if (leveltime > 2) // Reset those bumpers! - { - mobj->health = K_BumpersToHealth(K_StartingBumperCount()); - K_SpawnPlayerBattleBumpers(p); - } + mobj->health = K_BumpersToHealth(K_StartingBumperCount()); + K_SpawnPlayerBattleBumpers(p); } // Block visuals From d5bac5740969770686b77f0d9f842fab6922465f Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 14:42:26 -0700 Subject: [PATCH 27/53] Ring sting indicator: show for owner player as well --- src/k_kart.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index ceb1dbc7c..17e17169a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7927,8 +7927,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) debtflag->color = player->skincolor; debtflag->fuse = 2; - - debtflag->renderflags = K_GetPlayerDontDrawFlag(player); } if (player->springstars && (leveltime & 1)) From 7b3010c93d520e78511e83a4a959b3071528fab4 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 03:22:30 -0700 Subject: [PATCH 28/53] Fix many instances of splitscreen view number if there are duplicate displayplayers - Avoid iterating displayplayers to find view number and prefer R_GetViewNumber. - Iterate over all matching displayplayers if necessary, instead of stopping at the first match. --- src/g_build_ticcmd.cpp | 10 ++++- src/hardware/hw_main.c | 24 +--------- src/hud/timer.cpp | 3 +- src/k_hud.c | 100 ++++++++++++++++------------------------- src/k_kart.c | 14 +++--- src/k_tally.cpp | 5 ++- src/lua_hudlib.c | 2 +- src/lua_playerlib.c | 1 - src/p_inter.c | 1 - src/p_local.h | 1 - src/p_spec.c | 1 - src/p_telept.c | 3 -- src/p_user.c | 89 +++++++++++++----------------------- src/r_bsp.cpp | 16 +++---- src/r_plane.cpp | 64 ++++++++++++-------------- src/st_stuff.c | 2 +- src/v_video.cpp | 15 ++----- 17 files changed, 133 insertions(+), 218 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index 54f5069af..c12bdd44c 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -206,7 +206,15 @@ class TiccmdBuilder else #endif { - localangle[viewnum] += angleChange; + int p = g_localplayers[forplayer()]; + + for (int i = 0; i <= r_splitscreen; ++i) + { + if (displayplayers[i] == p) + { + localangle[i] += angleChange; + } + } } } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a16c8b447..b8cfc5784 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5398,17 +5398,7 @@ static void HWR_DrawSkyBackground(player_t *player) { FTransform dometransform; const float fpov = FIXED_TO_FLOAT(cv_fov[viewssnum].value+player->fovadd); - postimg_t *type = &postimgtype[0]; - SINT8 i; - - for (i = r_splitscreen; i >= 0; i--) - { - if (player == &players[displayplayers[i]]) - { - type = &postimgtype[i]; - break; - } - } + postimg_t *type = &postimgtype[R_GetViewNumber()]; memset(&dometransform, 0x00, sizeof(FTransform)); @@ -6104,20 +6094,10 @@ INT32 HWR_GetTextureUsed(void) void HWR_DoPostProcessor(player_t *player) { - postimg_t *type = &postimgtype[0]; - SINT8 i; + postimg_t *type = &postimgtype[R_GetViewNumber()]; HWD.pfnUnSetShader(); - for (i = r_splitscreen; i >= 0; i--) - { - if (player == &players[displayplayers[i]]) - { - type = &postimgtype[i]; - break; - } - } - // Armageddon Blast Flash! // Could this even be considered postprocessor? if (player->flashcount) diff --git a/src/hud/timer.cpp b/src/hud/timer.cpp index 12c09d592..7fc7c382c 100644 --- a/src/hud/timer.cpp +++ b/src/hud/timer.cpp @@ -4,6 +4,7 @@ #include "../g_game.h" #include "../k_hud.h" #include "../p_local.h" +#include "../r_fps.h" #include "../v_draw.hpp" using srb2::Draw; @@ -24,7 +25,7 @@ void K_drawKart2PTimestamp(void) { auto get_row = [] { - if (stplyr == &players[displayplayers[0]]) + if (R_GetViewNumber() == 0) { return Draw(286, 31).flags(V_SNAPTOTOP); } diff --git a/src/k_hud.c b/src/k_hud.c index 42773bb77..fa1ad8f8a 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1481,7 +1481,7 @@ static void K_drawKartItem(void) // pain and suffering defined below if (offset) { - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { fx = ITEM_X; fy = ITEM_Y; @@ -1622,7 +1622,7 @@ static void K_drawKartItem(void) { xo++; - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // Flip for P1 and P3 (yes, that's correct) + if (!(R_GetViewNumber() & 1)) // Flip for P1 and P3 (yes, that's correct) { xo -= 62; flip = V_FLIP; @@ -1730,7 +1730,7 @@ static void K_drawKartSlotMachine(void) if (offset) { boxoffx -= 4; - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { fx = ITEM_X + 10; fy = ITEM_Y + 10; @@ -2052,7 +2052,7 @@ static void K_DrawKartPositionNum(UINT8 num) { fx = BASEVIDWIDTH << FRACBITS; - if (stplyr == &players[displayplayers[0]]) + if (R_GetViewNumber() == 0) { // for player 1: display this at the top right, above the minimap. fy = 0; @@ -2071,8 +2071,7 @@ static void K_DrawKartPositionNum(UINT8 num) { fy = BASEVIDHEIGHT << FRACBITS; - if (stplyr == &players[displayplayers[0]] - || stplyr == &players[displayplayers[2]]) + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { // If we are P1 or P3... fx = 0; @@ -2512,7 +2511,7 @@ static void K_drawKartEmeralds(void) if (r_splitscreen < 2) { startx -= 8; - if (r_splitscreen == 1 && stplyr == &players[displayplayers[0]]) + if (r_splitscreen == 1 && R_GetViewNumber() == 0) { starty = 1; } @@ -2522,7 +2521,7 @@ static void K_drawKartEmeralds(void) { xindex = 2; starty -= 15; - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { startx = LAPS_X; splitflags = V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_SPLITSCREEN; @@ -2586,7 +2585,7 @@ static void K_drawKartLaps(void) } else { - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { fx = LAPS_X; fy = LAPS_Y; @@ -2693,7 +2692,7 @@ static void K_drawRingCounter(boolean gametypeinfoshown) } else { - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { fx = LAPS_X; fy = LAPS_Y; @@ -2833,7 +2832,7 @@ static void K_drawKartAccessibilityIcons(boolean gametypeinfoshown, INT32 fx) { fx = LAPS_X+44; fy = LAPS_Y; - if (!(stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]])) // If we are not P1 or P3... + if (R_GetViewNumber() & 1) // If we are not P1 or P3... { splitflags ^= (V_SNAPTOLEFT|V_SNAPTORIGHT); fx = (BASEVIDWIDTH/2) - fx; @@ -2992,7 +2991,7 @@ static void K_drawBlueSphereMeter(boolean gametypeinfoshown) else { xstep = 8; - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { fx = LAPS_X-2; fy = LAPS_Y; @@ -3077,7 +3076,7 @@ static void K_drawKartBumpersOrKarma(void) } else { - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... + if (!(R_GetViewNumber() & 1)) // If we are P1 or P3... { fx = LAPS_X; fy = LAPS_Y; @@ -3704,20 +3703,10 @@ static void K_drawKartNameTags(void) if (result.onScreen == true) { - if (!(demo.playback == true && demo.freecam == true)) + if (!(demo.playback == true && demo.freecam == true) && P_IsDisplayPlayer(ntplayer) && + ntplayer != &players[displayplayers[cnum]]) { - for (j = 0; j <= (unsigned)r_splitscreen; j++) - { - if (ntplayer == &players[displayplayers[j]]) - { - break; - } - } - - if (j <= (unsigned)r_splitscreen && j != cnum) - { - localindicator = j; - } + localindicator = G_PartyPosition(ntplayer - players); } if (localindicator >= 0) @@ -3896,7 +3885,7 @@ static void K_drawKartMinimap(void) // Only draw for the first player // Maybe move this somewhere else where this won't be a concern? - if (stplyr != &players[displayplayers[0]]) + if (R_GetViewNumber() != 0) return; if (specialstageinfo.valid == true) @@ -4431,7 +4420,7 @@ static void K_drawKartFinish(boolean finish) interpx = R_InterpolateFixed(ox, x); - if (r_splitscreen && stplyr == &players[displayplayers[1]]) + if (r_splitscreen && R_GetViewNumber() == 1) interpx = -interpx; V_DrawFixedPatch(interpx + (STCD_X<spectator || !stplyr->mo || (stplyr->mo->renderflags & RF_DONTDRAW)) return; - if (stplyr == &players[displayplayers[1]] && r_splitscreen) - { pn = pnum[1]; tn = turn[1]; dr = drift[1]; } - else if (stplyr == &players[displayplayers[2]] && r_splitscreen > 1) - { pn = pnum[2]; tn = turn[2]; dr = drift[2]; } - else if (stplyr == &players[displayplayers[3]] && r_splitscreen > 2) - { pn = pnum[3]; tn = turn[3]; dr = drift[3]; } - else - { pn = pnum[0]; tn = turn[0]; dr = drift[0]; } + { + UINT8 view = R_GetViewNumber(); + pn = pnum[view]; + tn = turn[view]; + dr = drift[view]; + } if (r_splitscreen) { @@ -4805,14 +4792,12 @@ static void K_drawKartFirstPerson(void) V_DrawFixedPatch(x, y, scale, splitflags, kp_fpview[target], colmap); - if (stplyr == &players[displayplayers[1]] && r_splitscreen) - { pnum[1] = pn; turn[1] = tn; drift[1] = dr; } - else if (stplyr == &players[displayplayers[2]] && r_splitscreen > 1) - { pnum[2] = pn; turn[2] = tn; drift[2] = dr; } - else if (stplyr == &players[displayplayers[3]] && r_splitscreen > 2) - { pnum[3] = pn; turn[3] = tn; drift[3] = dr; } - else - { pnum[0] = pn; turn[0] = tn; drift[0] = dr; } + { + UINT8 view = R_GetViewNumber(); + pnum[view] = pn; + turn[view] = tn; + drift[view] = dr; + } } // doesn't need to ever support 4p @@ -5093,26 +5078,19 @@ static void K_drawMiniPing (void) { UINT32 f = V_SNAPTORIGHT; - UINT8 i; + UINT8 i = R_GetViewNumber(); if (!cv_showping.value) { return; } - for (i = 0; i <= r_splitscreen; i++) + if (r_splitscreen > 1 && !(i & 1)) { - if (stplyr == &players[displayplayers[i]]) - { - if (r_splitscreen > 1 && !(i & 1)) - { - f = V_SNAPTOLEFT; - } - - Draw_party_ping(i, f); - break; - } + f = V_SNAPTOLEFT; } + + Draw_party_ping(i, f); } void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean pressed) @@ -5210,7 +5188,7 @@ static void K_drawDistributionDebugger(void) fixed_t y = -pad; size_t i; - if (stplyr != &players[displayplayers[0]]) // only for p1 + if (R_GetViewNumber() != 0) // only for p1 { return; } @@ -5268,7 +5246,7 @@ static void K_DrawWaypointDebugger(void) if (cv_kartdebugwaypoints.value == 0) return; - if (stplyr != &players[displayplayers[0]]) // only for p1 + if (R_GetViewNumber() != 0) // only for p1 return; if (netgame) @@ -5298,7 +5276,7 @@ static void K_DrawBotDebugger(void) return; } - if (stplyr != &players[displayplayers[0]]) // only for p1 + if (R_GetViewNumber() != 0) // only for p1 { return; } @@ -5368,7 +5346,7 @@ static void K_DrawGPRankDebugger(void) return; } - if (stplyr != &players[displayplayers[0]]) // only for p1 + if (R_GetViewNumber() != 0) // only for p1 { return; } @@ -5425,7 +5403,7 @@ void K_drawKartHUD(void) K_drawKartFirstPerson(); // Draw full screen stuff that turns off the rest of the HUD - if (mapreset && stplyr == &players[displayplayers[0]]) + if (mapreset && R_GetViewNumber() == 0) { K_drawChallengerScreen(); return; diff --git a/src/k_kart.c b/src/k_kart.c index 17e17169a..5fc0d21ce 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -264,13 +264,13 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player) return flag; if (player == &players[displayplayers[0]]) - flag = RF_DONTDRAWP1; - else if (r_splitscreen >= 1 && player == &players[displayplayers[1]]) - flag = RF_DONTDRAWP2; - else if (r_splitscreen >= 2 && player == &players[displayplayers[2]]) - flag = RF_DONTDRAWP3; - else if (r_splitscreen >= 3 && player == &players[displayplayers[3]]) - flag = RF_DONTDRAWP4; + flag |= RF_DONTDRAWP1; + if (r_splitscreen >= 1 && player == &players[displayplayers[1]]) + flag |= RF_DONTDRAWP2; + if (r_splitscreen >= 2 && player == &players[displayplayers[2]]) + flag |= RF_DONTDRAWP3; + if (r_splitscreen >= 3 && player == &players[displayplayers[3]]) + flag |= RF_DONTDRAWP4; return flag; } diff --git a/src/k_tally.cpp b/src/k_tally.cpp index 3e5c16f27..36f5ed0d1 100644 --- a/src/k_tally.cpp +++ b/src/k_tally.cpp @@ -33,6 +33,7 @@ #include "m_easing.h" #include "s_sound.h" #include "st_stuff.h" +#include "r_fps.h" boolean level_tally_t::UseBonuses(void) { @@ -883,14 +884,14 @@ void level_tally_t::Draw(void) SINT8 h_transition_sign = 1; if (r_splitscreen > 1) { - if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) + if (!(R_GetViewNumber() & 1)) { h_transition_sign = -h_transition_sign; } } else if (r_splitscreen > 0) { - if (stplyr == &players[displayplayers[1]]) + if (R_GetViewNumber() == 1) { h_transition_sign = -h_transition_sign; } diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index c5e6c0672..c9c463d4a 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -662,7 +662,7 @@ static int libd_drawOnMinimap(lua_State *L) if (gamestate != GS_LEVEL) return 0; - if (stplyr != &players[displayplayers[0]]) + if (R_GetViewNumber() != 0) return 0; AutomapPic = mapheaderinfo[gamemap-1]->minimapPic; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index c30d0d54d..5816da17b 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -599,7 +599,6 @@ static int player_set(lua_State *L) if (plr == &players[displayplayers[i]]) { localaiming[i] = plr->aiming; - break; } } } diff --git a/src/p_inter.c b/src/p_inter.c index bd09bc19c..05cffdf0e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1439,7 +1439,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (target->player == &players[displayplayers[i]]) { localaiming[i] = 0; - break; } } diff --git a/src/p_local.h b/src/p_local.h index de5030225..a254e332f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -167,7 +167,6 @@ boolean P_IsMachineLocalPlayer(player_t *player); boolean P_IsDisplayPlayer(player_t *player); void P_SetPlayerAngle(player_t *player, angle_t angle); -angle_t P_GetLocalAngle(player_t *player); void P_ForceLocalAngle(player_t *player, angle_t angle); boolean P_PlayerFullbright(player_t *player); diff --git a/src/p_spec.c b/src/p_spec.c index 8a56c4709..599ee327f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2867,7 +2867,6 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha camera[i].z += z; camera[i].subsector = R_PointInSubsector(camera[i].x, camera[i].y); R_RelativeTeleportViewInterpolation(i, x, y, z, 0); - break; } } } diff --git a/src/p_telept.c b/src/p_telept.c index 779c152c4..641e070c7 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -79,7 +79,6 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, if (camera[i].chase) P_ResetCamera(thing->player, &camera[i]); R_ResetViewInterpolation(i + 1); - break; } // don't run in place after a teleport @@ -170,8 +169,6 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle } R_ResetViewInterpolation(1 + i); - - break; } } diff --git a/src/p_user.c b/src/p_user.c index a8f2694bc..98cd2703b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3544,19 +3544,10 @@ boolean P_SpectatorJoinGame(player_t *player) player->enteredGame = true; // Reset away view (some code referenced from Got_Teamchange) + if (G_IsPartyLocal(player - players)) { - UINT8 i = 0; - const UINT8 *localplayertable = G_PartyArray(consoleplayer); - - for (i = 0; i <= r_splitscreen; i++) - { - if (localplayertable[i] == (player-players)) - { - LUA_HookViewpointSwitch(player, player, true); - displayplayers[i] = (player-players); - break; - } - } + LUA_HookViewpointSwitch(player, player, true); + displayplayers[G_PartyPosition(player - players)] = (player-players); } // a surprise tool that will help us later... @@ -3572,11 +3563,11 @@ boolean P_SpectatorJoinGame(player_t *player) } // the below is first person only, if you're curious. check out P_CalcChasePostImg in p_mobj.c for chasecam -static void P_CalcPostImg(player_t *player) +static void P_CalcPostImg(player_t *player, size_t viewnum) { sector_t *sector = player->mo->subsector->sector; - postimg_t *type = NULL; - INT32 *param; + postimg_t *type = &postimgtype[viewnum]; + INT32 *param = &postimgparam[viewnum]; fixed_t pviewheight; size_t i; @@ -3591,16 +3582,6 @@ static void P_CalcPostImg(player_t *player) pviewheight = player->awayview.mobj->z; } - for (i = 0; i <= (unsigned)r_splitscreen; i++) - { - if (player == &players[displayplayers[i]]) - { - type = &postimgtype[i]; - param = &postimgparam[i]; - break; - } - } - // see if we are in heat (no, not THAT kind of heat...) for (i = 0; i < sector->tags.count; i++) { @@ -4400,7 +4381,6 @@ void P_PlayerThink(player_t *player) // void P_PlayerAfterThink(player_t *player) { - camera_t *thiscam = NULL; // if not one of the displayed players, just don't bother UINT8 i; #ifdef PARANOIA @@ -4425,15 +4405,6 @@ void P_PlayerAfterThink(player_t *player) P_PlayerInSpecialSector(player); #endif - for (i = 0; i <= r_splitscreen; i++) - { - if (player == &players[displayplayers[i]]) - { - thiscam = &camera[i]; - break; - } - } - if (player->playerstate == PST_DEAD) { // Followers need handled while dead. @@ -4448,12 +4419,20 @@ void P_PlayerAfterThink(player_t *player) return; } - if (thiscam) { - if (!thiscam->chase) // bob view only if looking through the player's eyes + boolean chase = true; + + for (i = 0; i <= r_splitscreen; i++) + { + if (player == &players[displayplayers[i]] && !camera[i].chase) + { + chase = false; + } + } + + if (!chase) // bob view only if looking through the player's eyes { P_CalcHeight(player); - P_CalcPostImg(player); } else { @@ -4466,6 +4445,14 @@ void P_PlayerAfterThink(player_t *player) else player->viewz = player->mo->z + player->viewheight; } + + for (i = 0; i <= r_splitscreen; i++) + { + if (player == &players[displayplayers[i]] && !camera[i].chase) + { + P_CalcPostImg(player, i); + } + } } // spectator invisibility and nogravity. @@ -4530,10 +4517,15 @@ void P_PlayerAfterThink(player_t *player) K_UpdateBotGameplayVars(player); } - if (thiscam) + for (i = 0; i <= r_splitscreen; i++) { + if (player != &players[displayplayers[i]]) + { + continue; + } + // Store before it gets 0'd out - thiscam->pmomz = player->mo->pmomz; + camera[i].pmomz = player->mo->pmomz; } if (P_IsObjectOnGround(player->mo)) @@ -4632,21 +4624,6 @@ void P_SetPlayerAngle(player_t *player, angle_t angle) player->angleturn = angle; } -angle_t P_GetLocalAngle(player_t *player) -{ - // this function is from vanilla srb2. can you tell? - // (hint: they have separate variables for all of this shit instead of arrays) - UINT8 i; - - for (i = 0; i <= r_splitscreen; i++) - { - if (player == &players[displayplayers[i]]) - return localangle[i]; - } - - return 0; -} - void P_ForceLocalAngle(player_t *player, angle_t angle) { UINT8 i; @@ -4658,8 +4635,6 @@ void P_ForceLocalAngle(player_t *player, angle_t angle) if (player == &players[displayplayers[i]]) { localangle[i] = angle; - - break; } } diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index d89333bb7..f4e11bad4 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -20,6 +20,7 @@ #include "r_local.h" #include "r_state.h" #include "r_portal.h" // Add seg portals +#include "r_fps.h" #include "r_splats.h" #include "p_local.h" // camera @@ -276,18 +277,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, mobj_t *viewmobj = viewplayer->mo; INT32 heightsec; boolean underwater; - UINT8 i; + UINT8 i = R_GetViewNumber(); - for (i = 0; i <= r_splitscreen; i++) - { - if (viewplayer == &players[displayplayers[i]] && camera[i].chase) - { - heightsec = R_PointInSubsector(camera[i].x, camera[i].y)->sector->heightsec; - break; - } - } - - if (i > r_splitscreen && viewmobj) + if (camera[i].chase) + heightsec = R_PointInSubsector(camera[i].x, camera[i].y)->sector->heightsec; + else if (i > r_splitscreen && viewmobj) heightsec = R_PointInSubsector(viewmobj->x, viewmobj->y)->sector->heightsec; else return sec; diff --git a/src/r_plane.cpp b/src/r_plane.cpp index e5e29ea0a..1df08da37 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -20,6 +20,7 @@ #include "g_game.h" #include "p_setup.h" // levelflats #include "p_slopes.h" +#include "r_fps.h" #include "r_data.h" #include "r_textures.h" #include "r_local.h" @@ -963,8 +964,6 @@ void R_DrawSinglePlane(visplane_t *pl) planeripple.active = true; if (spanfunctype == SPANDRAWFUNC_TRANS) { - UINT8 i; - spanfunctype = SPANDRAWFUNC_WATER; // Copy the current scene, ugh @@ -977,43 +976,38 @@ void R_DrawSinglePlane(visplane_t *pl) bottom = viewheight; // Only copy the part of the screen we need - for (i = 0; i <= r_splitscreen; i++) + UINT8 i = R_GetViewNumber(); + INT32 scrx = 0; + INT32 scry = top; + INT32 offset; + + if (r_splitscreen == 1) { - if (viewplayer == &players[displayplayers[i]]) + if (i & 1) { - INT32 scrx = 0; - INT32 scry = top; - INT32 offset; - - if (r_splitscreen == 1) - { - if (i & 1) - { - scry += viewheight; - } - } - else - { - if (i & 1) - { - scrx += viewwidth; - } - - if (i / 2) - { - scry += viewheight; - } - } - - offset = (scry*vid.width) + scrx; - - // No idea if this works - VID_BlitLinearScreen(screens[0] + offset, - screens[1] + (top*vid.width), // intentionally not +offset - viewwidth, bottom-top, - vid.width, vid.width); + scry += viewheight; } } + else + { + if (i & 1) + { + scrx += viewwidth; + } + + if (i / 2) + { + scry += viewheight; + } + } + + offset = (scry*vid.width) + scrx; + + // No idea if this works + VID_BlitLinearScreen(screens[0] + offset, + screens[1] + (top*vid.width), // intentionally not +offset + viewwidth, bottom-top, + vid.width, vid.width); } } #endif diff --git a/src/st_stuff.c b/src/st_stuff.c index 85eb89706..a0dd6e984 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1203,7 +1203,7 @@ static void ST_overlayDrawer(void) { char name[MAXPLAYERNAME+12]; - INT32 y = (stplyr == &players[displayplayers[0]]) ? 4 : BASEVIDHEIGHT/2-12; + INT32 y = (viewnum == 0) ? 4 : BASEVIDHEIGHT/2-12; sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]); V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, name); } diff --git a/src/v_video.cpp b/src/v_video.cpp index e0f2bf791..2aa4067a6 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -27,6 +27,7 @@ #include "f_finale.h" #include "r_draw.h" #include "console.h" +#include "r_fps.h" #include "i_video.h" // rendermode #include "z_zone.h" @@ -513,8 +514,7 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du INT32 screenheight = vid.height; INT32 basewidth = BASEVIDWIDTH * dupx; INT32 baseheight = BASEVIDHEIGHT * dupy; - SINT8 player = -1; - UINT8 i; + SINT8 player = R_GetViewNumber(); if (options & V_SPLITSCREEN) { @@ -531,15 +531,6 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du } } - for (i = 0; i <= r_splitscreen; i++) - { - if (stplyr == &players[displayplayers[i]]) - { - player = i; - break; - } - } - if (vid.width != (BASEVIDWIDTH * dupx)) { if (options & V_SNAPTORIGHT) @@ -586,7 +577,7 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du if (r_splitscreen > 1) { - if (stplyr == &players[displayplayers[1]] || stplyr == &players[displayplayers[3]]) + if (player & 1) slidefromright = true; } From f2cc5ce36a679b4dd715a14b29a340307c0456bd Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 14:29:23 -0700 Subject: [PATCH 29/53] R_ResetViewInterpolation: wait an extra tic if R_UpdateViewInterpolation has not run yet, do not add extra time for subsequent calls --- src/r_fps.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/r_fps.c b/src/r_fps.c index c15a4b632..09c94e2a5 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -22,6 +22,7 @@ #include "r_state.h" #include "z_zone.h" #include "console.h" // con_startup_loadprogress +#include "i_time.h" UINT32 R_GetFramerateCap(void) { @@ -58,6 +59,7 @@ static viewvars_t skyview_old[MAXSPLITSCREENPLAYERS]; static viewvars_t skyview_new[MAXSPLITSCREENPLAYERS]; static viewvars_t *oldview = &pview_old[0]; +static tic_t last_view_update; static int oldview_invalid[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0}; viewvars_t *newview = &pview_new[0]; @@ -165,21 +167,27 @@ void R_UpdateViewInterpolation(void) skyview_old[i] = skyview_new[i]; if (oldview_invalid[i] > 0) oldview_invalid[i]--; } + + last_view_update = I_GetTime(); } void R_ResetViewInterpolation(UINT8 p) { + // Wait an extra tic if the interpolation state hasn't + // updated yet. + int t = last_view_update == I_GetTime() ? 1 : 2; + if (p == 0) { UINT8 i; for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { - oldview_invalid[i]++; + oldview_invalid[i] = t; } } else { - oldview_invalid[p - 1]++; + oldview_invalid[p - 1] = t; } } From d020c9faaa48dbe8a1e74cb867e452c946fc74db Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 14:32:56 -0700 Subject: [PATCH 30/53] Add G_FixCamera, reset camera, angle and view interpolation --- src/g_game.c | 33 ++++++++++++++++++++++----------- src/g_game.h | 1 + src/g_party.cpp | 18 +++--------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 0cce5ff8c..1b582bc7a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1580,7 +1580,6 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) UINT8 viewd; INT32 *displayplayerp; - camera_t *camerap; INT32 olddisplayplayer; INT32 playersviewable; @@ -1631,22 +1630,14 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) (*displayplayerp) = playernum; if ((*displayplayerp) != olddisplayplayer) { - camerap = &camera[viewnum-1]; - P_ResetCamera(&players[(*displayplayerp)], camerap); - - R_ResetViewInterpolation(viewnum); + G_FixCamera(viewnum); } if (viewnum > splits) { for (viewd = splits+1; viewd < viewnum; ++viewd) { - displayplayerp = (&displayplayers[viewd-1]); - camerap = &camera[viewd]; - - (*displayplayerp) = G_FindView(0, viewd, onlyactive, false); - - P_ResetCamera(&players[(*displayplayerp)], camerap); + G_FixCamera(viewd); } } @@ -1708,6 +1699,26 @@ void G_ResetViews(void) } } +// +// G_FixCamera +// Reset camera position, angle and interpolation on a view +// after changing state. +// +void G_FixCamera(UINT8 view) +{ + player_t *player = &players[displayplayers[view - 1]]; + + // The order of displayplayers can change, which would + // invalidate localangle. + localangle[view - 1] = player->angleturn; + + P_ResetCamera(player, &camera[view - 1]); + + // Make sure the viewport doesn't interpolate at all into + // its new position -- just snap instantly into place. + R_ResetViewInterpolation(view); +} + // // G_Ticker // Make ticcmd_ts for the players. diff --git a/src/g_game.h b/src/g_game.h index 885c7a44b..eeda11a79 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -240,6 +240,7 @@ INT32 G_CountPlayersPotentiallyViewable(boolean active); void G_ResetViews(void); void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive); void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive); +void G_FixCamera(UINT8 viewnum); void G_AddPlayer(INT32 playernum); void G_SpectatePlayerOnJoin(INT32 playernum); diff --git a/src/g_party.cpp b/src/g_party.cpp index 2b72d49f0..0caad76b7 100644 --- a/src/g_party.cpp +++ b/src/g_party.cpp @@ -19,7 +19,7 @@ #include "d_clisrv.h" // playerconsole #include "doomdef.h" // MAXPLAYERS #include "doomstat.h" // consoleplayer -#include "g_game.h" // localangle +#include "g_game.h" // G_FixCamera #include "g_party.h" #include "g_state.h" #include "p_local.h" @@ -136,20 +136,8 @@ public: for (std::size_t i = 0; i < size(); ++i) { - const playernum_t player = at(i); - - displayplayers[i] = player; - - // The order of displayplayers can change, which - // would make localangle invalid now. - localangle[i] = players[player].angleturn; - - P_ResetCamera(&players[player], &camera[i]); - - // Make sure the viewport doesn't interpolate at - // all into its new position -- just snap - // instantly into place. - R_ResetViewInterpolation(1 + i); + displayplayers[i] = at(i); + G_FixCamera(1 + i); } r_splitscreen = size() - 1; From 8b79689d8106714fc1370aa6303ff604b331a4ae Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 14:33:58 -0700 Subject: [PATCH 31/53] Add K_DirectorIsAvailable Fixes director not working correctly if there are duplicates in displayplayers. --- src/g_build_ticcmd.cpp | 2 +- src/k_director.c | 7 +++++++ src/k_director.h | 1 + src/k_hud.c | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/g_build_ticcmd.cpp b/src/g_build_ticcmd.cpp index c12bdd44c..b81c205e4 100644 --- a/src/g_build_ticcmd.cpp +++ b/src/g_build_ticcmd.cpp @@ -245,7 +245,7 @@ class TiccmdBuilder bool director_input() { - if (demo.freecam || G_IsPartyLocal(displayplayers[forplayer()]) == true) + if (demo.freecam || !K_DirectorIsAvailable(viewnum)) { return false; } diff --git a/src/k_director.c b/src/k_director.c index dd2f55ad6..d2d82212c 100644 --- a/src/k_director.c +++ b/src/k_director.c @@ -11,6 +11,7 @@ #include "k_director.h" #include "d_netcmd.h" #include "p_local.h" +#include "g_party.h" #define SWITCHTIME TICRATE * 5 // cooldown between unforced switches #define BOREDOMTIME 3 * TICRATE / 2 // how long until players considered far apart? @@ -322,3 +323,9 @@ void K_ToggleDirector(boolean active) directorinfo.active = active; } + +boolean K_DirectorIsAvailable(UINT8 viewnum) +{ + return viewnum <= r_splitscreen && viewnum < G_PartySize(consoleplayer) && + displayplayers[viewnum] != G_PartyMember(consoleplayer, viewnum); +} diff --git a/src/k_director.h b/src/k_director.h index 47b4b2265..297bff72e 100644 --- a/src/k_director.h +++ b/src/k_director.h @@ -28,6 +28,7 @@ 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); +boolean K_DirectorIsAvailable(UINT8 viewnum); #ifdef __cplusplus } // extern "C" diff --git a/src/k_hud.c b/src/k_hud.c index fa1ad8f8a..5e69f380a 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5618,7 +5618,7 @@ void K_drawKartHUD(void) K_drawKartPowerUps(); - if (G_IsPartyLocal(displayplayers[viewnum]) == false) + if (K_DirectorIsAvailable(viewnum) == true) { K_drawDirectorHUD(); } From 90d8a9643f76e89432e51123b744b28e1c9c4aec Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 14:46:38 -0700 Subject: [PATCH 32/53] G_CanView: unconditionally let view a player already viewed on a different splitscreen --- src/g_game.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 1b582bc7a..f6587e492 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1507,13 +1507,15 @@ boolean G_CouldView(INT32 playernum) // boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive) { + if (!playeringame[playernum] || players[playernum].spectator) + { + return false; + } + UINT8 splits; UINT8 viewd; INT32 *displayplayerp; - if (!(onlyactive ? G_CouldView(playernum) : (playeringame[playernum] && !players[playernum].spectator))) - return false; - splits = r_splitscreen+1; if (viewnum > splits) viewnum = splits; @@ -1522,15 +1524,18 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive) { displayplayerp = (&displayplayers[viewd-1]); if ((*displayplayerp) == playernum) - return false; + return true; } for (viewd = viewnum + 1; viewd <= splits; ++viewd) { displayplayerp = (&displayplayers[viewd-1]); if ((*displayplayerp) == playernum) - return false; + return true; } + if (onlyactive && !G_CouldView(playernum)) + return false; + return true; } From 454850d3492a8e374edb87f297df696544b03661 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 17:53:34 -0700 Subject: [PATCH 33/53] ST_CalculateFadeIn: do not interpolate at very beginning or end of fade --- src/st_stuff.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index a0dd6e984..153e2a48b 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1451,8 +1451,15 @@ static fixed_t ST_CalculateFadeIn(player_t *player) if (player->tally.hudSlide != 0) { tic_t timer = length - player->tally.hudSlide; + fixed_t f = timer * FRACUNIT; - return ((timer * FRACUNIT) + (FRACUNIT - rendertimefrac)) / length; + // Not interpolated at very beginning or end + if (timer > 0 && timer < length) + { + f += FRACUNIT - rendertimefrac; + } + + return f / length; } tic_t timer = lt_exitticker; @@ -1467,9 +1474,18 @@ static fixed_t ST_CalculateFadeIn(player_t *player) if (timer < length) { - return ((timer * FRACUNIT) + rendertimefrac) / length; + fixed_t f = timer * FRACUNIT; + + // Not interpolated at very beginning + if (timer > 0) + { + f += rendertimefrac; + } + + return f / length; } + // Not interpolated at very end return FRACUNIT; } From 36bbf08ab0df8cea99436d306f220d4268c14d6a Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 15:16:29 -0700 Subject: [PATCH 34/53] HUD: fix alignment of 2P level timer and power-ups --- src/hud/powerup.cpp | 4 ++-- src/hud/timer.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hud/powerup.cpp b/src/hud/powerup.cpp index dfdabca15..d4cf264bc 100644 --- a/src/hud/powerup.cpp +++ b/src/hud/powerup.cpp @@ -90,10 +90,10 @@ void K_drawKartPowerUps(void) switch (r_splitscreen) { case 0: - return { make_drawer(307, 55, Draw::Font::kZVote), "PWRU", -17, 7, -35, -1 }; + return { make_drawer(307, 58, Draw::Font::kZVote), "PWRU", -17, 7, -35, -1 }; case 1: - return { make_drawer(318, viewnum == 0 ? 55 : 155, Draw::Font::kPing), "PWRS", -9, 6, -19, -1 }; + return { make_drawer(318, viewnum == 0 ? 58 : 147, Draw::Font::kPing), "PWRS", -9, 6, -19, -1 }; } // 3/4P diff --git a/src/hud/timer.cpp b/src/hud/timer.cpp index 7fc7c382c..98456e8dd 100644 --- a/src/hud/timer.cpp +++ b/src/hud/timer.cpp @@ -27,11 +27,11 @@ void K_drawKart2PTimestamp(void) { if (R_GetViewNumber() == 0) { - return Draw(286, 31).flags(V_SNAPTOTOP); + return Draw(287, 33).flags(V_SNAPTOTOP); } else { - return Draw(286, 163).flags(V_SNAPTOBOTTOM); + return Draw(287, 156).flags(V_SNAPTOBOTTOM); } }; From da2f083e2c6fd15aca61b4782f15475d67c85b6c Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 17:42:06 -0700 Subject: [PATCH 35/53] HUD: fit bumpers, prisons, spheres, speedometer, rankings, item box HUD without overlapping --- src/k_hud.c | 68 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 5e69f380a..dcb4a9763 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1507,6 +1507,11 @@ static void K_drawKartItem(void) fflags = V_SNAPTOTOP|V_SNAPTOLEFT|V_SPLITSCREEN; } + if (r_splitscreen == 1) + { + fy -= 5; + } + V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg); // Need to draw these in a particular order, for sorting. @@ -1759,6 +1764,11 @@ static void K_drawKartSlotMachine(void) fflags = V_SNAPTOTOP|V_SNAPTOLEFT|V_SPLITSCREEN; } + if (r_splitscreen == 1) + { + fy -= 5; + } + V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg); V_SetClipRect( @@ -2903,6 +2913,11 @@ static void K_drawKartSpeedometer(boolean gametypeinfoshown) INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN; INT32 fy = LAPS_Y-14; + if (battleprisons) + { + fy -= 2; + } + if (!stplyr->exiting) // Keep the same speed value as when you crossed the finish line! { switch (cv_kartspeedometer.value) @@ -2975,7 +2990,23 @@ static void K_drawBlueSphereMeter(boolean gametypeinfoshown) if (r_splitscreen < 2) // don't change shit for THIS splitscreen. { fx = LAPS_X; - fy = LAPS_Y-7; + fy = LAPS_Y-4; + + if (battleprisons) + { + if (r_splitscreen == 1) + { + fy -= 8; + } + else + { + fy -= 5; + } + } + else if (r_splitscreen == 1) + { + fy -= 5; + } if (gametypeinfoshown) { @@ -3005,6 +3036,11 @@ static void K_drawBlueSphereMeter(boolean gametypeinfoshown) xstep = -xstep; } + if (battleprisons) + { + fy -= 5; + } + if (gametypeinfoshown) { fy -= 16; @@ -3092,11 +3128,14 @@ static void K_drawKartBumpersOrKarma(void) } V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|V_SLIDEIN|splitflags|flipflag, kp_ringstickersplit[0]); + + fx += 2; + V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|V_SLIDEIN|splitflags, frameslash); if (battleprisons) { - V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankcapsule, NULL); + V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankcapsule, NULL); if (numtargets > 9 || maptargets > 9) { @@ -3124,7 +3163,7 @@ static void K_drawKartBumpersOrKarma(void) const INT32 maxbumper = K_StartingBumperCount(); const UINT8 bumpers = K_Bumpers(stplyr); - V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap); + V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap); if (bumpers > 9 || maxbumper > 9) { @@ -3150,25 +3189,32 @@ static void K_drawKartBumpersOrKarma(void) } else { + INT32 fy = r_splitscreen == 1 ? LAPS_Y-3 : LAPS_Y; + if (battleprisons) { if (numtargets > 9 && maptargets > 9) - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulestickerwide, NULL); + V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulestickerwide, NULL); else - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulesticker, NULL); - V_DrawTimerString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", numtargets, maptargets)); + V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulesticker, NULL); + V_DrawTimerString(LAPS_X+47, fy+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", numtargets, maptargets)); } else { const INT32 maxbumper = K_StartingBumperCount(); const UINT8 bumpers = K_Bumpers(stplyr); - if (bumpers > 9 && maxbumper > 9) - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap); - else - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap); + if (r_splitscreen == 0) + { + fy += 2; + } - V_DrawTimerString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", bumpers, maxbumper)); + if (bumpers > 9 && maxbumper > 9) + V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap); + else + V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap); + + V_DrawTimerString(LAPS_X+47, fy+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", bumpers, maxbumper)); } } } From 4631af55c4628d5c12f83f98f7bbdf0f9c34fad2 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 17:44:40 -0700 Subject: [PATCH 36/53] HUD: do not include starting Battle Bumper count, "x/y" -> "x" - 1P/2P: - Resize sticker with number of digits - 3P/4P: - Pad to 2 digits - Use larger font --- src/k_hud.c | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index dcb4a9763..c16b7b1a7 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -100,6 +100,7 @@ static patch_t *kp_speedometersticker; static patch_t *kp_speedometerlabel[4]; static patch_t *kp_rankbumper; +static patch_t *kp_bigbumper; static patch_t *kp_tinybumper[2]; static patch_t *kp_ranknobumpers; static patch_t *kp_rankcapsule; @@ -439,6 +440,7 @@ void K_LoadKartHUDGraphics(void) // Extra ranking icons HU_UpdatePatch(&kp_rankbumper, "K_BLNICO"); + HU_UpdatePatch(&kp_bigbumper, "K_BLNBIG"); HU_UpdatePatch(&kp_tinybumper[0], "K_BLNA"); HU_UpdatePatch(&kp_tinybumper[1], "K_BLNB"); HU_UpdatePatch(&kp_ranknobumpers, "K_NOBLNS"); @@ -3131,10 +3133,9 @@ static void K_drawKartBumpersOrKarma(void) fx += 2; - V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|V_SLIDEIN|splitflags, frameslash); - if (battleprisons) { + V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|V_SLIDEIN|splitflags, frameslash); V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankcapsule, NULL); if (numtargets > 9 || maptargets > 9) @@ -3160,31 +3161,16 @@ static void K_drawKartBumpersOrKarma(void) } else { - const INT32 maxbumper = K_StartingBumperCount(); const UINT8 bumpers = K_Bumpers(stplyr); V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap); - if (bumpers > 9 || maxbumper > 9) - { - UINT8 ln[2]; - ln[0] = (bumpers / 10 % 10); - ln[1] = (bumpers % 10); + UINT8 ln[2]; + ln[0] = (bumpers / 10 % 10); + ln[1] = (bumpers % 10); - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); - V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); - - ln[0] = ((abs(maxbumper) / 10) % 10); - ln[1] = (abs(maxbumper) % 10); - - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); - V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); - } - else - { - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(bumpers) % 10]); - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(maxbumper) % 10]); - } + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[ln[0]]); + V_DrawScaledPatch(fx+19, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[ln[1]]); } } else @@ -3201,7 +3187,6 @@ static void K_drawKartBumpersOrKarma(void) } else { - const INT32 maxbumper = K_StartingBumperCount(); const UINT8 bumpers = K_Bumpers(stplyr); if (r_splitscreen == 0) @@ -3209,12 +3194,9 @@ static void K_drawKartBumpersOrKarma(void) fy += 2; } - if (bumpers > 9 && maxbumper > 9) - V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap); - else - V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap); - - V_DrawTimerString(LAPS_X+47, fy+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", bumpers, maxbumper)); + K_DrawSticker(LAPS_X+12, fy+5, bumpers > 9 ? 64 : 52, V_HUDTRANS|V_SLIDEIN|splitflags, false); + V_DrawMappedPatch(LAPS_X+15, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bigbumper, colormap); + V_DrawTimerString(LAPS_X+47, fy+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d", bumpers)); } } } From bf20db1e5e1f1a7ef702e5b7383343a583741ad5 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 17:44:58 -0700 Subject: [PATCH 37/53] HUD: draw item box over everything else --- src/k_hud.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index c16b7b1a7..40164b612 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5461,19 +5461,6 @@ void K_drawKartHUD(void) K_drawKartMinimap(); } - // Draw the item window - if (LUA_HudEnabled(hud_item) && !freecam) - { - if (stplyr->itemRoulette.ringbox && stplyr->itemamount == 0 && stplyr->itemtype == 0) - { - K_drawKartSlotMachine(); - } - else - { - K_drawKartItem(); - } - } - if (demo.title) ; else if (!r_splitscreen) @@ -5587,6 +5574,19 @@ void K_drawKartHUD(void) if (LUA_HudEnabled(hud_position)) K_drawInput(); } + + // Draw the item window + if (LUA_HudEnabled(hud_item) && !freecam) + { + if (stplyr->itemRoulette.ringbox && stplyr->itemamount == 0 && stplyr->itemtype == 0) + { + K_drawKartSlotMachine(); + } + else + { + K_drawKartItem(); + } + } } } From f426a136d57a30cbc09cb21eb2b6a4e44712fac1 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 20:31:17 -0700 Subject: [PATCH 38/53] HUD: fix 4P position numbers --- src/k_hud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 40164b612..ded8b5f07 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2139,7 +2139,7 @@ static void K_DrawKartPositionNum(UINT8 num) color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM, GTC_CACHE); } - if ((fflags & V_SNAPTORIGHT) == 0 && num > 9) + if ((fflags & V_SNAPTORIGHT) == 0) { const UINT8 splitIndex = (r_splitscreen > 0) ? 1 : 0; UINT8 adjustNum = num; From a8d0bad4b00e9dc22b3324dfd091abfbcd350a53 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 20:31:38 -0700 Subject: [PATCH 39/53] HUD: slide in position numbers if race starts immediately --- src/k_hud.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/k_hud.c b/src/k_hud.c index ded8b5f07..c5fb3c5e1 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2109,6 +2109,8 @@ static void K_DrawKartPositionNum(UINT8 num) fflags |= (trans << V_ALPHASHIFT); } + fflags |= V_SLIDEIN; + if (stplyr->exiting && num == 1) { // 1st place winner? You get rainbows!! From 54f2882bc9a53286b7e600b9d3e8f43011615f3f Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 20:31:57 -0700 Subject: [PATCH 40/53] HUD: fix 4P negative ring counter alignment --- src/k_hud.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index c5fb3c5e1..b0d16ade6 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2741,10 +2741,16 @@ static void K_drawRingCounter(boolean gametypeinfoshown) V_DrawMappedPatch(fr+ringx, fy-3, V_HUDTRANS|V_SLIDEIN|splitflags|ringflip, kp_smallring[ringanim_realframe], (colorring ? ringmap : NULL)); if (stplyr->hudrings < 0) // Draw the minus for ring debt - V_DrawMappedPatch(fr+7, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminussmall, ringmap); - - V_DrawMappedPatch(fr+11, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[0]], ringmap); - V_DrawMappedPatch(fr+15, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[1]], ringmap); + { + V_DrawMappedPatch(fr+11, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminussmall, ringmap); + V_DrawMappedPatch(fr+15, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[0]], ringmap); + V_DrawMappedPatch(fr+19, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[1]], ringmap); + } + else + { + V_DrawMappedPatch(fr+11, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[0]], ringmap); + V_DrawMappedPatch(fr+15, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[1]], ringmap); + } // SPB ring lock if (stplyr->pflags & PF_RINGLOCK) From 1935fdcdc38212561ffbfdde270c39311499220a Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 21:13:10 -0700 Subject: [PATCH 41/53] HUD: remove fade in from ping counters --- src/k_hud.c | 2 +- src/screen.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index b0d16ade6..b58718891 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5107,7 +5107,7 @@ void K_drawKartFreePlay(void) static void Draw_party_ping (int ss, INT32 snap) { - HU_drawMiniPing(0, 0, playerpingtable[displayplayers[ss]], V_HUDTRANS|V_SPLITSCREEN|V_SNAPTOTOP|snap); + HU_drawMiniPing(0, 0, playerpingtable[displayplayers[ss]], V_SPLITSCREEN|V_SNAPTOTOP|snap); } static void diff --git a/src/screen.c b/src/screen.c index 3cfb86f3f..cf03eadeb 100644 --- a/src/screen.c +++ b/src/screen.c @@ -578,7 +578,7 @@ void SCR_DisplayLocalPing(void) { INT32 dispy = cv_ticrate.value ? 160 : 181; offline = (consoleplayer == serverplayer); - HU_drawPing(307 * FRACUNIT, dispy * FRACUNIT, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS, offline, 0); + HU_drawPing(307 * FRACUNIT, dispy * FRACUNIT, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM, offline, 0); } } From 56775e721f3de3f9a8f73b2ea9fb68d6c9aae7e4 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 21:56:09 -0700 Subject: [PATCH 42/53] HUD: fix FREE PLAY 4P position Centered at bottom of each screen. --- src/k_hud.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index b58718891..f14b42bfa 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5081,23 +5081,26 @@ void K_drawKartFreePlay(void) if (((leveltime-lt_endtime) % TICRATE) < TICRATE/2) return; - const fixed_t x = ((BASEVIDWIDTH - (LAPS_X+6)) * FRACUNIT) - \ - V_StringScaledWidth( + INT32 h_snap = (r_splitscreen < 2 || R_GetViewNumber() & 1) ? V_SNAPTORIGHT : V_SNAPTOLEFT; + fixed_t x = ((r_splitscreen > 1 ? BASEVIDWIDTH/4 : BASEVIDWIDTH - (LAPS_X+6)) * FRACUNIT); + fixed_t y = ((r_splitscreen ? BASEVIDHEIGHT/2 : BASEVIDHEIGHT) - 20) * FRACUNIT; + + x -= V_StringScaledWidth( FRACUNIT, FRACUNIT, FRACUNIT, - V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, + V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|h_snap|V_SPLITSCREEN, KART_FONT, "FREE PLAY" - ); + ) / (r_splitscreen > 1 ? 2 : 1); V_DrawStringScaled( x, - (LAPS_Y+3) * FRACUNIT, + y, FRACUNIT, FRACUNIT, FRACUNIT, - V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, + V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|h_snap|V_SPLITSCREEN, NULL, KART_FONT, "FREE PLAY" From a11e8d793ac398f1b06714ea3dc18a78a9e2bb29 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sat, 30 Sep 2023 21:30:28 -0700 Subject: [PATCH 43/53] finish_legacy_ogl_update: merge with temp_legacy_finishupdate_draws, draw avrecorder stats in opengl --- src/i_video_common.cpp | 64 ++++++------------------------------------ 1 file changed, 8 insertions(+), 56 deletions(-) diff --git a/src/i_video_common.cpp b/src/i_video_common.cpp index 29d7eb37f..84241491a 100644 --- a/src/i_video_common.cpp +++ b/src/i_video_common.cpp @@ -107,62 +107,6 @@ static void postframe_update(Rhi& rhi) g_hw_state.palette_manager->destroy_per_frame_resources(rhi); } -#ifdef HWRENDER -static void finish_legacy_ogl_update() -{ - int player; - - SCR_CalculateFPS(); - - if (st_overlay) - { - if (cv_songcredits.value) - HU_DrawSongCredits(); - - if (cv_ticrate.value) - SCR_DisplayTicRate(); - - if (cv_showping.value && netgame && (consoleplayer != serverplayer || !server_lagless)) - { - if (server_lagless) - { - if (consoleplayer != serverplayer) - SCR_DisplayLocalPing(); - } - else - { - for (player = 1; player < MAXPLAYERS; player++) - { - if (D_IsPlayerHumanAndGaming(player)) - { - SCR_DisplayLocalPing(); - break; - } - } - } - } - if (cv_mindelay.value && consoleplayer == serverplayer && Playing()) - SCR_DisplayLocalPing(); - } - - if (marathonmode) - SCR_DisplayMarathonInfo(); - - // draw captions if enabled - if (cv_closedcaptioning.value) - SCR_ClosedCaptions(); - -#ifdef HAVE_DISCORDRPC - if (discordRequestList != NULL) - ST_AskToJoinEnvelope(); -#endif - - ST_drawDebugInfo(); - - OglSdlFinishUpdate(cv_vidwait.value); -} -#endif - static void temp_legacy_finishupdate_draws() { SCR_CalculateFPS(); @@ -215,6 +159,14 @@ static void temp_legacy_finishupdate_draws() ST_drawDebugInfo(); } +#ifdef HWRENDER +static void finish_legacy_ogl_update() +{ + temp_legacy_finishupdate_draws(); + OglSdlFinishUpdate(cv_vidwait.value); +} +#endif + static void new_twodee_frame() { g_2d = Twodee(); From dd1b0255f89a210f56dff98c5e4eadad56c45dfa Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 00:49:01 -0700 Subject: [PATCH 44/53] SCR_DisplayTicRate: do not say "FPS" Obscurs less of the position number in splitscreen. --- src/screen.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/screen.c b/src/screen.c index cf03eadeb..0877ba655 100644 --- a/src/screen.c +++ b/src/screen.c @@ -535,9 +535,6 @@ void SCR_DisplayTicRate(void) INT32 x = 318; double fps = round(averageFPS); - // draw "FPS" - V_DrawFixedPatch(306< (benchmark * 0.9)) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE); else if (fps < (benchmark * 0.5)) From 989ee48ef857ff77c2f7edc29b75f2a7e61f119a Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 21:14:05 -0700 Subject: [PATCH 45/53] SCR_DisplayLocalPing: show, even in splitscreen, in gamestates where player HUD is not drawn or when menu is opened --- src/screen.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/screen.c b/src/screen.c index 0877ba655..855a78be5 100644 --- a/src/screen.c +++ b/src/screen.c @@ -568,15 +568,28 @@ void SCR_DisplayTicRate(void) void SCR_DisplayLocalPing(void) { - boolean offline; - - UINT32 ping = playerpingtable[consoleplayer]; // consoleplayer's ping is everyone's ping in a splitnetgame :P - if (! r_splitscreen && ( cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping) )) // only show 2 (warning) if our ping is at a bad level + // Splitscreen party has its own ping counter, but show the + // 1P version anyway in some cases: + // - On intermission, vote, etc. gamestates where the player + // HUD is not drawn. + // - If the menu is opened, since it draws over the player + // HUD. + if (r_splitscreen && gamestate == GS_LEVEL && !menuactive) { - INT32 dispy = cv_ticrate.value ? 160 : 181; - offline = (consoleplayer == serverplayer); - HU_drawPing(307 * FRACUNIT, dispy * FRACUNIT, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM, offline, 0); + return; } + + UINT32 ping = playerpingtable[consoleplayer]; + + if (cv_showping.value == 2 && ping <= servermaxping) // only show 2 (warning) if our ping is at a bad level + { + return; + } + + INT32 dispy = cv_ticrate.value ? 160 : 181; + boolean offline = (consoleplayer == serverplayer); + + HU_drawPing(307 * FRACUNIT, dispy * FRACUNIT, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM, offline, 0); } From 0b7a6ed7f5cfadd122285188d7c7fd1104063028 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 22:09:28 -0700 Subject: [PATCH 46/53] P_DemoCameraMovement: use splitscreen ticcmd --- src/p_local.h | 2 +- src/p_user.c | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index a254e332f..15b338f9d 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -154,7 +154,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount); void P_ResetCamera(player_t *player, camera_t *thiscam); boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam); -void P_DemoCameraMovement(camera_t *cam); +void P_DemoCameraMovement(camera_t *cam, UINT8 num); boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled); void P_ToggleDemoCamera(void); diff --git a/src/p_user.c b/src/p_user.c index 98cd2703b..122a8964e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2887,7 +2887,7 @@ fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42}; struct demofreecam_s democam; -void P_DemoCameraMovement(camera_t *cam) +void P_DemoCameraMovement(camera_t *cam, UINT8 num) { ticcmd_t *cmd; angle_t thrustangle; @@ -2897,7 +2897,7 @@ void P_DemoCameraMovement(camera_t *cam) boolean moving = false; // first off we need to get button input - cmd = D_LocalTiccmd(0); + cmd = D_LocalTiccmd(num); if (cmd->aiming != 0) { @@ -3083,18 +3083,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (thiscam->subsector == NULL || thiscam->subsector->sector == NULL) return true; - if (demo.freecam || player->spectator) - { - P_DemoCameraMovement(thiscam); - return true; - } - - if (paused || P_AutoPause()) - return true; - - playerScale = FixedDiv(player->mo->scale, mapobjectscale); - scaleDiff = playerScale - FRACUNIT; - if (thiscam == &camera[1]) // Camera 2 { num = 1; @@ -3112,6 +3100,18 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall num = 0; } + if (demo.freecam || player->spectator) + { + P_DemoCameraMovement(thiscam, num); + return true; + } + + if (paused || P_AutoPause()) + return true; + + playerScale = FixedDiv(player->mo->scale, mapobjectscale); + scaleDiff = playerScale - FRACUNIT; + mo = player->mo; if (P_MobjIsFrozen(mo) || player->playerstate == PST_DEAD) From ff11166f30c908b450637587fc0f6e290f4c9aaa Mon Sep 17 00:00:00 2001 From: "James R." Date: Sat, 30 Sep 2023 21:23:44 -0700 Subject: [PATCH 47/53] setviews command: let outside of replays --- src/d_netcmd.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index d8601f665..1e91d4480 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1710,13 +1710,6 @@ static void Command_SetViews_f(void) UINT8 splits; UINT8 newsplits; - if (!( demo.playback && multiplayer )) - { - CONS_Alert(CONS_NOTICE, - "You must be viewing a multiplayer replay to use this.\n"); - return; - } - if (COM_Argc() != 2) { CONS_Printf("setviews : set the number of split screens\n"); @@ -1727,12 +1720,26 @@ static void Command_SetViews_f(void) newsplits = atoi(COM_Argv(1)); newsplits = min(max(newsplits, 1), 4); - if (newsplits > splits) + + if (newsplits > splits && demo.playback && multiplayer) + { G_AdjustView(newsplits, 0, true); + } else { + // Even if the splits go beyond the real number of + // splitscreen players, displayplayers was filled + // with duplicates of P1 (see Got_AddPlayer). r_splitscreen = newsplits-1; R_ExecuteSetViewSize(); + + // If promoting (outside of replays), make sure the + // camera is in the correct position. + UINT8 i; + for (i = splits + 1; i <= newsplits; ++i) + { + G_FixCamera(i); + } } } From 62503b244a8e46738293cfab9a87d706dc44de31 Mon Sep 17 00:00:00 2001 From: "James R." Date: Sun, 1 Oct 2023 15:29:34 -0700 Subject: [PATCH 48/53] Add give2, give3, give4 commands --- src/d_netcmd.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1e91d4480..e5f461985 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -419,6 +419,9 @@ void D_RegisterServerCommands(void) COM_AddDebugCommand("downloads", Command_Downloads_f); COM_AddDebugCommand("give", Command_KartGiveItem_f); + COM_AddDebugCommand("give2", Command_KartGiveItem_f); + COM_AddDebugCommand("give3", Command_KartGiveItem_f); + COM_AddDebugCommand("give4", Command_KartGiveItem_f); COM_AddCommand("schedule_add", Command_Schedule_Add); COM_AddCommand("schedule_clear", Command_Schedule_Clear); @@ -1606,6 +1609,22 @@ static void GetViewablePlayerPlaceRange(INT32 *first, INT32 *last) } } +static int GetCommandViewNumber(void) +{ + char c = COM_Argv(0)[strlen(COM_Argv(0))-1];/* may be digit */ + + switch (c) + { + default: + return 0; + + case '2': + case '3': + case '4': + return c - '1'; + } +} + #define PRINTVIEWPOINT( pre,suf ) \ CONS_Printf(pre"viewing \x84(%d) \x83%s\x80"suf".\n",\ (*displayplayerp), player_names[(*displayplayerp)]); @@ -1613,21 +1632,11 @@ static void Command_View_f(void) { INT32 *displayplayerp; INT32 olddisplayplayer; - int viewnum; + int viewnum = 1 + GetCommandViewNumber(); const char *playerparam; INT32 placenum; INT32 playernum; INT32 firstplace, lastplace; - char c; - /* easy peasy */ - c = COM_Argv(0)[strlen(COM_Argv(0))-1];/* may be digit */ - switch (c) - { - case '2': viewnum = 2; break; - case '3': viewnum = 3; break; - case '4': viewnum = 4; break; - default: viewnum = 1; - } if (viewnum > 1 && !( multiplayer && demo.playback )) { @@ -5924,6 +5933,8 @@ static void Command_Archivetest_f(void) */ static void Command_KartGiveItem_f(void) { + UINT8 localplayer = g_localplayers[GetCommandViewNumber()]; + int ac; const char *name; INT32 item; @@ -5979,7 +5990,7 @@ static void Command_KartGiveItem_f(void) else amt = BATTLE_POWERUP_TIME; - D_Cheat(consoleplayer, CHEAT_GIVEPOWERUP, item, amt); + D_Cheat(localplayer, CHEAT_GIVEPOWERUP, item, amt); } else if (item < NUMKARTITEMS) { @@ -5990,7 +6001,7 @@ static void Command_KartGiveItem_f(void) else amt = (item != KITEM_NONE);/* default to one quantity, or zero, if KITEM_NONE */ - D_Cheat(consoleplayer, CHEAT_GIVEITEM, item, amt); + D_Cheat(localplayer, CHEAT_GIVEITEM, item, amt); } else { From 8284aff4f1dea7084af75dd4170c7a1ad053a526 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Oct 2023 21:22:46 -0700 Subject: [PATCH 49/53] HUD: realign 1P ping counter and FPS counter positions --- src/screen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/screen.c b/src/screen.c index 855a78be5..0e4bbb109 100644 --- a/src/screen.c +++ b/src/screen.c @@ -532,7 +532,7 @@ void SCR_DisplayTicRate(void) const UINT8 *ticcntcolor = NULL; UINT32 cap = R_GetFramerateCap(); UINT32 benchmark = (cap == 0) ? I_GetRefreshRate() : cap; - INT32 x = 318; + INT32 x = 317; double fps = round(averageFPS); if (fps > (benchmark * 0.9)) @@ -586,7 +586,7 @@ void SCR_DisplayLocalPing(void) return; } - INT32 dispy = cv_ticrate.value ? 160 : 181; + INT32 dispy = cv_ticrate.value ? 170 : 181; boolean offline = (consoleplayer == serverplayer); HU_drawPing(307 * FRACUNIT, dispy * FRACUNIT, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM, offline, 0); From 35cb0e4c5ca690f48a7f208083233dffd6b5f8db Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Oct 2023 21:27:48 -0700 Subject: [PATCH 50/53] HUD: do not show position number in splitscreen FREE PLAY --- src/k_hud.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index f14b42bfa..8eea55fdc 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -5486,18 +5486,23 @@ void K_drawKartHUD(void) islonesome = K_drawKartPositionFaces(); } - else if (r_splitscreen == 1) + else { - if (LUA_HudEnabled(hud_time)) + islonesome = M_NotFreePlay() == false; + + if (r_splitscreen == 1) { - K_drawKart2PTimestamp(); + if (LUA_HudEnabled(hud_time)) + { + K_drawKart2PTimestamp(); + } } - } - else if (viewnum == r_splitscreen) - { - if (LUA_HudEnabled(hud_time)) + else if (viewnum == r_splitscreen) { - K_drawKart4PTimestamp(); + if (LUA_HudEnabled(hud_time)) + { + K_drawKart4PTimestamp(); + } } } From 0019e74604b04000e8408fd9cbfe5c2c88497551 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Oct 2023 21:51:35 -0700 Subject: [PATCH 51/53] HUD: fix nametag position for P2 in 2P splitscreen --- src/k_hud.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 8eea55fdc..0f36e22f1 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3453,7 +3453,7 @@ static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p) // Since there's no "V_DrawFixedFill", and I don't feel like making it, // fuck it, we're gonna just V_NOSCALESTART hack it - if (cnum & 1) + if (r_splitscreen > 1 && cnum & 1) { x += (BASEVIDWIDTH/2) * FRACUNIT; } From dc4c66322f2524da12d0e1578965191d9875680c Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 3 Oct 2023 22:05:48 -0700 Subject: [PATCH 52/53] K_drawKartNameTags: crop HUD tracking to splitscreen viewports --- src/k_hud.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/k_hud.c b/src/k_hud.c index 0f36e22f1..89479c115 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3552,6 +3552,31 @@ static void K_drawKartNameTags(void) return; } + // Crop within splitscreen bounds + switch (r_splitscreen) + { + case 1: + V_SetClipRect( + 0, + cnum == 1 ? (BASEVIDHEIGHT / 2) * FRACUNIT : 0, + BASEVIDWIDTH * FRACUNIT, + (BASEVIDHEIGHT / 2) * FRACUNIT, + 0 + ); + break; + + case 2: + case 3: + V_SetClipRect( + cnum & 1 ? (BASEVIDWIDTH / 2) * FRACUNIT : 0, + cnum > 1 ? (BASEVIDHEIGHT / 2) * FRACUNIT : 0, + (BASEVIDWIDTH / 2) * FRACUNIT, + (BASEVIDHEIGHT / 2) * FRACUNIT, + 0 + ); + break; + } + c.x = viewx; c.y = viewy; c.z = viewz; @@ -3767,6 +3792,8 @@ static void K_drawKartNameTags(void) } } } + + V_ClearClipRect(); } #define PROGRESSION_BAR_WIDTH 120 From e4fde7735e34aa8c32d049cb34361c02994ad9bf Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 4 Oct 2023 00:06:21 -0700 Subject: [PATCH 53/53] Revert "HUD: slide in position numbers if race starts immediately" This reverts commit a8d0bad4b00e9dc22b3324dfd091abfbcd350a53. --- src/k_hud.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 89479c115..a5dc2b1d8 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2109,8 +2109,6 @@ static void K_DrawKartPositionNum(UINT8 num) fflags |= (trans << V_ALPHASHIFT); } - fflags |= V_SLIDEIN; - if (stplyr->exiting && num == 1) { // 1st place winner? You get rainbows!!