From 86366b000cc27f43cc03d8f10b3100fa9f91d70c Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 30 Oct 2022 05:58:15 -0700 Subject: [PATCH 01/67] HOSTCODE 'ironman' - WIP --- src/d_player.h | 4 ++++ src/deh_tables.c | 1 + src/g_demo.c | 7 ++++++- src/g_game.c | 10 ++++++++++ src/k_hud.c | 17 ++++++++++++++--- src/lua_playerlib.c | 8 ++++++++ src/m_random.h | 2 ++ src/p_saveg.c | 4 ++++ src/p_user.c | 22 ++++++++++++++++++++++ src/r_skins.c | 12 ++++++++++++ src/r_skins.h | 1 + 11 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index d61360ded..10a9cf3a9 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -37,6 +37,7 @@ typedef enum { SF_HIRES = 1, // Draw the sprite at different size? SF_MACHINE = 1<<1, // Beep boop. Are you a robot? + SF_IRONMAN = 1<<2, // Pick a new skin during POSITION. I main Random! // free up to and including 1<<31 } skinflags_t; @@ -386,6 +387,9 @@ typedef struct player_s INT32 skin; UINT32 availabilities; + UINT8 fakeskin; // ironman + UINT8 lastfakeskin; + UINT8 kartspeed; // Kart speed stat between 1 and 9 UINT8 kartweight; // Kart weight stat between 1 and 9 diff --git a/src/deh_tables.c b/src/deh_tables.c index 2f68edf2c..6d9c8c7f2 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6318,6 +6318,7 @@ struct int_const_s const INT_CONST[] = { // Character flags (skinflags_t) {"SF_HIRES",SF_HIRES}, {"SF_MACHINE",SF_MACHINE}, + {"SF_IRONMAN",SF_IRONMAN}, // Sound flags {"SF_TOTALLYSINGLE",SF_TOTALLYSINGLE}, diff --git a/src/g_demo.c b/src/g_demo.c index 103a60a41..baad4e3fc 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -274,6 +274,7 @@ void G_ReadDemoExtraData(void) kartspeed = READUINT8(demo_p); kartweight = READUINT8(demo_p); + demo_p++; // lastfakeskin if (stricmp(skins[players[p].skin].name, name) != 0) FindClosestSkinForStats(p, kartspeed, kartweight); @@ -2110,6 +2111,7 @@ void G_BeginRecording(void) // Kart speed and weight WRITEUINT8(demo_p, skins[player->skin].kartspeed); WRITEUINT8(demo_p, skins[player->skin].kartweight); + WRITEUINT8(demo_p, player->lastfakeskin); // And mobjtype_t is best with UINT32 too... WRITEUINT32(demo_p, player->followitem); @@ -2709,7 +2711,7 @@ void G_DoPlayDemo(char *defdemoname) char msg[1024]; boolean spectator; - UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], numslots = 0; + UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], lastfakeskin[MAXPLAYERS], numslots = 0; #if defined(SKIPERRORS) && !defined(DEVELOP) boolean skiperrors = false; @@ -3086,6 +3088,7 @@ void G_DoPlayDemo(char *defdemoname) // Kart stats, temporarily kartspeed[p] = READUINT8(demo_p); kartweight[p] = READUINT8(demo_p); + lastfakeskin[p] = READUINT8(demo_p); if (stricmp(skins[players[p].skin].name, skin) != 0) FindClosestSkinForStats(p, kartspeed[p], kartweight[p]); @@ -3143,6 +3146,7 @@ void G_DoPlayDemo(char *defdemoname) // it would only break the replay if we clipped them. players[i].kartspeed = kartspeed[i]; players[i].kartweight = kartweight[i]; + players[i].fakeskin = lastfakeskin[i]; } demo.deferstart = true; @@ -3334,6 +3338,7 @@ void G_AddGhost(char *defdemoname) kartspeed = READUINT8(p); kartweight = READUINT8(p); + p += 1; // lastfakeskin p += 4; // followitem (maybe change later) diff --git a/src/g_game.c b/src/g_game.c index bf37aadbc..3d06aed1c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2233,6 +2233,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) UINT16 skincolor; INT32 skin; UINT32 availabilities; + UINT8 fakeskin; + UINT8 lastfakeskin; tic_t jointime; @@ -2278,6 +2280,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) skincolor = players[player].skincolor; skin = players[player].skin; + fakeskin = players[player].fakeskin; + lastfakeskin = players[player].lastfakeskin; // SRB2kart kartspeed = players[player].kartspeed; @@ -2431,6 +2435,12 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->botvars.rival = botrival; p->xtralife = xtralife; + if (betweenmaps) + p->fakeskin = MAXSKINS; + else + p->fakeskin = fakeskin; + p->lastfakeskin = lastfakeskin; + // SRB2kart p->itemroulette = itemroulette; p->roulettetype = roulettetype; diff --git a/src/k_hud.c b/src/k_hud.c index d4127e131..a2e2baa1c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1699,6 +1699,7 @@ static boolean K_drawKartPositionFaces(void) boolean completed[MAXPLAYERS]; INT32 rankplayer[MAXPLAYERS]; INT32 bumperx, emeraldx, numplayersingame = 0; + INT32 xoff, yoff, flipflag = 0; UINT8 *colormap; ranklines = 0; @@ -1784,15 +1785,25 @@ static boolean K_drawKartPositionFaces(void) bumperx = FACE_X+19; emeraldx = FACE_X+16; + if (skins[players[rankplayer[i]].skin].flags & SF_IRONMAN) + { + flipflag = V_FLIP; + xoff = 16; + } else + { + flipflag = 0; + xoff = yoff = 0; + } + if (players[rankplayer[i]].mo->color) { - colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE); + colormap = R_GetTranslationColormap(((skin_t*)players[rankplayer[i]].mo->skin) - skins, players[rankplayer[i]].mo->color, GTC_CACHE); if (players[rankplayer[i]].mo->colorized) colormap = R_GetTranslationColormap(TC_RAINBOW, players[rankplayer[i]].mo->color, GTC_CACHE); else - colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE); + colormap = R_GetTranslationColormap(((skin_t*)players[rankplayer[i]].mo->skin) - skins, players[rankplayer[i]].mo->color, GTC_CACHE); - V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, faceprefix[players[rankplayer[i]].skin][FACE_RANK], colormap); + V_DrawMappedPatch(FACE_X + xoff, Y + yoff, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT|flipflag, faceprefix[((skin_t*)players[rankplayer[i]].mo->skin) - skins][FACE_RANK], colormap); if (LUA_HudEnabled(hud_battlebumpers)) { diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index c5f5cc4d0..2a3b9e46a 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -410,6 +410,10 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->skin); else if (fastcmp(field,"availabilities")) lua_pushinteger(L, plr->availabilities); + else if (fastcmp(field,"fakeskin")) + lua_pushinteger(L, plr->fakeskin); + else if (fastcmp(field,"lastfakeskin")) + lua_pushinteger(L, plr->lastfakeskin); else if (fastcmp(field,"score")) lua_pushinteger(L, plr->score); // SRB2kart @@ -575,6 +579,10 @@ static int player_set(lua_State *L) return NOSET; else if (fastcmp(field,"availabilities")) return NOSET; + else if (fastcmp(field,"fakeskin")) + return NOSET; + else if (fastcmp(field,"lastfakeskin")) + return NOSET; else if (fastcmp(field,"score")) plr->score = luaL_checkinteger(L, 3); // SRB2kart diff --git a/src/m_random.h b/src/m_random.h index c08e32993..dc6f1884b 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -62,6 +62,8 @@ typedef enum PR_MOVINGTARGET, // Randomised moving targets + PR_RANDOMSKIN, // Random skin select from Heavy Magician(?) + PRNUMCLASS } pr_class_t; diff --git a/src/p_saveg.c b/src/p_saveg.c index e35fa823f..b75dfe591 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -151,6 +151,8 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].skincolor); WRITEINT32(save_p, players[i].skin); WRITEUINT32(save_p, players[i].availabilities); + WRITEUINT8(save_p, players[i].fakeskin); + WRITEUINT8(save_p, players[i].lastfakeskin); WRITEUINT32(save_p, players[i].score); WRITESINT8(save_p, players[i].lives); WRITESINT8(save_p, players[i].xtralife); @@ -470,6 +472,8 @@ static void P_NetUnArchivePlayers(void) players[i].skincolor = READUINT8(save_p); players[i].skin = READINT32(save_p); players[i].availabilities = READUINT32(save_p); + players[i].fakeskin = READUINT8(save_p); + players[i].lastfakeskin = READUINT8(save_p); players[i].score = READUINT32(save_p); players[i].lives = READSINT8(save_p); players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter diff --git a/src/p_user.c b/src/p_user.c index be7beff57..3c64604f4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4167,6 +4167,28 @@ void P_PlayerThink(player_t *player) { player->stairjank--; } + // Random skin / "ironman" + if (((skin_t *)player->mo->skin)->flags & SF_IRONMAN) + { + if (player->mo) { + if (player->fakeskin != MAXSKINS) + { + SetFakePlayerSkin(player, player->fakeskin); + } + else + { + INT32 i; + do { + i = P_RandomKey(PR_RANDOMSKIN, numskins); + } while (skins[i].flags & SF_IRONMAN || i == player->lastfakeskin); + + SetFakePlayerSkin(player, i); + + S_StartSound(NULL, sfx_kc33); + K_SpawnDriftElectricSparks(player, player->skincolor, false); + } + } + } K_KartPlayerThink(player, cmd); // SRB2kart diff --git a/src/r_skins.c b/src/r_skins.c index 0557e9e88..ba081efd6 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -334,6 +334,17 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) SetPlayerSkinByNum(playernum, 0); // not found, put in the default skin } +// Set mo skin but not player_t skin, for ironman +void SetFakePlayerSkin(player_t* player, INT32 skinnum) +{ + player->mo->skin = &skins[skinnum]; + player->fakeskin = skinnum; + player->lastfakeskin = skinnum; + player->kartspeed = skins[skinnum].kartspeed; + player->kartweight = skins[skinnum].kartweight; + player->charflags = skins[skinnum].flags; +} + // // Add skins from a pwad, each skin preceded by 'S_SKIN' marker // @@ -484,6 +495,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) // 1, true, yes are all valid values GETFLAG(HIRES) GETFLAG(MACHINE) + GETFLAG(IRONMAN) #undef GETFLAG else // let's check if it's a sound, otherwise error out diff --git a/src/r_skins.h b/src/r_skins.h index ded45a71f..9e51f025c 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -81,6 +81,7 @@ void R_InitSkins(void); void SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 +void SetFakePlayerSkin(player_t* player, INT32 skinnum); boolean R_SkinUsable(INT32 playernum, INT32 skinnum); UINT32 R_GetSkinAvailabilities(void); INT32 R_SkinAvailable(const char *name); From c2224d2edca2c4b44e1639c60f107d73c96ca41e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 30 Oct 2022 06:19:21 -0700 Subject: [PATCH 02/67] Ironman: demo fixes --- src/g_demo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index baad4e3fc..c0aeb5839 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -274,7 +274,6 @@ void G_ReadDemoExtraData(void) kartspeed = READUINT8(demo_p); kartweight = READUINT8(demo_p); - demo_p++; // lastfakeskin if (stricmp(skins[players[p].skin].name, name) != 0) FindClosestSkinForStats(p, kartspeed, kartweight); From 8cc535925ba3b23c4b1146f812e032ca46278db1 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 30 Oct 2022 17:04:19 -0700 Subject: [PATCH 03/67] Ironman: Randomize every lap and after intro --- src/g_demo.c | 2 +- src/k_hud.c | 12 +++++++++--- src/p_spec.c | 3 +++ src/p_user.c | 12 ++---------- src/r_skins.c | 16 ++++++++++++++++ src/r_skins.h | 1 + 6 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index c0aeb5839..bacc64063 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3145,7 +3145,7 @@ void G_DoPlayDemo(char *defdemoname) // it would only break the replay if we clipped them. players[i].kartspeed = kartspeed[i]; players[i].kartweight = kartweight[i]; - players[i].fakeskin = lastfakeskin[i]; + players[i].lastfakeskin = lastfakeskin[i]; } demo.deferstart = true; diff --git a/src/k_hud.c b/src/k_hud.c index a2e2baa1c..47f103f34 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1700,6 +1700,7 @@ static boolean K_drawKartPositionFaces(void) INT32 rankplayer[MAXPLAYERS]; INT32 bumperx, emeraldx, numplayersingame = 0; INT32 xoff, yoff, flipflag = 0; + UINT8 workingskin; UINT8 *colormap; ranklines = 0; @@ -1797,13 +1798,18 @@ static boolean K_drawKartPositionFaces(void) if (players[rankplayer[i]].mo->color) { - colormap = R_GetTranslationColormap(((skin_t*)players[rankplayer[i]].mo->skin) - skins, players[rankplayer[i]].mo->color, GTC_CACHE); + if ((skin_t*)players[rankplayer[i]].mo->skin) + workingskin = (skin_t*)players[rankplayer[i]].mo->skin - skins; + else + workingskin = players[rankplayer[i]].skin; + + colormap = R_GetTranslationColormap(workingskin, players[rankplayer[i]].mo->color, GTC_CACHE); if (players[rankplayer[i]].mo->colorized) colormap = R_GetTranslationColormap(TC_RAINBOW, players[rankplayer[i]].mo->color, GTC_CACHE); else - colormap = R_GetTranslationColormap(((skin_t*)players[rankplayer[i]].mo->skin) - skins, players[rankplayer[i]].mo->color, GTC_CACHE); + colormap = R_GetTranslationColormap(workingskin, players[rankplayer[i]].mo->color, GTC_CACHE); - V_DrawMappedPatch(FACE_X + xoff, Y + yoff, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT|flipflag, faceprefix[((skin_t*)players[rankplayer[i]].mo->skin) - skins][FACE_RANK], colormap); + V_DrawMappedPatch(FACE_X + xoff, Y + yoff, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT|flipflag, faceprefix[workingskin][FACE_RANK], colormap); if (LUA_HudEnabled(hud_battlebumpers)) { diff --git a/src/p_spec.c b/src/p_spec.c index 25d75f3ff..7063b6dc5 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1919,6 +1919,9 @@ static void K_HandleLapIncrement(player_t *player) player->karthud[khud_lapanimation] = 80; } + if (skins[player->skin].flags & SF_IRONMAN) + SetRandomFakePlayerSkin(player); + if (rainbowstartavailable == true) { S_StartSound(player->mo, sfx_s23c); diff --git a/src/p_user.c b/src/p_user.c index 3c64604f4..f19211f9f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4168,7 +4168,7 @@ void P_PlayerThink(player_t *player) player->stairjank--; } // Random skin / "ironman" - if (((skin_t *)player->mo->skin)->flags & SF_IRONMAN) + if (leveltime >= introtime && ((skin_t *)player->mo->skin)->flags & SF_IRONMAN) { if (player->mo) { if (player->fakeskin != MAXSKINS) @@ -4177,15 +4177,7 @@ void P_PlayerThink(player_t *player) } else { - INT32 i; - do { - i = P_RandomKey(PR_RANDOMSKIN, numskins); - } while (skins[i].flags & SF_IRONMAN || i == player->lastfakeskin); - - SetFakePlayerSkin(player, i); - - S_StartSound(NULL, sfx_kc33); - K_SpawnDriftElectricSparks(player, player->skincolor, false); + SetRandomFakePlayerSkin(player); } } } diff --git a/src/r_skins.c b/src/r_skins.c index ba081efd6..d4708b597 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -27,6 +27,8 @@ #include "p_local.h" #include "dehacked.h" // get_number (for thok) #include "m_cond.h" +#include "k_kart.h" +#include "m_random.h" #if 0 #include "k_kart.h" // K_KartResetPlayerColor #endif @@ -345,6 +347,20 @@ void SetFakePlayerSkin(player_t* player, INT32 skinnum) player->charflags = skins[skinnum].flags; } +// Loudly rerandomize +void SetRandomFakePlayerSkin(player_t* player) +{ + INT32 i; + do { + i = P_RandomKey(PR_RANDOMSKIN, numskins); + } while (skins[i].flags & SF_IRONMAN || i == player->lastfakeskin); + + SetFakePlayerSkin(player, i); + + S_StartSound(NULL, sfx_kc33); + K_SpawnDriftElectricSparks(player, player->skincolor, false); +} + // // Add skins from a pwad, each skin preceded by 'S_SKIN' marker // diff --git a/src/r_skins.h b/src/r_skins.h index 9e51f025c..66fdaf3a6 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -82,6 +82,7 @@ void R_InitSkins(void); void SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 void SetFakePlayerSkin(player_t* player, INT32 skinnum); +void SetRandomFakePlayerSkin(player_t* player); boolean R_SkinUsable(INT32 playernum, INT32 skinnum); UINT32 R_GetSkinAvailabilities(void); INT32 R_SkinAvailable(const char *name); From 4a0666dcf367069a37964c76d6f860f4d620a9ed Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 30 Oct 2022 20:32:10 -0700 Subject: [PATCH 04/67] Ironman: vaguely Heavy Magician-esque transform particles --- src/r_skins.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/r_skins.c b/src/r_skins.c index d4708b597..8688d8648 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -357,8 +357,46 @@ void SetRandomFakePlayerSkin(player_t* player) SetFakePlayerSkin(player, i); - S_StartSound(NULL, sfx_kc33); - K_SpawnDriftElectricSparks(player, player->skincolor, false); + if (player->mo) + { + S_StartSound(player->mo, sfx_kc33); + + mobj_t *parent = player->mo; + fixed_t rad = FixedDiv(FixedHypot(parent->radius, parent->radius), parent->scale); + INT32 j; + + for (j = 0; j < 16; j++) + { + fixed_t hmomentum = P_RandomRange(PR_DECORATION, 3, 6) * parent->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, 1, 3) * parent->scale; + UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); + + angle_t ang = R_PointToAngle(parent->momx, parent->momy); + SINT8 flip = 1; + + mobj_t *dust; + + if (j & 1) + ang -= ANGLE_90; + else + ang += ANGLE_90; + + dust = P_SpawnMobjFromMobj(parent, + FixedMul(rad, FINECOSINE(ang >> ANGLETOFINESHIFT)), + FixedMul(rad, FINESINE(ang >> ANGLETOFINESHIFT)), + parent->height, (j%3 == 0) ? MT_SIGNSPARKLE : MT_SPINDASHDUST + ); + flip = P_MobjFlip(dust); + + dust->momx = parent->momx + FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); + dust->momy = parent->momy + FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); + dust->momz = vmomentum * flip; + dust->scale = dust->scale*4; + dust->frame |= FF_SUBTRACT|FF_TRANS90; + dust->color = color; + dust->colorized = true; + } + } } // From 8fe89c3dcdbeb59af460486b4de1350bb1ac57ef Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Sun, 30 Oct 2022 23:23:35 -0700 Subject: [PATCH 05/67] Ironman: papersprite box hell --- src/deh_tables.c | 5 +++ src/info.c | 58 +++++++++++++++++++++++++++++++ src/info.h | 6 ++++ src/p_mobj.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ src/r_skins.c | 20 +++++++++-- 5 files changed, 176 insertions(+), 3 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 6d9c8c7f2..bd908e8b3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3281,6 +3281,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi //"S_ITEMCAPSULE_BOTTOM", //"S_ITEMCAPSULE_INSIDE", + "S_MAGICIANBOX", + "S_MAGICIANBOXTOP", + // Signpost sparkles "S_SIGNSPARK1", "S_SIGNSPARK2", @@ -5278,6 +5281,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_FLOATINGITEM", "MT_ITEMCAPSULE", "MT_ITEMCAPSULE_PART", + "MT_MAGICIANBOX", + "MT_MAGICIANBOX_SIDE", "MT_SIGNSPARKLE", diff --git a/src/info.c b/src/info.c index b1f4bc1be..0d8d3e462 100644 --- a/src/info.c +++ b/src/info.c @@ -542,6 +542,7 @@ char sprnames[NUMSPRITES + 1][5] = "KINF", // Invincibility flash "INVI", // Invincibility speedlines "ICAP", // Item capsules + "MGBX", // Heavy Magician transform box "WIPD", // Wipeout dust trail "DRIF", // Drift Sparks @@ -3888,6 +3889,9 @@ state_t states[NUMSTATES] = //{SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM //{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE + {SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX + {SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP + {SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3 @@ -22390,6 +22394,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_MAGICIANBOX + -1, // doomednum + S_MAGICIANBOX, // 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 + 26*FRACUNIT, // radius + 26*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_MAGICIANBOX_SIDE + -1, // doomednum + S_MAGICIANBOX, // 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 + 26*FRACUNIT, // radius + 14*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + { // MT_SIGNSPARKLE -1, // doomednum S_SIGNSPARK1, // spawnstate diff --git a/src/info.h b/src/info.h index 176705a41..05caa8010 100644 --- a/src/info.h +++ b/src/info.h @@ -1088,6 +1088,7 @@ typedef enum sprite SPR_KINF, // Invincibility flash SPR_INVI, // Invincibility speedlines SPR_ICAP, // Item capsules + SPR_MGBX, // Heavy Magician transform box SPR_WIPD, // Wipeout dust trail SPR_DRIF, // Drift Sparks @@ -4292,6 +4293,9 @@ typedef enum state //S_ITEMCAPSULE_BOTTOM, //S_ITEMCAPSULE_INSIDE, + S_MAGICIANBOX, + S_MAGICIANBOX_TOP, + // Signpost sparkles S_SIGNSPARK1, S_SIGNSPARK2, @@ -6325,6 +6329,8 @@ typedef enum mobj_type MT_FLOATINGITEM, MT_ITEMCAPSULE, MT_ITEMCAPSULE_PART, + MT_MAGICIANBOX, + MT_MAGICIANBOX_SIDE, MT_SIGNSPARKLE, diff --git a/src/p_mobj.c b/src/p_mobj.c index bdf0064f0..cf58bf6c9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7609,6 +7609,96 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->renderflags = (mobj->renderflags & ~RF_TRANSMASK)|(trans << RF_TRANSSHIFT); } break; + case MT_MAGICIANBOX: + fixed_t destx, desty, fakeangle; + INT32 j; + + // EV1: rotation rate + // EV2: lifetime + // cusval: should play sounds (limit 1) + + mobj->extravalue2--; + + if (mobj->extravalue2 == 0) + { + P_RemoveMobj(mobj); + break; + } + else if (mobj->extravalue2 < TICRATE/3) + { + mobj->target = NULL; + if (mobj->extravalue2 & 1) + mobj->renderflags |= RF_DONTDRAW; + else + mobj->renderflags &= ~RF_DONTDRAW; + } + else if (mobj->extravalue2 == TICRATE/3 && mobj->target) + { + mobj->target->renderflags &= ~RF_DONTDRAW; + + if (mobj->cusval) // Are we the side selected to play a sound? + { + S_StartSound(mobj, sfx_kc2e); + S_StartSound(mobj, sfx_s3k9f); + } + + for (j = 0; j < 16; j++) + { + fixed_t hmomentum = P_RandomRange(PR_DECORATION, 3, 6) * mobj->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, 1, 3) * mobj->scale; + UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); + + angle_t ang = R_PointToAngle(mobj->target->momx, mobj->target->momy); + SINT8 flip = 1; + + mobj_t *dust; + + if (j & 1) + ang -= ANGLE_90; + else + ang += ANGLE_90; + + dust = P_SpawnMobjFromMobj(mobj, + FixedMul(mobj->radius, FINECOSINE(ang >> ANGLETOFINESHIFT)), + FixedMul(mobj->radius, FINESINE(ang >> ANGLETOFINESHIFT)), + mobj->target->height, (j%3 == 0) ? MT_SIGNSPARKLE : MT_SPINDASHDUST + ); + flip = P_MobjFlip(dust); + + dust->momx = mobj->target->momx + FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); + dust->momy = mobj->target->momy + FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); + dust->momz = vmomentum * flip; + dust->scale = dust->scale*4; + dust->frame |= FF_SUBTRACT|FF_TRANS90; + dust->color = color; + dust->colorized = true; + } + } + else + { + mobj->target->renderflags |= RF_DONTDRAW; + } + + if (!mobj->target || !mobj->target->health || !mobj->target->player) { + mobj->extravalue2 = min(mobj->extravalue2, TICRATE/3); + return true; + } + + mobj->extravalue1 += 1; + + mobj->angle += ANG1*mobj->extravalue1; + mobj->scale = mobj->target->scale; + + destx = mobj->target->x; + desty = mobj->target->y; + + fakeangle = (FixedInt(AngleFixed(mobj->angle)) + 90)%360; // What + + destx += FixedMul(mobj->radius*2, FINECOSINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + desty += FixedMul(mobj->radius*2, FINESINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + + P_MoveOrigin(mobj, destx, desty, mobj->target->z); + break; case MT_LIGHTNINGSHIELD: { fixed_t destx, desty; diff --git a/src/r_skins.c b/src/r_skins.c index 8688d8648..92299a9d2 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -360,15 +360,29 @@ void SetRandomFakePlayerSkin(player_t* player) if (player->mo) { S_StartSound(player->mo, sfx_kc33); + S_StartSound(player->mo, sfx_cdfm44); mobj_t *parent = player->mo; fixed_t rad = FixedDiv(FixedHypot(parent->radius, parent->radius), parent->scale); - INT32 j; + INT32 j, k; + + for (k = 0; k < 4; k++) + { + mobj_t *box = P_SpawnMobjFromMobj(parent, 0, 0, 0, MT_MAGICIANBOX); + box->target = parent; + box->angle = ANGLE_90 * k; + box->extravalue1 = 1; // Rotation rate + box->extravalue2 = 3*TICRATE/2; // Lifetime + if (k == 0) + box->cusval = 1; // Should play sounds when disappearing + else + box->cusval = 0; + } for (j = 0; j < 16; j++) { - fixed_t hmomentum = P_RandomRange(PR_DECORATION, 3, 6) * parent->scale; - fixed_t vmomentum = P_RandomRange(PR_DECORATION, 1, 3) * parent->scale; + fixed_t hmomentum = P_RandomRange(PR_DECORATION, 10, 20) * parent->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, 5, 10) * parent->scale; UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); angle_t ang = R_PointToAngle(parent->momx, parent->momy); From 2a46af5a443661a98026f75eca136a8a2cc2310e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 15:45:07 -0700 Subject: [PATCH 06/67] Ironman: animation fixes, don't transform in POSITION --- src/deh_tables.c | 1 - src/info.c | 37 +++++-------------------------------- src/info.h | 1 - src/p_mobj.c | 21 ++++++++++++++++++++- src/p_user.c | 3 ++- src/r_skins.c | 18 ++++++++++++++---- src/r_skins.h | 2 +- 7 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index bd908e8b3..3b6ad291f 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5282,7 +5282,6 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_ITEMCAPSULE", "MT_ITEMCAPSULE_PART", "MT_MAGICIANBOX", - "MT_MAGICIANBOX_SIDE", "MT_SIGNSPARKLE", diff --git a/src/info.c b/src/info.c index 0d8d3e462..b3d377532 100644 --- a/src/info.c +++ b/src/info.c @@ -22394,7 +22394,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_MAGICIANBOX + { // MT_MAGICIANBOX -1, // doomednum S_MAGICIANBOX, // spawnstate 1000, // spawnhealth @@ -22411,43 +22411,16 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 26*FRACUNIT, // radius - 26*FRACUNIT, // height + 20*FRACUNIT, // radius + 20*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, - - { // MT_MAGICIANBOX_SIDE - -1, // doomednum - S_MAGICIANBOX, // 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 - 26*FRACUNIT, // radius - 14*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_SCENERY|MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags - S_NULL // raisestate - }, - + { // MT_SIGNSPARKLE -1, // doomednum S_SIGNSPARK1, // spawnstate diff --git a/src/info.h b/src/info.h index 05caa8010..f70925273 100644 --- a/src/info.h +++ b/src/info.h @@ -6330,7 +6330,6 @@ typedef enum mobj_type MT_ITEMCAPSULE, MT_ITEMCAPSULE_PART, MT_MAGICIANBOX, - MT_MAGICIANBOX_SIDE, MT_SIGNSPARKLE, diff --git a/src/p_mobj.c b/src/p_mobj.c index cf58bf6c9..d3f50c475 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7610,6 +7610,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; case MT_MAGICIANBOX: + { fixed_t destx, desty, fakeangle; INT32 j; @@ -7635,6 +7636,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj) else if (mobj->extravalue2 == TICRATE/3 && mobj->target) { mobj->target->renderflags &= ~RF_DONTDRAW; + + mobj->momx = mobj->target->momx; + mobj->momy = mobj->target->momy; + mobj->momz = mobj->target->momz; + + P_Thrust(mobj, mobj->angle + ANGLE_90, 32*mapobjectscale); + mobj->flags &= ~MF_NOGRAVITY; + mobj->momz += 10*mapobjectscale; if (mobj->cusval) // Are we the side selected to play a sound? { @@ -7673,6 +7682,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) dust->color = color; dust->colorized = true; } + return true; } else { @@ -7697,8 +7707,17 @@ static boolean P_MobjRegularThink(mobj_t *mobj) destx += FixedMul(mobj->radius*2, FINECOSINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); desty += FixedMul(mobj->radius*2, FINESINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); - P_MoveOrigin(mobj, destx, desty, mobj->target->z); + if (mobj->flags2 & MF2_AMBUSH) + { + P_SetOrigin(mobj, destx, desty, mobj->target->z); + mobj->flags2 &= ~MF2_AMBUSH; + } + else + { + P_MoveOrigin(mobj, destx, desty, mobj->target->z); + } break; + } case MT_LIGHTNINGSHIELD: { fixed_t destx, desty; diff --git a/src/p_user.c b/src/p_user.c index f19211f9f..8d07207ed 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4177,7 +4177,8 @@ void P_PlayerThink(player_t *player) } else { - SetRandomFakePlayerSkin(player); + // "Don't halfass" - Oni + // SetRandomFakePlayerSkin(player, false); } } } diff --git a/src/r_skins.c b/src/r_skins.c index 92299a9d2..3c689ea22 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -348,7 +348,7 @@ void SetFakePlayerSkin(player_t* player, INT32 skinnum) } // Loudly rerandomize -void SetRandomFakePlayerSkin(player_t* player) +void SetRandomFakePlayerSkin(player_t* player, boolean fast) { INT32 i; do { @@ -364,15 +364,25 @@ void SetRandomFakePlayerSkin(player_t* player) mobj_t *parent = player->mo; fixed_t rad = FixedDiv(FixedHypot(parent->radius, parent->radius), parent->scale); + fixed_t baseangle = P_RandomRange(PR_DECORATION, 0, 359); INT32 j, k; for (k = 0; k < 4; k++) { mobj_t *box = P_SpawnMobjFromMobj(parent, 0, 0, 0, MT_MAGICIANBOX); box->target = parent; - box->angle = ANGLE_90 * k; - box->extravalue1 = 1; // Rotation rate - box->extravalue2 = 3*TICRATE/2; // Lifetime + box->angle = FixedAngle((baseangle + k*90) * FRACUNIT); + box->flags2 |= MF2_AMBUSH; + if (fast) + { + box->extravalue1 = 25; // Rotation rate + box->extravalue2 = 3*TICRATE/4; // Lifetime + } + else + { + box->extravalue1 = 1; + box->extravalue2 = 3*TICRATE/2; + } if (k == 0) box->cusval = 1; // Should play sounds when disappearing else diff --git a/src/r_skins.h b/src/r_skins.h index 66fdaf3a6..512e476f8 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -82,7 +82,7 @@ void R_InitSkins(void); void SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 void SetFakePlayerSkin(player_t* player, INT32 skinnum); -void SetRandomFakePlayerSkin(player_t* player); +void SetRandomFakePlayerSkin(player_t* player, boolean fast); boolean R_SkinUsable(INT32 playernum, INT32 skinnum); UINT32 R_GetSkinAvailabilities(void); INT32 R_SkinAvailable(const char *name); From 8c800cf88eb036c376106917b8ca307d3c7cc92e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 16:03:24 -0700 Subject: [PATCH 07/67] Ironman: use introtime transform in non-race --- src/p_spec.c | 2 +- src/p_user.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 7063b6dc5..deb197a6e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1920,7 +1920,7 @@ static void K_HandleLapIncrement(player_t *player) } if (skins[player->skin].flags & SF_IRONMAN) - SetRandomFakePlayerSkin(player); + SetRandomFakePlayerSkin(player, true); if (rainbowstartavailable == true) { diff --git a/src/p_user.c b/src/p_user.c index 8d07207ed..24317d014 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4175,10 +4175,9 @@ void P_PlayerThink(player_t *player) { SetFakePlayerSkin(player, player->fakeskin); } - else + else if (!(gametyperules & GTR_CIRCUIT)) { - // "Don't halfass" - Oni - // SetRandomFakePlayerSkin(player, false); + SetRandomFakePlayerSkin(player, false); } } } From dd93f322cc6fcc2e3d8e60947d603869073c4144 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 16:46:54 -0700 Subject: [PATCH 08/67] Ironman: fix weird particle angles --- src/p_mobj.c | 18 +++++++++--------- src/r_skins.c | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index d3f50c475..f3f3cb97c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7644,20 +7644,20 @@ static boolean P_MobjRegularThink(mobj_t *mobj) P_Thrust(mobj, mobj->angle + ANGLE_90, 32*mapobjectscale); mobj->flags &= ~MF_NOGRAVITY; mobj->momz += 10*mapobjectscale; - - if (mobj->cusval) // Are we the side selected to play a sound? - { - S_StartSound(mobj, sfx_kc2e); - S_StartSound(mobj, sfx_s3k9f); - } + + if (!mobj->cusval) // Some stuff should only occur once per box + return true; + + S_StartSound(mobj, sfx_kc2e); + S_StartSound(mobj, sfx_s3k9f); for (j = 0; j < 16; j++) { - fixed_t hmomentum = P_RandomRange(PR_DECORATION, 3, 6) * mobj->scale; - fixed_t vmomentum = P_RandomRange(PR_DECORATION, 1, 3) * mobj->scale; + fixed_t hmomentum = P_RandomRange(PR_DECORATION, -5, 5) * mobj->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, -5, 5) * mobj->scale; UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); - angle_t ang = R_PointToAngle(mobj->target->momx, mobj->target->momy); + fixed_t ang = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359)*FRACUNIT); SINT8 flip = 1; mobj_t *dust; diff --git a/src/r_skins.c b/src/r_skins.c index 3c689ea22..9fbeaf038 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -391,11 +391,11 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) for (j = 0; j < 16; j++) { - fixed_t hmomentum = P_RandomRange(PR_DECORATION, 10, 20) * parent->scale; - fixed_t vmomentum = P_RandomRange(PR_DECORATION, 5, 10) * parent->scale; + fixed_t hmomentum = P_RandomRange(PR_DECORATION, -10, 10) * parent->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, -10, 10) * parent->scale; UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); - angle_t ang = R_PointToAngle(parent->momx, parent->momy); + angle_t ang = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359)*FRACUNIT); SINT8 flip = 1; mobj_t *dust; From b9517d3a890e1bfb1261763c733ac7488e20ba1b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 16:56:53 -0700 Subject: [PATCH 09/67] Ironman: longer lap-advance animation --- src/r_skins.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_skins.c b/src/r_skins.c index 9fbeaf038..4db1d7963 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -375,8 +375,8 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) box->flags2 |= MF2_AMBUSH; if (fast) { - box->extravalue1 = 25; // Rotation rate - box->extravalue2 = 3*TICRATE/4; // Lifetime + box->extravalue1 = 10; // Rotation rate + box->extravalue2 = 5*TICRATE/4; // Lifetime } else { From 02bf3bc695257f14662f545227ec51373a99bea7 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 18:09:02 -0700 Subject: [PATCH 10/67] Ironman: splat top/bottom WIP --- src/deh_tables.c | 1 + src/info.c | 5 ++++- src/info.h | 3 +++ src/p_mobj.c | 30 ++++++++++++++++++++++++------ src/r_skins.c | 9 ++++++++- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 3b6ad291f..17b5a7bde 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3283,6 +3283,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_MAGICIANBOX", "S_MAGICIANBOXTOP", + "S_MAGICIANBOXBOTTOM", // Signpost sparkles "S_SIGNSPARK1", diff --git a/src/info.c b/src/info.c index b3d377532..d04bd078d 100644 --- a/src/info.c +++ b/src/info.c @@ -543,6 +543,8 @@ char sprnames[NUMSPRITES + 1][5] = "INVI", // Invincibility speedlines "ICAP", // Item capsules "MGBX", // Heavy Magician transform box + "MGBT", // Heavy Magician transform box top + "MGBB", // Heavy Magician transform box bottom "WIPD", // Wipeout dust trail "DRIF", // Drift Sparks @@ -3890,7 +3892,8 @@ state_t states[NUMSTATES] = //{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE {SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX - {SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP + {SPR_MGBT, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP + {SPR_MGBB, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_BOTTOM {SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 diff --git a/src/info.h b/src/info.h index f70925273..b272e5176 100644 --- a/src/info.h +++ b/src/info.h @@ -1089,6 +1089,8 @@ typedef enum sprite SPR_INVI, // Invincibility speedlines SPR_ICAP, // Item capsules SPR_MGBX, // Heavy Magician transform box + SPR_MGBT, // Heavy Magician transform box top + SPR_MGBB, // Heavy Magician transform box bottom SPR_WIPD, // Wipeout dust trail SPR_DRIF, // Drift Sparks @@ -4295,6 +4297,7 @@ typedef enum state S_MAGICIANBOX, S_MAGICIANBOX_TOP, + S_MAGICIANBOX_BOTTOM, // Signpost sparkles S_SIGNSPARK1, diff --git a/src/p_mobj.c b/src/p_mobj.c index f3f3cb97c..1d0d11371 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7612,6 +7612,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_MAGICIANBOX: { fixed_t destx, desty, fakeangle; + fixed_t zoff = 0; INT32 j; // EV1: rotation rate @@ -7635,15 +7636,20 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else if (mobj->extravalue2 == TICRATE/3 && mobj->target) { + mobj->target->renderflags &= ~RF_DONTDRAW; mobj->momx = mobj->target->momx; mobj->momy = mobj->target->momy; mobj->momz = mobj->target->momz; - P_Thrust(mobj, mobj->angle + ANGLE_90, 32*mapobjectscale); + if (mobj->state == &states[S_MAGICIANBOX]) // sides + P_Thrust(mobj, mobj->angle + ANGLE_90, 32*mapobjectscale); + mobj->flags &= ~MF_NOGRAVITY; mobj->momz += 10*mapobjectscale; + if (mobj->state == &states[S_MAGICIANBOX_BOTTOM]) + mobj->momz *= -1; if (!mobj->cusval) // Some stuff should only occur once per box return true; @@ -7702,19 +7708,31 @@ static boolean P_MobjRegularThink(mobj_t *mobj) destx = mobj->target->x; desty = mobj->target->y; - fakeangle = (FixedInt(AngleFixed(mobj->angle)) + 90)%360; // What + if (mobj->state == &states[S_MAGICIANBOX]) // sides + { + CONS_Printf("side\n"); + fakeangle = (FixedInt(AngleFixed(mobj->angle)) + 90)%360; // What - destx += FixedMul(mobj->radius*2, FINECOSINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); - desty += FixedMul(mobj->radius*2, FINESINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + destx += FixedMul(mobj->radius*2, FINECOSINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + desty += FixedMul(mobj->radius*2, FINESINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + } + else if (mobj->state == &states[S_MAGICIANBOX_TOP]) // top + { + CONS_Printf("top\n"); + zoff = mobj->radius*4; + } + else { + CONS_Printf("bottom\n"); + } if (mobj->flags2 & MF2_AMBUSH) { - P_SetOrigin(mobj, destx, desty, mobj->target->z); + P_SetOrigin(mobj, destx, desty, mobj->target->z + zoff); mobj->flags2 &= ~MF2_AMBUSH; } else { - P_MoveOrigin(mobj, destx, desty, mobj->target->z); + P_MoveOrigin(mobj, destx, desty, mobj->target->z + zoff); } break; } diff --git a/src/r_skins.c b/src/r_skins.c index 4db1d7963..7ffcc7f7b 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -367,7 +367,7 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) fixed_t baseangle = P_RandomRange(PR_DECORATION, 0, 359); INT32 j, k; - for (k = 0; k < 4; k++) + for (k = 0; k < 6; k++) { mobj_t *box = P_SpawnMobjFromMobj(parent, 0, 0, 0, MT_MAGICIANBOX); box->target = parent; @@ -387,6 +387,13 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) box->cusval = 1; // Should play sounds when disappearing else box->cusval = 0; + + if (k > 3) + { + P_SetMobjState(box, (k == 4) ? S_MAGICIANBOX_TOP : S_MAGICIANBOX_BOTTOM); + box->renderflags |= RF_NOSPLATBILLBOARD; + box->angle = FixedAngle(baseangle*FRACUNIT); + } } for (j = 0; j < 16; j++) From 8d2d6bfc78cb288eb332b7fdc577ad1ada0d3a1b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 19:01:28 -0700 Subject: [PATCH 11/67] Ironman: return to base character when exiting --- src/p_mobj.c | 5 ----- src/p_spec.c | 7 ++++--- src/p_user.c | 26 ++++++++++++++++++-------- src/r_skins.c | 9 +++++++++ src/r_skins.h | 1 + 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1d0d11371..0967eff2e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7710,7 +7710,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->state == &states[S_MAGICIANBOX]) // sides { - CONS_Printf("side\n"); fakeangle = (FixedInt(AngleFixed(mobj->angle)) + 90)%360; // What destx += FixedMul(mobj->radius*2, FINECOSINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); @@ -7718,12 +7717,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else if (mobj->state == &states[S_MAGICIANBOX_TOP]) // top { - CONS_Printf("top\n"); zoff = mobj->radius*4; } - else { - CONS_Printf("bottom\n"); - } if (mobj->flags2 & MF2_AMBUSH) { diff --git a/src/p_spec.c b/src/p_spec.c index deb197a6e..ca2f32009 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1919,9 +1919,6 @@ static void K_HandleLapIncrement(player_t *player) player->karthud[khud_lapanimation] = 80; } - if (skins[player->skin].flags & SF_IRONMAN) - SetRandomFakePlayerSkin(player, true); - if (rainbowstartavailable == true) { S_StartSound(player->mo, sfx_s23c); @@ -1965,7 +1962,11 @@ static void K_HandleLapIncrement(player_t *player) { P_DoPlayerExit(player); P_SetupSignExit(player); + } else if (skins[player->skin].flags & SF_IRONMAN) + { + SetRandomFakePlayerSkin(player, true); } + if (player->laps > player->latestlap) { diff --git a/src/p_user.c b/src/p_user.c index 24317d014..03c35affe 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1264,6 +1264,8 @@ void P_DoPlayerExit(player_t *player) if (!player->spectator) { + ClearFakePlayerSkin(player); + if ((gametyperules & GTR_CIRCUIT)) // If in Race Mode, allow { K_KartUpdatePosition(player); @@ -4168,18 +4170,26 @@ void P_PlayerThink(player_t *player) player->stairjank--; } // Random skin / "ironman" - if (leveltime >= introtime && ((skin_t *)player->mo->skin)->flags & SF_IRONMAN) + if ((!P_MobjWasRemoved(player->mo)) & (skins[player->skin].flags & SF_IRONMAN)) // we are Heavy Magician with a mobj { - if (player->mo) { - if (player->fakeskin != MAXSKINS) + if (((skin_t *)player->mo->skin)->flags & SF_IRONMAN) // no fakeskin yet + { + if (leveltime >= introtime && !player->exiting) { - SetFakePlayerSkin(player, player->fakeskin); - } - else if (!(gametyperules & GTR_CIRCUIT)) - { - SetRandomFakePlayerSkin(player, false); + if (player->fakeskin != MAXSKINS) + { + SetFakePlayerSkin(player, player->fakeskin); + } + else if (!(gametyperules & GTR_CIRCUIT)) + { + SetRandomFakePlayerSkin(player, false); + } } } + else if (player->exiting) // wearing a fakeskin, but need to display signpost postrace etc + { + ClearFakePlayerSkin(player); + } } K_KartPlayerThink(player, cmd); // SRB2kart diff --git a/src/r_skins.c b/src/r_skins.c index 7ffcc7f7b..71ea80f1f 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -430,6 +430,15 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) } } +// Return to base skin from an SF_IRONMAN randomization +void ClearFakePlayerSkin(player_t* player) +{ + if (player->mo) + { + player->mo->skin = &skins[player->skin]; + } +} + // // Add skins from a pwad, each skin preceded by 'S_SKIN' marker // diff --git a/src/r_skins.h b/src/r_skins.h index 512e476f8..1cc06cca4 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -83,6 +83,7 @@ void SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 void SetFakePlayerSkin(player_t* player, INT32 skinnum); void SetRandomFakePlayerSkin(player_t* player, boolean fast); +void ClearFakePlayerSkin(player_t* player); boolean R_SkinUsable(INT32 playernum, INT32 skinnum); UINT32 R_GetSkinAvailabilities(void); INT32 R_SkinAvailable(const char *name); From 770378eea066bb1487ca149d7358441e8c7fd55e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 19:14:30 -0700 Subject: [PATCH 12/67] Ironman: move transform VFX into function for reuse --- src/k_kart.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/k_kart.h | 1 + src/p_mobj.c | 38 +++++--------------------------------- src/r_skins.c | 45 +++++++-------------------------------------- 4 files changed, 54 insertions(+), 71 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index dff8c406a..d8fe83541 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2727,6 +2727,47 @@ void K_SpawnBumpEffect(mobj_t *mo) S_StartSound(mo, sfx_s3k49); } +void K_SpawnMagicianParticles(mobj_t *mo, int spread) +{ + INT32 i; + mobj_t *target = mo->target; + + if (P_MobjWasRemoved(target)) + target = mo; + + for (i = 0; i < 16; i++) + { + fixed_t hmomentum = P_RandomRange(PR_DECORATION, spread * -1, spread) * mo->scale; + fixed_t vmomentum = P_RandomRange(PR_DECORATION, spread * -1, spread) * mo->scale; + UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); + + fixed_t ang = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359)*FRACUNIT); + SINT8 flip = 1; + + mobj_t *dust; + + if (i & 1) + ang -= ANGLE_90; + else + ang += ANGLE_90; + + dust = P_SpawnMobjFromMobj(mo, + FixedMul(mo->radius, FINECOSINE(ang >> ANGLETOFINESHIFT)), + FixedMul(mo->radius, FINESINE(ang >> ANGLETOFINESHIFT)), + target->height, (i%3 == 0) ? MT_SIGNSPARKLE : MT_SPINDASHDUST + ); + flip = P_MobjFlip(dust); + + dust->momx = target->momx + FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); + dust->momy = target->momy + FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); + dust->momz = vmomentum * flip; + dust->scale = dust->scale*4; + dust->frame |= FF_SUBTRACT|FF_TRANS90; + dust->color = color; + dust->colorized = true; + } +} + static SINT8 K_GlanceAtPlayers(player_t *glancePlayer) { const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); diff --git a/src/k_kart.h b/src/k_kart.h index a5d2b0185..db280afc0 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -110,6 +110,7 @@ void K_SpawnBoostTrail(player_t *player); void K_SpawnSparkleTrail(mobj_t *mo); void K_SpawnWipeoutTrail(mobj_t *mo); void K_SpawnDraftDust(mobj_t *mo); +void K_SpawnMagicianParticles(mobj_t *mo, int spread); void K_DriftDustHandling(mobj_t *spawner); void K_Squish(mobj_t *mo); mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset); diff --git a/src/p_mobj.c b/src/p_mobj.c index 0967eff2e..c2ef43d05 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7613,11 +7613,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) { fixed_t destx, desty, fakeangle; fixed_t zoff = 0; - INT32 j; // EV1: rotation rate // EV2: lifetime - // cusval: should play sounds (limit 1) + // cusval: responsible for disappear FX (should only happen once) + + // S_MAGICANBOX: sides, starting angle is set in the spawner (SetRandomFakePlayerSkin) + // S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets mobj->extravalue2--; @@ -7657,37 +7659,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) S_StartSound(mobj, sfx_kc2e); S_StartSound(mobj, sfx_s3k9f); - for (j = 0; j < 16; j++) - { - fixed_t hmomentum = P_RandomRange(PR_DECORATION, -5, 5) * mobj->scale; - fixed_t vmomentum = P_RandomRange(PR_DECORATION, -5, 5) * mobj->scale; - UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); - - fixed_t ang = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359)*FRACUNIT); - SINT8 flip = 1; - - mobj_t *dust; - - if (j & 1) - ang -= ANGLE_90; - else - ang += ANGLE_90; - - dust = P_SpawnMobjFromMobj(mobj, - FixedMul(mobj->radius, FINECOSINE(ang >> ANGLETOFINESHIFT)), - FixedMul(mobj->radius, FINESINE(ang >> ANGLETOFINESHIFT)), - mobj->target->height, (j%3 == 0) ? MT_SIGNSPARKLE : MT_SPINDASHDUST - ); - flip = P_MobjFlip(dust); - - dust->momx = mobj->target->momx + FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); - dust->momy = mobj->target->momy + FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); - dust->momz = vmomentum * flip; - dust->scale = dust->scale*4; - dust->frame |= FF_SUBTRACT|FF_TRANS90; - dust->color = color; - dust->colorized = true; - } + K_SpawnMagicianParticles(mobj, 5); return true; } else diff --git a/src/r_skins.c b/src/r_skins.c index 71ea80f1f..59156ba06 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -363,15 +363,14 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) S_StartSound(player->mo, sfx_cdfm44); mobj_t *parent = player->mo; - fixed_t rad = FixedDiv(FixedHypot(parent->radius, parent->radius), parent->scale); fixed_t baseangle = P_RandomRange(PR_DECORATION, 0, 359); - INT32 j, k; + INT32 j; - for (k = 0; k < 6; k++) + for (j = 0; j < 6; j++) // 0-3 = sides, 4 = top, 5 = bottom { mobj_t *box = P_SpawnMobjFromMobj(parent, 0, 0, 0, MT_MAGICIANBOX); box->target = parent; - box->angle = FixedAngle((baseangle + k*90) * FRACUNIT); + box->angle = FixedAngle((baseangle + j*90) * FRACUNIT); box->flags2 |= MF2_AMBUSH; if (fast) { @@ -383,50 +382,20 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) box->extravalue1 = 1; box->extravalue2 = 3*TICRATE/2; } - if (k == 0) + if (j == 0) box->cusval = 1; // Should play sounds when disappearing else box->cusval = 0; - if (k > 3) + if (j > 3) { - P_SetMobjState(box, (k == 4) ? S_MAGICIANBOX_TOP : S_MAGICIANBOX_BOTTOM); + P_SetMobjState(box, (j == 4) ? S_MAGICIANBOX_TOP : S_MAGICIANBOX_BOTTOM); box->renderflags |= RF_NOSPLATBILLBOARD; box->angle = FixedAngle(baseangle*FRACUNIT); } } - for (j = 0; j < 16; j++) - { - fixed_t hmomentum = P_RandomRange(PR_DECORATION, -10, 10) * parent->scale; - fixed_t vmomentum = P_RandomRange(PR_DECORATION, -10, 10) * parent->scale; - UINT16 color = P_RandomKey(PR_DECORATION, numskincolors); - - angle_t ang = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359)*FRACUNIT); - SINT8 flip = 1; - - mobj_t *dust; - - if (j & 1) - ang -= ANGLE_90; - else - ang += ANGLE_90; - - dust = P_SpawnMobjFromMobj(parent, - FixedMul(rad, FINECOSINE(ang >> ANGLETOFINESHIFT)), - FixedMul(rad, FINESINE(ang >> ANGLETOFINESHIFT)), - parent->height, (j%3 == 0) ? MT_SIGNSPARKLE : MT_SPINDASHDUST - ); - flip = P_MobjFlip(dust); - - dust->momx = parent->momx + FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); - dust->momy = parent->momy + FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); - dust->momz = vmomentum * flip; - dust->scale = dust->scale*4; - dust->frame |= FF_SUBTRACT|FF_TRANS90; - dust->color = color; - dust->colorized = true; - } + K_SpawnMagicianParticles(player->mo, 10); } } From 26eb1cf9e2ba2dce47a9b7b192985bff2f664723 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 31 Oct 2022 19:01:44 -0700 Subject: [PATCH 13/67] Use interpolated mobj x/y/z/angle for splats --- src/hardware/hw_glob.h | 2 ++ src/hardware/hw_main.c | 77 ++++++++++++++++++++++++------------------ src/r_splats.c | 8 ++--- src/r_things.c | 1 + src/r_things.h | 2 +- 5 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index c13da6889..bc05ea4d4 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -87,6 +87,8 @@ typedef struct gl_vissprite_s boolean rotated; UINT8 translucency; //alpha level 0-255 + angle_t angle; // for splats + //Hurdler: 25/04/2000: now support colormap in hardware mode UINT8 *colormap; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3fecba478..c0db0fe5c 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4179,7 +4179,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) scale *= spr->shadowscale; if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) - angle = spr->mobj->angle; + angle = spr->angle; else angle = viewangle; @@ -4234,8 +4234,8 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Translate for (i = 0; i < 4; i++) { - wallVerts[i].x = rotated[i].x + FIXED_TO_FLOAT(spr->mobj->x); - wallVerts[i].z = rotated[i].y + FIXED_TO_FLOAT(spr->mobj->y); + wallVerts[i].x = rotated[i].x + spr->x1; + wallVerts[i].z = rotated[i].y + spr->z1; } if (renderflags & (RF_SLOPESPLAT | RF_OBJECTSLOPESPLAT)) @@ -4262,7 +4262,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) else { for (i = 0; i < 4; i++) - wallVerts[i].y = FIXED_TO_FLOAT(spr->mobj->z) + zoffset; + wallVerts[i].y = FIXED_TO_FLOAT(spr->gz) + zoffset; } } else @@ -5383,43 +5383,52 @@ static void HWR_ProjectSprite(mobj_t *thing) this_xscale = spritexscale * this_scale; this_yscale = spriteyscale * this_scale; - if (flip) + if (splat) { - x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); - x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); + z1 = z2 = tr_y; + x1 = x2 = tr_x; + gz = gzt = interp.z; } else { - x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); - x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); - } + if (flip) + { + x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); + x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); + } + else + { + x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); + x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); + } - // test if too close -/* - if (papersprite) - { - z1 = tz - x1 * angle_scalez; - z2 = tz + x2 * angle_scalez; + // test if too close + /* + if (papersprite) + { + z1 = tz - x1 * angle_scalez; + z2 = tz + x2 * angle_scalez; - if (max(z1, z2) < ZCLIP_PLANE) - return; - } -*/ + if (max(z1, z2) < ZCLIP_PLANE) + return; + } + */ - z1 = tr_y + x1 * rightsin; - z2 = tr_y - x2 * rightsin; - x1 = tr_x + x1 * rightcos; - x2 = tr_x - x2 * rightcos; + z1 = tr_y + x1 * rightsin; + z2 = tr_y - x2 * rightsin; + x1 = tr_x + x1 * rightcos; + x2 = tr_x - x2 * rightcos; - if (vflip) - { - gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); - gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); - } - else - { - gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); - gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale); + if (vflip) + { + gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); + } + else + { + gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale); + } } if (thing->subsector->sector->cullheight) @@ -5575,6 +5584,8 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->precip = false; vis->bbox = false; + + vis->angle = interp.angle; } #ifdef HWPRECIP diff --git a/src/r_splats.c b/src/r_splats.c index 27cc5566a..80ff44743 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -185,7 +185,7 @@ void R_DrawFloorSplat(vissprite_t *spr) splat.scale = FixedMul(splat.scale, ((skin_t *)mobj->skin)->highresscale); if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) - splatangle = mobj->angle; + splatangle = spr->centerangle; else splatangle = spr->viewpoint.angle; @@ -209,14 +209,14 @@ void R_DrawFloorSplat(vissprite_t *spr) xoffset = FixedMul(leftoffset, splat.xscale); yoffset = FixedMul(topoffset, splat.yscale); - x = mobj->x; - y = mobj->y; + x = spr->gx; + y = spr->gy; w = (splat.width * splat.xscale); h = (splat.height * splat.yscale); splat.x = x; splat.y = y; - splat.z = mobj->z; + splat.z = spr->pz; splat.slope = NULL; // Set positions diff --git a/src/r_things.c b/src/r_things.c index 5b43beed2..9e042c6af 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2056,6 +2056,7 @@ static void R_ProjectSprite(mobj_t *thing) tr_y = (interp.y - sort_y) - viewy; sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); sortsplat = FixedDiv(projectiony[viewssnum], sort_z); + centerangle = interp.angle; } // PORTAL SPRITE CLIPPING diff --git a/src/r_things.h b/src/r_things.h index 881de773e..18c55629b 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -171,7 +171,7 @@ typedef struct vissprite_s fixed_t paperoffset, paperdistance; // for paper sprites, offset/dist relative to the angle fixed_t xiscale; // negative if flipped - angle_t centerangle; // for paper sprites + angle_t centerangle; // for paper sprites / splats // for floor sprites struct { From 603a1671b46286d0570f8f2ff11b57a53bddae60 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 31 Oct 2022 19:03:09 -0700 Subject: [PATCH 14/67] Use angle between viewz and mobj z to determine splat sprite angle --- src/hardware/hw_main.c | 13 ++++++++++--- src/r_things.c | 6 +++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c0db0fe5c..74385e7f7 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5254,9 +5254,16 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif - ang = R_PointToAngle (interp.x, interp.y) - interp.angle; - if (mirrored) - ang = InvAngle(ang); + if (splat) + { + ang = R_PointToAngle2(0, viewz, 0, interp.z); + } + else + { + ang = R_PointToAngle (interp.x, interp.y) - interp.angle; + if (mirrored) + ang = InvAngle(ang); + } if (sprframe->rotate == SRF_SINGLE) { diff --git a/src/r_things.c b/src/r_things.c index 9e042c6af..41dfc8585 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1755,7 +1755,11 @@ static void R_ProjectSprite(mobj_t *thing) I_Error("R_ProjectSprite: sprframes NULL for sprite %d\n", thing->sprite); #endif - if (sprframe->rotate != SRF_SINGLE || papersprite) + if (splat) + { + ang = R_PointToAngle2(0, viewz, 0, interp.z); + } + else if (sprframe->rotate != SRF_SINGLE || papersprite) { ang = R_PointToAngle (interp.x, interp.y) - interp.angle; if (mirrored) From 69f70964fa348c776e09c85d51d33ad5c4959044 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 31 Oct 2022 19:20:30 -0700 Subject: [PATCH 15/67] Ironman: Add FX to exit transform --- src/r_skins.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/r_skins.c b/src/r_skins.c index 59156ba06..180ee2678 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -402,9 +402,11 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) // Return to base skin from an SF_IRONMAN randomization void ClearFakePlayerSkin(player_t* player) { - if (player->mo) + if (!P_MobjWasRemoved(player->mo)) { player->mo->skin = &skins[player->skin]; + S_StartSound(player->mo, sfx_s3k9f); + K_SpawnMagicianParticles(player->mo, 5); } } From 216bad471209e9be32dc2f2e7caeb2637232256b Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 03:57:43 -0700 Subject: [PATCH 16/67] Ironman: Don't do 5 angle conversions for no reason --- src/p_mobj.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index c2ef43d05..5fb2b7114 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7611,7 +7611,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) break; case MT_MAGICIANBOX: { - fixed_t destx, desty, fakeangle; + fixed_t destx, desty; fixed_t zoff = 0; // EV1: rotation rate @@ -7682,10 +7682,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->state == &states[S_MAGICIANBOX]) // sides { - fakeangle = (FixedInt(AngleFixed(mobj->angle)) + 90)%360; // What - - destx += FixedMul(mobj->radius*2, FINECOSINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); - desty += FixedMul(mobj->radius*2, FINESINE(FixedAngle(fakeangle*FRACUNIT) >> ANGLETOFINESHIFT)); + destx += FixedMul(mobj->radius*2, FINECOSINE((mobj->angle+ANGLE_90) >> ANGLETOFINESHIFT)); + desty += FixedMul(mobj->radius*2, FINESINE((mobj->angle+ANGLE_90) >> ANGLETOFINESHIFT)); } else if (mobj->state == &states[S_MAGICIANBOX_TOP]) // top { From 565a6de546a6bee0d7791932f6dfacd0c3aa01e1 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 04:15:38 -0700 Subject: [PATCH 17/67] Ironman: Don't flip minirankings until you're actually transformed --- src/k_hud.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 47f103f34..e9f8204d5 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1786,7 +1786,10 @@ static boolean K_drawKartPositionFaces(void) bumperx = FACE_X+19; emeraldx = FACE_X+16; - if (skins[players[rankplayer[i]].skin].flags & SF_IRONMAN) + // Flip SF_IRONMAN portraits, but only if they're transformed + if (skins[players[rankplayer[i]].skin].flags & SF_IRONMAN + && !P_MobjWasRemoved(players[rankplayer[i]].mo) + && !(((skin_t*)players[rankplayer[i]].mo->skin)->flags & SF_IRONMAN) ) { flipflag = V_FLIP; xoff = 16; From 29595f946b968a9cb514560532a5192437198041 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 3 Nov 2022 08:47:44 -0400 Subject: [PATCH 18/67] Add V_VFLIP Ironman can now be shitty --- src/deh_tables.c | 1 + src/hardware/hw_draw.c | 17 ++++++++++++++--- src/k_hud.c | 4 ++-- src/v_video.c | 41 +++++++++++++++++++++++++++-------------- src/v_video.h | 9 ++++++--- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 17b5a7bde..63b076d30 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6690,6 +6690,7 @@ struct int_const_s const INT_CONST[] = { {"V_OVERLAY",V_OVERLAY}, {"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE}, {"V_FLIP",V_FLIP}, + {"V_VFLIP",V_VFLIP}, {"V_SNAPTOTOP",V_SNAPTOTOP}, {"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM}, {"V_SNAPTOLEFT",V_SNAPTOLEFT}, diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index b4917751b..b5268986b 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -188,7 +188,10 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p offsetx = (float)(gpatch->leftoffset) * fscalew; // top offset - offsety = (float)(gpatch->topoffset) * fscaleh; + if (option & V_VFLIP) + offsety = (float)(gpatch->height - gpatch->topoffset) * fscaleh; + else + offsety = (float)(gpatch->topoffset) * fscaleh; cx -= offsetx; cy -= offsety; @@ -249,8 +252,16 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p v[2].s = v[1].s = hwrPatch->max_s; } - v[0].t = v[1].t = 0.0f; - v[2].t = v[3].t = hwrPatch->max_t; + if (option & V_VFLIP) + { + v[0].t = v[1].t = hwrPatch->max_t; + v[2].t = v[3].t = 0.0f; + } + else + { + v[0].t = v[1].t = 0.0f; + v[2].t = v[3].t = hwrPatch->max_t; + } flags = PF_NoDepthTest; diff --git a/src/k_hud.c b/src/k_hud.c index e9f8204d5..18d133844 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1791,8 +1791,8 @@ static boolean K_drawKartPositionFaces(void) && !P_MobjWasRemoved(players[rankplayer[i]].mo) && !(((skin_t*)players[rankplayer[i]].mo->skin)->flags & SF_IRONMAN) ) { - flipflag = V_FLIP; - xoff = 16; + flipflag = V_FLIP|V_VFLIP; // blonic flip + xoff = yoff = 16; } else { flipflag = 0; diff --git a/src/v_video.c b/src/v_video.c index 0e85bf2fa..1369ca627 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -593,10 +593,6 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca colfrac = FixedDiv(FRACUNIT, fdup); rowfrac = FixedDiv(FRACUNIT, vdup); - // So it turns out offsets aren't scaled in V_NOSCALESTART unless V_OFFSET is applied ...poo, that's terrible - // For now let's just at least give V_OFFSET the ability to support V_FLIP - // I'll probably make a better fix for 2.2 where I don't have to worry about breaking existing support for stuff - // -- Monster Iestyn 29/10/18 { fixed_t offsetx = 0, offsety = 0; @@ -607,15 +603,17 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca offsetx = FixedMul(patch->leftoffset<topoffset<height - patch->topoffset)<topoffset<= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) break; } + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS])); while (column->topdelta != 0xff) @@ -683,17 +682,31 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca topdelta += prevdelta; prevdelta = topdelta; source = (const UINT8 *)(column) + 3; + dest = desttop; if (scrn & V_FLIP) - dest = deststart + (destend - desttop); + dest = deststart + (destend - dest); dest += FixedInt(FixedMul(topdelta<>FRACBITS) < column->length; ofs += rowfrac) + if (scrn & V_VFLIP) { - if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) - *dest = patchdrawfunc(dest, source, ofs); - dest += vid.width; + for (ofs = (column->length << FRACBITS)-1; dest < deststop && ofs >= 0; ofs -= rowfrac) + { + if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = patchdrawfunc(dest, source, ofs); + dest += vid.width; + } } + else + { + for (ofs = 0; dest < deststop && ofs < (column->length << FRACBITS); ofs += rowfrac) + { + if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + *dest = patchdrawfunc(dest, source, ofs); + dest += vid.width; + } + } + column = (const column_t *)((const UINT8 *)column + column->length + 4); } } @@ -752,7 +765,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ y -= FixedMul(patch->topoffset<leftoffset<>FRACBITS) < column->length && (((ofs>>FRACBITS) - sy) + topdelta) < h; ofs += rowfrac) { - if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION) + if (dest >= screens[scrn&V_SCREENMASK]) // don't draw off the top of the screen (CRASH PREVENTION) *dest = patchdrawfunc(dest, source, ofs); dest += vid.width; } diff --git a/src/v_video.h b/src/v_video.h index 35be68b2f..c3467d31e 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -81,11 +81,14 @@ void V_CubeApply(RGBA_t *input); #define V_GetColor(color) (pLocalPalette[color&0xFF]) #define V_GetMasterColor(color) (pMasterPalette[color&0xFF]) -// Bottom 8 bits are used for parameter (screen or character) +// Bottom 8 bits are used for parameter (character) #define V_PARAMMASK 0x000000FF -// strings/characters only -#define V_STRINGDANCE 0x00000002 +// Bottom bit is used for screen (patches) +#define V_SCREENMASK 0x0000000F + +#define V_STRINGDANCE 0x00000002 // (strings/characters only) funny undertale +#define V_VFLIP 0x00000010 // (patches only) Vertical flip // flags hacked in scrn (not supported by all functions (see src)) // patch scaling uses bits 9 and 10 From 8d4688af12ffc157f048eae422ec61581ae65110 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 06:15:45 -0700 Subject: [PATCH 19/67] Ironman: fix non-Race transformations and true death skin restore --- src/p_user.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 03c35affe..1ef60277a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4169,12 +4169,13 @@ void P_PlayerThink(player_t *player) { player->stairjank--; } + // Random skin / "ironman" - if ((!P_MobjWasRemoved(player->mo)) & (skins[player->skin].flags & SF_IRONMAN)) // we are Heavy Magician with a mobj + if ((!P_MobjWasRemoved(player->mo)) && (skins[player->skin].flags & SF_IRONMAN)) // we are Heavy Magician with a mobj { if (((skin_t *)player->mo->skin)->flags & SF_IRONMAN) // no fakeskin yet { - if (leveltime >= introtime && !player->exiting) + if (leveltime >= starttime && !player->exiting) { if (player->fakeskin != MAXSKINS) { From 0a8e3046e609754bd5a6f040d431ac6dd7060748 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 14:58:45 -0700 Subject: [PATCH 20/67] Ironman: appease pedantry --- src/m_random.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/m_random.h b/src/m_random.h index dc6f1884b..34e4c34c8 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -46,6 +46,7 @@ typedef enum PR_PLAYERSTARTS, // Player starts PR_VOICES, // Player voice sounds + PR_RANDOMSKIN, // Random skin select from Heavy Magician(?) PR_RULESCRAMBLE, // Rule scrambing events @@ -62,8 +63,6 @@ typedef enum PR_MOVINGTARGET, // Randomised moving targets - PR_RANDOMSKIN, // Random skin select from Heavy Magician(?) - PRNUMCLASS } pr_class_t; From 7c839e841aac87f04591bcd7965744d2ae263b1e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 15:05:43 -0700 Subject: [PATCH 21/67] Ironman: use P_SetTarget helper where appropriate --- src/p_mobj.c | 2 +- src/r_skins.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 5fb2b7114..31ad11939 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7630,7 +7630,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else if (mobj->extravalue2 < TICRATE/3) { - mobj->target = NULL; + P_SetTarget(&mobj->target, NULL); if (mobj->extravalue2 & 1) mobj->renderflags |= RF_DONTDRAW; else diff --git a/src/r_skins.c b/src/r_skins.c index 180ee2678..eb92bc806 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -369,7 +369,7 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) for (j = 0; j < 6; j++) // 0-3 = sides, 4 = top, 5 = bottom { mobj_t *box = P_SpawnMobjFromMobj(parent, 0, 0, 0, MT_MAGICIANBOX); - box->target = parent; + P_SetTarget(&box->target, parent); box->angle = FixedAngle((baseangle + j*90) * FRACUNIT); box->flags2 |= MF2_AMBUSH; if (fast) From 1410b6c0e0e6796829a6d6a017d8884a3a6d9c76 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 15:44:49 -0700 Subject: [PATCH 22/67] Ironman: visibility/hyudoro behavior cleanup --- src/p_mobj.c | 27 +++++++++++++++++++-------- src/r_skins.c | 9 +++++++-- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 31ad11939..05fd8669d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7636,11 +7636,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) else mobj->renderflags &= ~RF_DONTDRAW; } - else if (mobj->extravalue2 == TICRATE/3 && mobj->target) + else if (mobj->extravalue2 == TICRATE/3 && !P_MobjWasRemoved(mobj->target)) { - - mobj->target->renderflags &= ~RF_DONTDRAW; - mobj->momx = mobj->target->momx; mobj->momy = mobj->target->momy; mobj->momz = mobj->target->momz; @@ -7659,15 +7656,29 @@ static boolean P_MobjRegularThink(mobj_t *mobj) S_StartSound(mobj, sfx_kc2e); S_StartSound(mobj, sfx_s3k9f); - K_SpawnMagicianParticles(mobj, 5); + if (mobj->target->player->hyudorotimer) + { + P_RemoveMobj(mobj); + break; + } + else + { + K_SpawnMagicianParticles(mobj, 5); + } return true; } - else + else if (mobj->target && !P_MobjWasRemoved(mobj->target)) { - mobj->target->renderflags |= RF_DONTDRAW; + mobj->renderflags &= ~RF_DONTDRAW; + mobj->renderflags |= (mobj->target->renderflags & RF_DONTDRAW); + // NB: This depends on order of thinker execution! + // SetRandomFakePlayerSkin (r_skins.c) sets cusval on the bottom (last) side (i=5). + // This writes to the player's visibility only after every other side has ticked and inherited it. + if (mobj->cusval) + mobj->target->renderflags |= RF_DONTDRAW; } - if (!mobj->target || !mobj->target->health || !mobj->target->player) { + if (P_MobjWasRemoved(mobj->target) || !mobj->target->health || !mobj->target->player) { mobj->extravalue2 = min(mobj->extravalue2, TICRATE/3); return true; } diff --git a/src/r_skins.c b/src/r_skins.c index eb92bc806..ec1eaf1cb 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -382,8 +382,13 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) box->extravalue1 = 1; box->extravalue2 = 3*TICRATE/2; } - if (j == 0) - box->cusval = 1; // Should play sounds when disappearing + + // cusval controls behavior that should run only once, like disappear FX and RF_DONTDRAW handling. + // NB: Order of thinker execution matters here! + // We want the other sides to inherit the player's "existing" RF_DONTDRAW before the last side writes to it. + // See the MT_MAGICIANBOX thinker in p_mobj.c. + if (j == 5) + box->cusval = 1; else box->cusval = 0; From 0353512b053c45dbbcfab81fb378bf82b90cd2e2 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 16:01:25 -0700 Subject: [PATCH 23/67] Ironman: Keep player_t charflags up to date in demos --- src/g_demo.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index bacc64063..d5d01cc43 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -266,6 +266,7 @@ void G_ReadDemoExtraData(void) if (extradata & DXD_SKIN) { UINT8 kartspeed, kartweight; + UINT32 charflags; // Skin M_Memcpy(name, demo_p, 16); @@ -274,12 +275,14 @@ void G_ReadDemoExtraData(void) kartspeed = READUINT8(demo_p); kartweight = READUINT8(demo_p); + charflags = READUINT32(demo_p); if (stricmp(skins[players[p].skin].name, name) != 0) FindClosestSkinForStats(p, kartspeed, kartweight); players[p].kartspeed = kartspeed; players[p].kartweight = kartweight; + players[p].charflags = charflags; } if (extradata & DXD_COLOR) { @@ -428,7 +431,7 @@ void G_WriteDemoExtraData(void) WRITEUINT8(demo_p, skins[players[i].skin].kartspeed); WRITEUINT8(demo_p, skins[players[i].skin].kartweight); - + WRITEUINT32(demo_p, skins[players[i].skin].flags); } if (demo_extradata[i] & DXD_COLOR) { @@ -2111,6 +2114,7 @@ void G_BeginRecording(void) WRITEUINT8(demo_p, skins[player->skin].kartspeed); WRITEUINT8(demo_p, skins[player->skin].kartweight); WRITEUINT8(demo_p, player->lastfakeskin); + WRITEUINT32(demo_p, player->charflags); // And mobjtype_t is best with UINT32 too... WRITEUINT32(demo_p, player->followitem); @@ -2711,6 +2715,7 @@ void G_DoPlayDemo(char *defdemoname) boolean spectator; UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], lastfakeskin[MAXPLAYERS], numslots = 0; + UINT32 charflags[MAXPLAYERS]; #if defined(SKIPERRORS) && !defined(DEVELOP) boolean skiperrors = false; @@ -3088,6 +3093,7 @@ void G_DoPlayDemo(char *defdemoname) kartspeed[p] = READUINT8(demo_p); kartweight[p] = READUINT8(demo_p); lastfakeskin[p] = READUINT8(demo_p); + charflags[p] = READUINT32(demo_p); if (stricmp(skins[players[p].skin].name, skin) != 0) FindClosestSkinForStats(p, kartspeed[p], kartweight[p]); @@ -3146,6 +3152,7 @@ void G_DoPlayDemo(char *defdemoname) players[i].kartspeed = kartspeed[i]; players[i].kartweight = kartweight[i]; players[i].lastfakeskin = lastfakeskin[i]; + players[i].charflags = charflags[i]; } demo.deferstart = true; @@ -3338,6 +3345,7 @@ void G_AddGhost(char *defdemoname) kartspeed = READUINT8(p); kartweight = READUINT8(p); p += 1; // lastfakeskin + p += 4; // charflags p += 4; // followitem (maybe change later) From c4f0390ad65b24d5488d62ddcd08c6186f46acba Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 16:04:23 -0700 Subject: [PATCH 24/67] Fix reading follower color from demos --- src/g_demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_demo.c b/src/g_demo.c index d5d01cc43..a4400d4ff 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -318,7 +318,7 @@ void G_ReadDemoExtraData(void) { if (!stricmp(Followercolor_cons_t[i].strvalue, name)) { - players[p].followercolor = i; + players[p].followercolor = Followercolor_cons_t[i].value; break; } } From 80252717c93453c69fe15003eecb9f6fb4abd94c Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 16:19:17 -0700 Subject: [PATCH 25/67] Kill SF_HIRES, use skin_t highresscale instead --- src/d_player.h | 5 ++--- src/deh_tables.c | 1 - src/hardware/hw_main.c | 2 +- src/k_menudraw.c | 2 +- src/p_user.c | 2 +- src/r_skins.c | 1 - src/r_splats.c | 2 +- src/r_things.c | 6 +++--- 8 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 10a9cf3a9..c5dcb495a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -35,9 +35,8 @@ // Extra abilities/settings for skins (combinable stuff) typedef enum { - SF_HIRES = 1, // Draw the sprite at different size? - SF_MACHINE = 1<<1, // Beep boop. Are you a robot? - SF_IRONMAN = 1<<2, // Pick a new skin during POSITION. I main Random! + SF_MACHINE = 1, // Beep boop. Are you a robot? + SF_IRONMAN = 1<<1, // Pick a new skin during POSITION. I main Random! // free up to and including 1<<31 } skinflags_t; diff --git a/src/deh_tables.c b/src/deh_tables.c index 63b076d30..4f0829415 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6321,7 +6321,6 @@ struct int_const_s const INT_CONST[] = { {"CR_ZOOMTUBE",CR_ZOOMTUBE}, // Character flags (skinflags_t) - {"SF_HIRES",SF_HIRES}, {"SF_MACHINE",SF_MACHINE}, {"SF_IRONMAN",SF_IRONMAN}, diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 74385e7f7..32f46bda3 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5298,7 +5298,7 @@ static void HWR_ProjectSprite(mobj_t *thing) flip ^= (1<skin && ((skin_t *)thing->skin)->flags & SF_HIRES) + if (thing->skin && ((skin_t *)thing->skin)->highresscale != FRACUNIT) this_scale *= FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); spr_width = spritecachedinfo[lumpoff].width; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 92e47cb2f..5e20c0790 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1178,7 +1178,7 @@ static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, INT32 addflag if (sprframe->flip & 1) // Only for first sprite flags |= V_FLIP; // This sprite is left/right flipped! - if (skins[skin].flags & SF_HIRES) + if (skins[skin].highresscale != FRACUNIT) { V_DrawFixedPatch(x<stairjank--; } - + // Random skin / "ironman" if ((!P_MobjWasRemoved(player->mo)) && (skins[player->skin].flags & SF_IRONMAN)) // we are Heavy Magician with a mobj { diff --git a/src/r_skins.c b/src/r_skins.c index ec1eaf1cb..fe9007652 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -563,7 +563,6 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) // parameters for individual character flags // these are uppercase so they can be concatenated with SF_ // 1, true, yes are all valid values - GETFLAG(HIRES) GETFLAG(MACHINE) GETFLAG(IRONMAN) #undef GETFLAG diff --git a/src/r_splats.c b/src/r_splats.c index 80ff44743..011e1d9eb 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -181,7 +181,7 @@ void R_DrawFloorSplat(vissprite_t *spr) splat.height = spr->patch->height; splat.scale = mobj->scale; - if (mobj->skin && ((skin_t *)mobj->skin)->flags & SF_HIRES) + if (mobj->skin && ((skin_t *)mobj->skin)->highresscale != FRACUNIT) splat.scale = FixedMul(splat.scale, ((skin_t *)mobj->skin)->highresscale); if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) diff --git a/src/r_things.c b/src/r_things.c index 41dfc8585..d1398e9ea 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -945,7 +945,7 @@ static void R_DrawVisSprite(vissprite_t *vis) frac = vis->startfrac; windowtop = windowbottom = sprbotscreen = INT32_MAX; - if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) + if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->highresscale != FRACUNIT) this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale); if (this_scale <= 0) @@ -1410,7 +1410,7 @@ static void R_ProjectDropShadow( shadow->gzt = groundz + patch->height * shadowyscale / 2; shadow->gz = shadow->gzt - patch->height * shadowyscale; shadow->texturemid = FixedMul(interp.scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); - if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) + if (thing->skin && ((skin_t *)thing->skin)->highresscale != FRACUNIT) shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale); shadow->scalestep = 0; shadow->shear.tan = shadowskew; // repurposed variable @@ -1797,7 +1797,7 @@ static void R_ProjectSprite(mobj_t *thing) I_Assert(lump < max_spritelumps); - if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) + if (thing->skin && ((skin_t *)thing->skin)->highresscale != FRACUNIT) this_scale = FixedMul(this_scale, ((skin_t *)thing->skin)->highresscale); spr_width = spritecachedinfo[lump].width; From d95244a693afe6bd589e81528f0a48c0dec8a7e1 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 22:15:40 -0700 Subject: [PATCH 26/67] Ironman: Don't carry modified stats into the next race --- src/g_game.c | 9 ++++++++- src/r_skins.c | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index acf3b9c6d..8b27e6d46 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2441,10 +2441,17 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->botvars.rival = botrival; p->xtralife = xtralife; - if (betweenmaps) + if (betweenmaps) + { p->fakeskin = MAXSKINS; + p->kartspeed = skins[p->skin].kartspeed; + p->kartweight = skins[p->skin].kartweight; + } else + { p->fakeskin = fakeskin; + } + p->lastfakeskin = lastfakeskin; // SRB2kart diff --git a/src/r_skins.c b/src/r_skins.c index fe9007652..3bf406fe3 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -410,6 +410,10 @@ void ClearFakePlayerSkin(player_t* player) if (!P_MobjWasRemoved(player->mo)) { player->mo->skin = &skins[player->skin]; + player->fakeskin = MAXSKINS; + player->kartspeed = skins[player->skin].kartspeed; + player->kartweight = skins[player->skin].kartweight; + player->charflags = skins[player->skin].flags; S_StartSound(player->mo, sfx_s3k9f); K_SpawnMagicianParticles(player->mo, 5); } From 01c35b7957416d249051f9b298e341cc57e7a3b8 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 3 Nov 2022 22:22:47 -0700 Subject: [PATCH 27/67] Ironman: Don't do detransform unless your real skin is actually SF_IRONMAN --- src/r_skins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_skins.c b/src/r_skins.c index 3bf406fe3..9068a1021 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -407,7 +407,7 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) // Return to base skin from an SF_IRONMAN randomization void ClearFakePlayerSkin(player_t* player) { - if (!P_MobjWasRemoved(player->mo)) + if ((skins[player->skin].flags & SF_IRONMAN) && !P_MobjWasRemoved(player->mo)) { player->mo->skin = &skins[player->skin]; player->fakeskin = MAXSKINS; From c77147fd1c048e7d0272f75f98f38b1a6f523e3b Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 26 Oct 2022 20:27:32 +0100 Subject: [PATCH 28/67] Rewrite ping timeout - Reduce the joiner grace period for normal ping limit to 10 seconds (from 30) - Properly account for ignoring all local players when the host is splitscreen # Conflicts: # src/d_clisrv.c --- src/d_clisrv.c | 68 ++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1387c80e4..673991117 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5529,56 +5529,64 @@ boolean TryRunTics(tic_t realtics) static INT32 pingtimeout[MAXPLAYERS]; +#define PINGKICK_TICQUEUE 2 +#define PINGKICK_LIMIT 1 + static inline void PingUpdate(void) { INT32 i; - boolean laggers[MAXPLAYERS]; - UINT8 numlaggers = 0; - memset(laggers, 0, sizeof(boolean) * MAXPLAYERS); + boolean pingkick[MAXPLAYERS]; + UINT8 nonlaggers = 0; + memset(pingkick, 0, sizeof(pingkick)); netbuffer->packettype = PT_PING; //check for ping limit breakage. if (cv_maxping.value) { - for (i = 1; i < MAXPLAYERS; i++) + for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] - && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) + if (!playeringame[i] || P_IsMachineLocalPlayer(&players[i])) { - if (players[i].jointime > 30 * TICRATE) - laggers[i] = true; - numlaggers++; + pingtimeout[i] = 0; + continue; + } + + if ((cv_maxping.value) + && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value)) + { + if (players[i].jointime > 10 * TICRATE) + { + pingkick[i] = true; + } } else - pingtimeout[i] = 0; + { + nonlaggers++; + + // you aren't lagging, but you aren't free yet. In case you'll keep spiking, we just make the timer go back down. (Very unstable net must still get kicked). + if (pingtimeout[i] > 0) + pingtimeout[i]--; + } } //kick lagging players... unless everyone but the server's ping sucks. //in that case, it is probably the server's fault. - if (numlaggers < D_NumPlayers() - 1) + if (nonlaggers > 0) { - for (i = 1; i < MAXPLAYERS; i++) + for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && laggers[i]) - { - pingtimeout[i]++; + XBOXSTATIC char buf[2]; - // ok your net has been bad for too long, you deserve to die. - if (pingtimeout[i] > cv_pingtimeout.value) - { - pingtimeout[i] = 0; - SendKick(i, KICK_MSG_PING_HIGH); - } - } - /* - you aren't lagging, - but you aren't free yet. - In case you'll keep spiking, - we just make the timer go back down. (Very unstable net must still get kicked). - */ - else - pingtimeout[i] = (pingtimeout[i] == 0 ? 0 : pingtimeout[i]-1); + if (!playeringame[i] || !pingkick[i]) + continue; + + // Don't kick on ping alone if we haven't reached our threshold yet. + if (++pingtimeout[i] < cv_pingtimeout.value) + continue; + + pingtimeout[i] = 0; + SendKick(i, KICK_MSG_PING_HIGH); } } } From 0da626807c436081ad7231be03ef756dc8cd0df5 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 5 Nov 2022 22:48:39 +0000 Subject: [PATCH 29/67] EXPERIMENTAL: Dedicated server idling system - If no clients at server start or after 10 seconds of GS_LEVEL, and no Netxcmd waiting to be digested, halt all SV_MakeTic. - It's absolutely netsafe to only have enabled on the host's end, the only risk is that a dedicated server might not re-awaken when presented with certain stimuli --- src/d_clisrv.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 673991117..22be4dfb7 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5767,6 +5767,9 @@ void NetKeepAlive(void) FileSendTicker(); } +// If a tree falls in the forest but nobody is around to hear it, does it make a tic? +#define DEDICATEDIDLETIME (10*TICRATE) + void NetUpdate(void) { static tic_t resptime = 0; @@ -5779,6 +5782,7 @@ void NetUpdate(void) if (realtics <= 0) // nothing new to update return; + if (realtics > 5) { if (server) @@ -5787,6 +5791,55 @@ void NetUpdate(void) realtics = 5; } +#ifdef DEDICATEDIDLETIME + if (server && dedicated && gamestate == GS_LEVEL) + { + static tic_t dedicatedidle = 0; + + for (i = 1; i < MAXNETNODES; ++i) + if (nodeingame[i]) + { + if (dedicatedidle == DEDICATEDIDLETIME) + { + CONS_Printf("DEDICATED: Awakening from idle (Node %d detected...)\n", i); + dedicatedidle = 0; + } + break; + } + + if (i == MAXNETNODES) + { + if (leveltime == 2) + { + // On next tick... + dedicatedidle = DEDICATEDIDLETIME-1; + } + else if (dedicatedidle == DEDICATEDIDLETIME) + { + if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic+1, 0)) + { + CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n"); + dedicatedidle = 0; + } + else + { + realtics = 0; + } + } + else if ((dedicatedidle += realtics) >= DEDICATEDIDLETIME) + { + const char *idlereason = "at round start"; + if (leveltime > 3) + idlereason = va("for %d seconds", dedicatedidle/TICRATE); + + CONS_Printf("DEDICATED: No nodes %s, idling...\n", idlereason); + realtics = 0; + dedicatedidle = DEDICATEDIDLETIME; + } + } + } +#endif + gametime = nowtime; UpdatePingTable(); @@ -5824,7 +5877,7 @@ void NetUpdate(void) } else { - if (!demo.playback) + if (!demo.playback && realtics > 0) { INT32 counts; From 34540b9caadd245174379287380695864d3cf4d7 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 5 Nov 2022 22:53:26 +0000 Subject: [PATCH 30/67] More consistently time out people nearing the end of the BACKUPTICS, not just if they cross the line, to match desired v1 behaviour --- src/d_clisrv.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 22be4dfb7..f6bb86d39 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5883,19 +5883,20 @@ void NetUpdate(void) hu_redownloadinggamestate = false; - firstticstosend = gametic; - for (i = 0; i < MAXNETNODES; i++) - if (nodeingame[i] && nettics[i] < firstticstosend) - { - firstticstosend = nettics[i]; - - if (maketic + 1 >= nettics[i] + BACKUPTICS) - Net_ConnectionTimeout(i); - } - // Don't erase tics not acknowledged counts = realtics; + firstticstosend = gametic; + for (i = 0; i < MAXNETNODES; i++) + { + if (!nodeingame[i]) + continue; + if (nettics[i] < firstticstosend) + firstticstosend = nettics[i]; + if (maketic + counts >= nettics[i] + (BACKUPTICS - TICRATE)) + Net_ConnectionTimeout(i); + } + if (maketic + counts >= firstticstosend + BACKUPTICS) counts = firstticstosend+BACKUPTICS-maketic-1; From ebdb5db50214be4425b26f85775190685f54e355 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 5 Nov 2022 22:57:44 +0000 Subject: [PATCH 31/67] Unused variable cropped up during porting --- src/d_clisrv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f6bb86d39..39e1fe1a0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5576,8 +5576,6 @@ static inline void PingUpdate(void) { for (i = 0; i < MAXPLAYERS; i++) { - XBOXSTATIC char buf[2]; - if (!playeringame[i] || !pingkick[i]) continue; From 11209c5d24917f329efc45a16f2668b0957ffed4 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 00:16:16 +0000 Subject: [PATCH 32/67] Fix the most significant, immediately-apparent problems with Dedicated - Don't load level twice (only became apparent thanks to new console print warnings) - Get first map of gametype instead of defaulting to Test Run - Don't apply profile material --- src/d_main.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 7fb82482e..20df9f9ae 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1205,7 +1205,7 @@ void D_SRB2Main(void) INT32 numbasemapheaders; - INT32 pstartmap = 1; + INT32 pstartmap = 0; boolean autostart = false; /* break the version string into version numbers, for netplay */ @@ -1759,11 +1759,14 @@ void D_SRB2Main(void) // Has to be done before anything else so skin, color, etc in command buffer has an affect. // ttlprofilen used because it's roughly equivalent in functionality - a QoL aid for quickly getting from startup to action - PR_ApplyProfile(cv_ttlprofilen.value, 0); - - for (i = 1; i < cv_splitplayers.value; i++) + if (!dedicated) { - PR_ApplyProfile(cv_lastprofile[i].value, i); + PR_ApplyProfile(cv_ttlprofilen.value, 0); + + for (i = 1; i < cv_splitplayers.value; i++) + { + PR_ApplyProfile(cv_lastprofile[i].value, i); + } } if (autostart || netgame) @@ -1845,8 +1848,13 @@ void D_SRB2Main(void) CV_SetValue(&cv_kartspeed, newskill); } - if (server && !M_CheckParm("+map")) + if (server && (dedicated || !M_CheckParm("+map"))) { + if (!pstartmap && (pstartmap = G_GetFirstMapOfGametype(gametype)+1) > nummapheaders) + { + I_Error("Can't get first map of gametype\n"); + } + if (M_MapLocked(pstartmap)) { G_SetUsedCheats(); @@ -1868,14 +1876,6 @@ void D_SRB2Main(void) CON_ToggleOff(); - if (dedicated && server) - { - levelstarttic = gametic; - G_SetGamestate(GS_LEVEL); - if (!P_LoadLevel(false, false)) - I_Quit(); // fail so reset game stuff - } - #ifdef HAVE_DISCORDRPC if (! dedicated) { From 0f471b1cf10c442fa698f4c5386cedee9616f8ec Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 6 Nov 2022 13:15:17 +0000 Subject: [PATCH 33/67] Move some command and cvar registering between D_RegisterServerCommands and D_RegisterClientCommands depending on whether a dedicated server needs them or not --- src/d_netcmd.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 51d205931..c01e97b59 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -802,8 +802,6 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_pingmeasurement); CV_RegisterVar(&cv_showviewpointtext); - CV_RegisterVar(&cv_director); - CV_RegisterVar(&cv_schedule); CV_RegisterVar(&cv_automate); CV_RegisterVar(&cv_livestudioaudience); @@ -816,6 +814,23 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_discordinvites); RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo); + + COM_AddCommand("numthinkers", Command_Numthinkers_f); + COM_AddCommand("countmobjs", Command_CountMobjs_f); + + CV_RegisterVar(&cv_recordmultiplayerdemos); + CV_RegisterVar(&cv_netdemosyncquality); + + CV_RegisterVar(&cv_shoutname); + CV_RegisterVar(&cv_shoutcolor); + CV_RegisterVar(&cv_autoshout); + +#ifdef _DEBUG + COM_AddCommand("causecfail", Command_CauseCfail_f); +#endif +#ifdef LUA_ALLOW_BYTECODE + COM_AddCommand("dumplua", Command_Dumplua_f); +#endif } // ========================================================================= @@ -860,9 +875,6 @@ void D_RegisterClientCommands(void) if (dedicated) return; - COM_AddCommand("numthinkers", Command_Numthinkers_f); - COM_AddCommand("countmobjs", Command_CountMobjs_f); - COM_AddCommand("changeteam", Command_Teamchange_f); COM_AddCommand("changeteam2", Command_Teamchange2_f); COM_AddCommand("changeteam3", Command_Teamchange3_f); @@ -958,9 +970,6 @@ void D_RegisterClientCommands(void) COM_AddCommand("displayplayer", Command_Displayplayer_f); - CV_RegisterVar(&cv_recordmultiplayerdemos); - CV_RegisterVar(&cv_netdemosyncquality); - // FIXME: not to be here.. but needs be done for config loading CV_RegisterVar(&cv_globalgamma); CV_RegisterVar(&cv_globalsaturation); @@ -996,10 +1005,6 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_chatnotifications); CV_RegisterVar(&cv_chatbacktint); - CV_RegisterVar(&cv_shoutname); - CV_RegisterVar(&cv_shoutcolor); - CV_RegisterVar(&cv_autoshout); - CV_RegisterVar(&cv_songcredits); CV_RegisterVar(&cv_tutorialprompt); CV_RegisterVar(&cv_showfocuslost); @@ -1047,7 +1052,6 @@ void D_RegisterClientCommands(void) // screen.c CV_RegisterVar(&cv_fullscreen); CV_RegisterVar(&cv_renderview); - CV_RegisterVar(&cv_renderhitbox); CV_RegisterVar(&cv_vhseffect); CV_RegisterVar(&cv_shittyscreen); CV_RegisterVar(&cv_renderer); @@ -1055,6 +1059,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_scr_width); CV_RegisterVar(&cv_scr_height); + CV_RegisterVar(&cv_director); + CV_RegisterVar(&cv_soundtest); CV_RegisterVar(&cv_invincmusicfade); @@ -1075,7 +1081,7 @@ void D_RegisterClientCommands(void) // CV_RegisterVar(&cv_grid); // CV_RegisterVar(&cv_snapto); - // add cheat commands + // add cheats COM_AddCommand("noclip", Command_CheatNoClip_f); COM_AddCommand("god", Command_CheatGod_f); COM_AddCommand("setrings", Command_Setrings_f); @@ -1089,12 +1095,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("rteleport", Command_RTeleport_f); COM_AddCommand("skynum", Command_Skynum_f); COM_AddCommand("weather", Command_Weather_f); -#ifdef _DEBUG - COM_AddCommand("causecfail", Command_CauseCfail_f); -#endif -#ifdef LUA_ALLOW_BYTECODE - COM_AddCommand("dumplua", Command_Dumplua_f); -#endif + CV_RegisterVar(&cv_renderhitbox); #ifdef HAVE_DISCORDRPC CV_RegisterVar(&cv_discordrp); From 990e342b12917de6ffa4788779f72404ae04b73c Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 6 Nov 2022 06:20:28 -0800 Subject: [PATCH 34/67] Fix KITEM DEH list not defined with KITEM_ prefix --- src/deh_tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 383823833..7cb97c82a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6756,7 +6756,7 @@ struct int_const_s const INT_CONST[] = { // SRB2Kart // kartitems_t -#define FOREACH( name, n ) { #name, KITEM_ ## name } +#define FOREACH( name, n ) { TOSTR (KITEM_ ## name), KITEM_ ## name } KART_ITEM_ITERATOR, // Actual items (can be set for k_itemtype) #undef FOREACH {"NUMKARTITEMS",NUMKARTITEMS}, From f5f94b977e6b3583941c4120245527aa404f70d0 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 12 Nov 2022 17:42:16 +0000 Subject: [PATCH 35/67] Deprecated constants flagged in review --- src/d_clisrv.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 39e1fe1a0..5fe4034c0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5529,9 +5529,6 @@ boolean TryRunTics(tic_t realtics) static INT32 pingtimeout[MAXPLAYERS]; -#define PINGKICK_TICQUEUE 2 -#define PINGKICK_LIMIT 1 - static inline void PingUpdate(void) { INT32 i; From 8882406ff34664844a00690f059c4b1fe5f46696 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 12 Nov 2022 17:48:00 +0000 Subject: [PATCH 36/67] On second thoughts, restrict ANY profile application in dedicated - not just on initial startup - to the Guest profile --- src/k_profiles.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/k_profiles.c b/src/k_profiles.c index 5f50d189f..05cd60155 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -449,9 +449,10 @@ void PR_ApplyProfile(UINT8 profilenum, UINT8 playernum) profile_t *p = PR_GetProfile(profilenum); // this CAN happen!! - if (p == NULL) + if (dedicated || p == NULL) { - CONS_Printf("Profile '%d' could not be loaded as it does not exist. Guest Profile will be loaded instead.\n", profilenum); + if (!dedicated) + CONS_Printf("Profile '%d' could not be loaded as it does not exist. Guest Profile will be loaded instead.\n", profilenum); profilenum = 0; // make sure to set this so that the cvar is set properly. p = PR_GetProfile(profilenum); } @@ -481,9 +482,10 @@ void PR_ApplyProfilePretend(UINT8 profilenum, UINT8 playernum) profile_t *p = PR_GetProfile(profilenum); // this CAN happen!! - if (p == NULL) + if (dedicated || p == NULL) { - CONS_Printf("Profile '%d' could not be loaded as it does not exist. Guest Profile will be loaded instead.\n", profilenum); + if (!dedicated) + CONS_Printf("Profile '%d' could not be loaded as it does not exist. Guest Profile will be loaded instead.\n", profilenum); profilenum = 0; // make sure to set this so that the cvar is set properly. p = PR_GetProfile(profilenum); } From f06d4b4369ad08d4523bedf7c16d28dc2e5a7915 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Nov 2022 22:37:16 +0000 Subject: [PATCH 37/67] Only return early for floordiff if under-water surface is SLOPED --- src/p_mobj.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index d5924de51..43e6139b1 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3218,14 +3218,15 @@ boolean P_CanRunOnWater(mobj_t *mobj, ffloor_t *rover) // We start water run IF we can step onto it! if (surfDiff <= maxStep && surfDiff >= 0) { - if (ourZAng < 0) + pslope_t *groundSlope = (flip ? mobj->subsector->sector->c_slope : mobj->subsector->sector->f_slope); + if (groundSlope != NULL && groundSlope->zangle != 0) { fixed_t floorheight = flip ? P_GetSectorCeilingZAt(mobj->subsector->sector, mobj->x, mobj->y) : P_GetSectorFloorZAt(mobj->subsector->sector, mobj->x, mobj->y); fixed_t floorDiff = flip ? (floorheight - mobjbottom) : (mobjbottom - floorheight); if (floorDiff <= maxStep && floorDiff >= -maxStep) { - // ... but NOT if going down and real floor is in range. - // FIXME: Count solid FOFs in this check + // ... but NOT if downward-sloping real floor is in range. + // FIXME: Count solid FOFs in these checks return false; } } From f83b14e16e07f75503ae8eb56d42c5b35e01acb1 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Nov 2022 22:39:14 +0000 Subject: [PATCH 38/67] Minimum speed of 40% for waterskii (resolves #327) Not 50% to catch spindashing better --- src/k_kart.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 40d1ff0a2..f435ae9e4 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3445,6 +3445,8 @@ boolean K_WaterRun(mobj_t *mobj) case MT_PLAYER: { + fixed_t minspeed = 0; + if (mobj->player == NULL) { return false; @@ -3455,11 +3457,18 @@ boolean K_WaterRun(mobj_t *mobj) return K_IsHoldingDownTop(mobj->player) == false; } + minspeed = 2 * K_GetKartSpeed(mobj->player, false, false); // 200% + + if (mobj->player->speed < minspeed / 5) // 40% + { + return false; + } + if (mobj->player->invincibilitytimer || mobj->player->sneakertimer || mobj->player->tiregrease || mobj->player->flamedash - || mobj->player->speed > 2 * K_GetKartSpeed(mobj->player, false, false)) + || mobj->player->speed > minspeed) { return true; } From 2e0365e399effba8cd24e6433a1f4fec9e1aca8e Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 19 Nov 2022 22:41:30 +0000 Subject: [PATCH 39/67] Attenuate fastfall bounce underwater (resolves #329) Probably not worth a branch all by itself, and this branch is already pretty wet --- src/k_kart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index f435ae9e4..6bb2be28e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10371,6 +10371,9 @@ boolean K_FastFallBounce(player_t *player) } } + if (player->mo->eflags & MFE_UNDERWATER) + bounce = (117 * bounce) / 200; + S_StartSound(player->mo, sfx_ffbonc); player->mo->momz = bounce * P_MobjFlip(player->mo); From b31aa1bbb09beb7bda56912f9557022d4b0dc521 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 20 Nov 2022 19:27:34 -0500 Subject: [PATCH 40/67] Put tm* variables into a struct This makes it significantly easier to save/restore the state of these variables, whenever we need to do so for calling movement functions in the middle of other movement functions. This will also make it easier to move it out of global variable hell if desired later. --- src/f_finale.c | 2 +- src/k_collide.c | 6 +- src/lua_baselib.c | 72 +-- src/lua_maplib.c | 16 +- src/lua_mobjlib.c | 36 +- src/p_enemy.c | 8 +- src/p_local.h | 47 +- src/p_map.c | 1367 ++++++++++++++++++++++----------------------- src/p_maputl.c | 50 +- src/p_maputl.h | 2 - src/p_mobj.c | 68 +-- src/p_polyobj.c | 10 +- src/p_setup.c | 8 +- src/p_sight.c | 6 +- 14 files changed, 830 insertions(+), 868 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index a0ae60cf2..ca5b44fb3 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2729,7 +2729,7 @@ void F_EndTextPrompt(boolean forceexec, boolean noexec) // \todo net safety, maybe loop all player thinkers? if ((promptwasactive || forceexec) && !noexec && promptpostexectag) { - if (tmthing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail + if (tm.thing) // edge case where starting an invalid prompt immediately on level load will make P_MapStart fail P_LinedefExecute(promptpostexectag, promptmo, NULL); else { diff --git a/src/k_collide.c b/src/k_collide.c index d3b9bc60c..6a67e5a04 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -655,12 +655,12 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2) { // Counter desyncs /*mobj_t *oldthing = thing; - mobj_t *oldtmthing = tmthing; + mobj_t *oldtm.thing = tm.thing; - P_Thrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), 4*thing->scale); + P_Thrust(tm.thing, R_PointToAngle2(thing->x, thing->y, tm.thing->x, tm.thing->y), 4*thing->scale); thing = oldthing; - P_SetTarget(&tmthing, oldtmthing);*/ + P_SetTarget(&tm.thing, oldtm.thing);*/ if (P_PlayerInPain(t2->player) || t2->player->flashing || t2->player->hyudorotimer diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d73e7b073..57a260374 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1004,108 +1004,108 @@ static int lib_pRemoveFloorSpriteSlope(lua_State *L) static int lib_pRailThinker(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!mobj) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_RailThinker(mobj)); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 1; } static int lib_pXYMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_XYMovement(actor); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 0; } static int lib_pRingXYMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_RingXYMovement(actor); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 0; } static int lib_pSceneryXYMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_SceneryXYMovement(actor); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 0; } static int lib_pZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_ZMovement(actor)); P_CheckPosition(actor, actor->x, actor->y); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 1; } static int lib_pRingZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_RingZMovement(actor); P_CheckPosition(actor, actor->x, actor->y); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 0; } static int lib_pSceneryZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SceneryZMovement(actor)); P_CheckPosition(actor, actor->x, actor->y); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 1; } static int lib_pPlayerZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_PlayerZMovement(actor); P_CheckPosition(actor, actor->x, actor->y); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 0; } @@ -1307,13 +1307,13 @@ static int lib_pGivePlayerLives(lua_State *L) static int lib_pMovePlayer(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; NOHUD INLEVEL if (!player) return LUA_ErrInvalid(L, "player_t"); P_MovePlayer(player); - P_SetTarget(&tmthing, ptmthing); + tm = ptm; return 0; } @@ -1385,7 +1385,7 @@ static int lib_pNukeEnemies(lua_State *L) static int lib_pCheckPosition(lua_State *L) { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1394,14 +1394,14 @@ static int lib_pCheckPosition(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_CheckPosition(thing, x, y)); - LUA_PushUserdata(L, tmthing, META_MOBJ); - P_SetTarget(&tmthing, ptmthing); + LUA_PushUserdata(L, tm.thing, META_MOBJ); + tm = ptm; return 2; } static int lib_pTryMove(lua_State *L) { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1411,14 +1411,14 @@ static int lib_pTryMove(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff)); - LUA_PushUserdata(L, tmthing, META_MOBJ); - P_SetTarget(&tmthing, ptmthing); + LUA_PushUserdata(L, tm.thing, META_MOBJ); + tm = ptm; return 2; } static int lib_pMove(lua_State *L) { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t speed = luaL_checkfixed(L, 2); NOHUD @@ -1426,14 +1426,14 @@ static int lib_pMove(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_Move(actor, speed)); - LUA_PushUserdata(L, tmthing, META_MOBJ); - P_SetTarget(&tmthing, ptmthing); + LUA_PushUserdata(L, tm.thing, META_MOBJ); + tm = ptm; return 2; } static int lib_pTeleportMove(lua_State *L) { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1444,14 +1444,14 @@ static int lib_pTeleportMove(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin"); lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); - LUA_PushUserdata(L, tmthing, META_MOBJ); - P_SetTarget(&tmthing, ptmthing); + LUA_PushUserdata(L, tm.thing, META_MOBJ); + tm = ptm; return 2; } static int lib_pSetOrigin(lua_State *L) { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1461,14 +1461,14 @@ static int lib_pSetOrigin(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SetOrigin(thing, x, y, z)); - LUA_PushUserdata(L, tmthing, META_MOBJ); - P_SetTarget(&tmthing, ptmthing); + LUA_PushUserdata(L, tm.thing, META_MOBJ); + tm = ptm; return 2; } static int lib_pMoveOrigin(lua_State *L) { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); @@ -1478,8 +1478,8 @@ static int lib_pMoveOrigin(lua_State *L) if (!thing) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); - LUA_PushUserdata(L, tmthing, META_MOBJ); - P_SetTarget(&tmthing, ptmthing); + LUA_PushUserdata(L, tm.thing, META_MOBJ); + tm = ptm; return 2; } diff --git a/src/lua_maplib.c b/src/lua_maplib.c index f89059402..209e8732e 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -722,7 +722,7 @@ static int sector_set(lua_State *L) return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); case sector_floorheight: { // floorheight boolean flag; - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; fixed_t lastpos = sector->floorheight; sector->floorheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); @@ -731,12 +731,12 @@ static int sector_set(lua_State *L) sector->floorheight = lastpos; P_CheckSector(sector, true); } - P_SetTarget(&tmthing, ptmthing); + tm = ptm; break; } case sector_ceilingheight: { // ceilingheight boolean flag; - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; fixed_t lastpos = sector->ceilingheight; sector->ceilingheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); @@ -745,7 +745,7 @@ static int sector_set(lua_State *L) sector->ceilingheight = lastpos; P_CheckSector(sector, true); } - P_SetTarget(&tmthing, ptmthing); + tm = ptm; break; } case sector_floorpic: @@ -2127,7 +2127,7 @@ static int ffloor_set(lua_State *L) case ffloor_topheight: { // topheight boolean flag; fixed_t lastpos = *ffloor->topheight; - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; sector_t *sector = §ors[ffloor->secnum]; sector->ceilingheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); @@ -2136,7 +2136,7 @@ static int ffloor_set(lua_State *L) *ffloor->topheight = lastpos; P_CheckSector(sector, true); } - P_SetTarget(&tmthing, ptmthing); + tm = ptm; break; } case ffloor_toppic: @@ -2148,7 +2148,7 @@ static int ffloor_set(lua_State *L) case ffloor_bottomheight: { // bottomheight boolean flag; fixed_t lastpos = *ffloor->bottomheight; - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; sector_t *sector = §ors[ffloor->secnum]; sector->floorheight = luaL_checkfixed(L, 3); flag = P_CheckSector(sector, true); @@ -2157,7 +2157,7 @@ static int ffloor_set(lua_State *L) *ffloor->bottomheight = lastpos; P_CheckSector(sector, true); } - P_SetTarget(&tmthing, ptmthing); + tm = ptm; break; } case ffloor_bottompic: diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index ecd87f49f..8dcf20ac5 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -515,14 +515,14 @@ static int mobj_set(lua_State *L) case mobj_z: { // z doesn't cross sector bounds so it's okay. - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mo->z = luaL_checkfixed(L, 3); P_CheckPosition(mo, mo->x, mo->y); - mo->floorz = tmfloorz; - mo->ceilingz = tmceilingz; - mo->floorrover = tmfloorrover; - mo->ceilingrover = tmceilingrover; - P_SetTarget(&tmthing, ptmthing); + mo->floorz = tm.floorz; + mo->ceilingz = tm.ceilingz; + mo->floorrover = tm.floorrover; + mo->ceilingrover = tm.ceilingrover; + tm = ptm; break; } case mobj_snext: @@ -583,30 +583,30 @@ static int mobj_set(lua_State *L) return NOSET; case mobj_radius: { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mo->radius = luaL_checkfixed(L, 3); if (mo->radius < 0) mo->radius = 0; P_CheckPosition(mo, mo->x, mo->y); - mo->floorz = tmfloorz; - mo->ceilingz = tmceilingz; - mo->floorrover = tmfloorrover; - mo->ceilingrover = tmceilingrover; - P_SetTarget(&tmthing, ptmthing); + mo->floorz = tm.floorz; + mo->ceilingz = tm.ceilingz; + mo->floorrover = tm.floorrover; + mo->ceilingrover = tm.ceilingrover; + tm = ptm; break; } case mobj_height: { - mobj_t *ptmthing = tmthing; + tm_t ptm = tm; mo->height = luaL_checkfixed(L, 3); if (mo->height < 0) mo->height = 0; P_CheckPosition(mo, mo->x, mo->y); - mo->floorz = tmfloorz; - mo->ceilingz = tmceilingz; - mo->floorrover = tmfloorrover; - mo->ceilingrover = tmceilingrover; - P_SetTarget(&tmthing, ptmthing); + mo->floorz = tm.floorz; + mo->ceilingz = tm.ceilingz; + mo->floorrover = tm.floorrover; + mo->ceilingrover = tm.ceilingrover; + tm = ptm; break; } case mobj_momx: diff --git a/src/p_enemy.c b/src/p_enemy.c index 439e5c16e..eb2098280 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -543,10 +543,10 @@ boolean P_Move(mobj_t *actor, fixed_t speed) if (!P_TryMove(actor, tryx, tryy, false)) { - if (actor->flags & MF_FLOAT && floatok) + if (actor->flags & MF_FLOAT && tm.floatok) { // must adjust height - if (actor->z < tmfloorz) + if (actor->z < tm.floorz) actor->z += FixedMul(FLOATSPEED, actor->scale); else actor->z -= FixedMul(FLOATSPEED, actor->scale); @@ -10421,13 +10421,13 @@ void A_FlickyCenter(mobj_t *actor) { actor->extravalue2 = 1; P_SetOrigin(actor, actor->target->x, actor->target->y, actor->target->z); - tmthing = NULL; + P_SetTarget(&tm.thing, NULL); } else if(actor->extravalue2) { actor->extravalue2 = 0; P_SetOrigin(actor, originx, originy, originz); - tmthing = NULL; + P_SetTarget(&tm.thing, NULL); } } } diff --git a/src/p_local.h b/src/p_local.h index f5d613e97..79fb6f3e2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -381,25 +381,46 @@ void P_InternalFlickyHop(mobj_t *actor, fixed_t momz, fixed_t momh, angle_t angl // P_MAP // -// If "floatok" true, move would be ok -// if within "tmfloorz - tmceilingz". -extern boolean floatok; -extern fixed_t tmfloorz; -extern fixed_t tmceilingz; -extern ffloor_t *tmfloorrover, *tmceilingrover; -extern mobj_t *tmfloorthing, *tmhitthing, *tmthing; +typedef struct tm_s +{ + mobj_t *thing; + fixed_t x, y; + fixed_t bbox[4]; + INT32 flags; + + precipmobj_t *precipthing; + fixed_t precipbbox[4]; + + // If "floatok" true, move would be ok + // if within "tm.floorz - tm.ceilingz". + boolean floatok; + + fixed_t floorz, ceilingz; + fixed_t dropoffz, drpoffceilz; // drop-off floor/ceiling heights + mobj_t *floorthing; // the thing corresponding to tm.floorz or NULL if tm.floorz is from a sector + mobj_t *hitthing; // the solid thing you bumped into (for collisions) + ffloor_t *floorrover, *ceilingrover; + pslope_t *floorslope, *ceilingslope; + INT32 floorpic, ceilingpic; + fixed_t floorstep, ceilingstep; + + // keep track of the line that lowers the ceiling, + // so missiles don't explode against sky hack walls + line_t *ceilingline; + + // set by PIT_CheckLine() for any line that stopped the PIT_CheckLine() + // that is, for any line which is 'solid' + line_t *blockingline; +} tm_t; + +extern tm_t tm; + extern camera_t *mapcampointer; -extern fixed_t tmx; -extern fixed_t tmy; -extern pslope_t *tmfloorslope, *tmceilingslope; -extern INT32 tmfloorpic, tmceilingpic; /* cphipps 2004/08/30 */ extern void P_MapStart(void); extern void P_MapEnd(void); -extern line_t *ceilingline; -extern line_t *blockingline; extern msecnode_t *sector_list; extern mprecipsecnode_t *precipsector_list; diff --git a/src/p_map.c b/src/p_map.c index 677954b43..0fc07d0cf 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -44,36 +44,7 @@ #include "m_perfstats.h" // ps_checkposition_calls -fixed_t tmbbox[4]; -mobj_t *tmthing; -static INT32 tmflags; -fixed_t tmx; -fixed_t tmy; - -static precipmobj_t *tmprecipthing; -static fixed_t preciptmbbox[4]; - -// If "floatok" true, move would be ok -// if within "tmfloorz - tmceilingz". -boolean floatok; - -fixed_t tmfloorz, tmceilingz; -static fixed_t tmdropoffz, tmdrpoffceilz; // drop-off floor/ceiling heights -mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz is from a sector -mobj_t *tmhitthing; // the solid thing you bumped into (for collisions) -ffloor_t *tmfloorrover, *tmceilingrover; -pslope_t *tmfloorslope, *tmceilingslope; -INT32 tmfloorpic, tmceilingpic; -static fixed_t tmfloorstep; -static fixed_t tmceilingstep; - -// keep track of the line that lowers the ceiling, -// so missiles don't explode against sky hack walls -line_t *ceilingline; - -// set by PIT_CheckLine() for any line that stopped the PIT_CheckLine() -// that is, for any line which is 'solid' -line_t *blockingline; +tm_t tm = {0}; // Mostly re-ported from DOOM Legacy // Keep track of special lines as they are hit, process them when the move is valid @@ -126,10 +97,10 @@ static boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) if (P_MobjWasRemoved(thing)) return true; - thing->floorz = tmfloorz; - thing->ceilingz = tmceilingz; - thing->floorrover = tmfloorrover; - thing->ceilingrover = tmceilingrover; + thing->floorz = tm.floorz; + thing->ceilingz = tm.ceilingz; + thing->floorrover = tm.floorrover; + thing->ceilingrover = tm.ceilingrover; return true; } @@ -529,32 +500,32 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) { fixed_t blockdist; - if (tmthing == NULL || P_MobjWasRemoved(tmthing) == true) - return BMIT_STOP; // func just popped our tmthing, cannot continue. + if (tm.thing == NULL || P_MobjWasRemoved(tm.thing) == true) + return BMIT_STOP; // func just popped our tm.thing, cannot continue. // Ignore... things. if (thing == NULL || P_MobjWasRemoved(thing) == true) return BMIT_CONTINUE; // don't clip against self - if (thing == tmthing) + if (thing == tm.thing) return BMIT_CONTINUE; // Ignore spectators - if ((tmthing->player && tmthing->player->spectator) + if ((tm.thing->player && tm.thing->player->spectator) || (thing->player && thing->player->spectator)) return BMIT_CONTINUE; // Ignore the collision if BOTH things are in hitlag. - if (thing->hitlag > 0 && tmthing->hitlag > 0) + if (thing->hitlag > 0 && tm.thing->hitlag > 0) return BMIT_CONTINUE; if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) return BMIT_CONTINUE; - blockdist = thing->radius + tmthing->radius; + blockdist = thing->radius + tm.thing->radius; - if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) + if (abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist) return BMIT_CONTINUE; // didn't hit it if (thing->flags & MF_PAPERCOLLISION) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing. @@ -576,47 +547,47 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) junk.dx = 2*cosradius; // v2.x - v1.x; junk.dy = 2*sinradius; // v2.y - v1.y; - if (tmthing->flags & MF_PAPERCOLLISION) // more strenuous checking to prevent clipping issues + if (tm.thing->flags & MF_PAPERCOLLISION) // more strenuous checking to prevent clipping issues { INT32 check1, check2, check3, check4; - fixed_t tmcosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); - fixed_t tmsinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); - if (abs(thing->x - tmx) >= (abs(tmcosradius) + abs(cosradius)) || abs(thing->y - tmy) >= (abs(tmsinradius) + abs(sinradius))) + fixed_t tmcosradius = FixedMul(tm.thing->radius, FINECOSINE(tm.thing->angle>>ANGLETOFINESHIFT)); + fixed_t tmsinradius = FixedMul(tm.thing->radius, FINESINE(tm.thing->angle>>ANGLETOFINESHIFT)); + if (abs(thing->x - tm.x) >= (abs(tmcosradius) + abs(cosradius)) || abs(thing->y - tm.y) >= (abs(tmsinradius) + abs(sinradius))) return BMIT_CONTINUE; // didn't hit it - check1 = P_PointOnLineSide(tmx - tmcosradius, tmy - tmsinradius, &junk); - check2 = P_PointOnLineSide(tmx + tmcosradius, tmy + tmsinradius, &junk); - check3 = P_PointOnLineSide(tmx + tmthing->momx - tmcosradius, tmy + tmthing->momy - tmsinradius, &junk); - check4 = P_PointOnLineSide(tmx + tmthing->momx + tmcosradius, tmy + tmthing->momy + tmsinradius, &junk); + check1 = P_PointOnLineSide(tm.x - tmcosradius, tm.y - tmsinradius, &junk); + check2 = P_PointOnLineSide(tm.x + tmcosradius, tm.y + tmsinradius, &junk); + check3 = P_PointOnLineSide(tm.x + tm.thing->momx - tmcosradius, tm.y + tm.thing->momy - tmsinradius, &junk); + check4 = P_PointOnLineSide(tm.x + tm.thing->momx + tmcosradius, tm.y + tm.thing->momy + tmsinradius, &junk); if ((check1 == check2) && (check2 == check3) && (check3 == check4)) return BMIT_CONTINUE; // the line doesn't cross between collider's start or end } else { - if (abs(thing->x - tmx) >= (tmthing->radius + abs(cosradius)) || abs(thing->y - tmy) >= (tmthing->radius + abs(sinradius))) + if (abs(thing->x - tm.x) >= (tm.thing->radius + abs(cosradius)) || abs(thing->y - tm.y) >= (tm.thing->radius + abs(sinradius))) return BMIT_CONTINUE; // didn't hit it - if ((P_PointOnLineSide(tmx - tmthing->radius, tmy - tmthing->radius, &junk) - == P_PointOnLineSide(tmx + tmthing->radius, tmy + tmthing->radius, &junk)) - && (P_PointOnLineSide(tmx + tmthing->radius, tmy - tmthing->radius, &junk) - == P_PointOnLineSide(tmx - tmthing->radius, tmy + tmthing->radius, &junk))) + if ((P_PointOnLineSide(tm.x - tm.thing->radius, tm.y - tm.thing->radius, &junk) + == P_PointOnLineSide(tm.x + tm.thing->radius, tm.y + tm.thing->radius, &junk)) + && (P_PointOnLineSide(tm.x + tm.thing->radius, tm.y - tm.thing->radius, &junk) + == P_PointOnLineSide(tm.x - tm.thing->radius, tm.y + tm.thing->radius, &junk))) return BMIT_CONTINUE; // the line doesn't cross between either pair of opposite corners } } - else if (tmthing->flags & MF_PAPERCOLLISION) + else if (tm.thing->flags & MF_PAPERCOLLISION) { fixed_t tmcosradius, tmsinradius; vertex_t v1, v2; // fake vertexes line_t junk; // fake linedef - tmcosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); - tmsinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); + tmcosradius = FixedMul(tm.thing->radius, FINECOSINE(tm.thing->angle>>ANGLETOFINESHIFT)); + tmsinradius = FixedMul(tm.thing->radius, FINESINE(tm.thing->angle>>ANGLETOFINESHIFT)); - if (abs(thing->x - tmx) >= (thing->radius + abs(tmcosradius)) || abs(thing->y - tmy) >= (thing->radius + abs(tmsinradius))) + if (abs(thing->x - tm.x) >= (thing->radius + abs(tmcosradius)) || abs(thing->y - tm.y) >= (thing->radius + abs(tmsinradius))) return BMIT_CONTINUE; // didn't hit it - v1.x = tmx - tmcosradius; - v1.y = tmy - tmsinradius; - v2.x = tmx + tmcosradius; - v2.y = tmy + tmsinradius; + v1.x = tm.x - tmcosradius; + v1.y = tm.y - tmsinradius; + v2.x = tm.x + tmcosradius; + v2.y = tm.y + tmsinradius; junk.v1 = &v1; junk.v2 = &v2; @@ -632,16 +603,16 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } { - UINT8 shouldCollide = LUA_Hook2Mobj(thing, tmthing, MOBJ_HOOK(MobjCollide)); // checks hook for thing's type - if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) + UINT8 shouldCollide = LUA_Hook2Mobj(thing, tm.thing, MOBJ_HOOK(MobjCollide)); // checks hook for thing's type + if (P_MobjWasRemoved(tm.thing) || P_MobjWasRemoved(thing)) return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) return BMIT_ABORT; // force collide else if (shouldCollide == 2) return BMIT_CONTINUE; // force no collide - shouldCollide = LUA_Hook2Mobj(tmthing, thing, MOBJ_HOOK(MobjMoveCollide)); // checks hook for tmthing's type - if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) + shouldCollide = LUA_Hook2Mobj(tm.thing, thing, MOBJ_HOOK(MobjMoveCollide)); // checks hook for tm.thing's type + if (P_MobjWasRemoved(tm.thing) || P_MobjWasRemoved(thing)) return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) return BMIT_ABORT; // force collide @@ -650,66 +621,66 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // When solid spikes move, assume they just popped up and teleport things on top of them to hurt. - if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID) + if (tm.thing->type == MT_SPIKE && tm.thing->flags & MF_SOLID) { - if (thing->z > tmthing->z + tmthing->height) + if (thing->z > tm.thing->z + tm.thing->height) return BMIT_CONTINUE; // overhead - if (thing->z + thing->height < tmthing->z) + if (thing->z + thing->height < tm.thing->z) return BMIT_CONTINUE; // underneath - if (tmthing->eflags & MFE_VERTICALFLIP) - P_SetOrigin(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale)); + if (tm.thing->eflags & MFE_VERTICALFLIP) + P_SetOrigin(thing, thing->x, thing->y, tm.thing->z - thing->height - FixedMul(FRACUNIT, tm.thing->scale)); else - P_SetOrigin(thing, thing->x, thing->y, tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale)); + P_SetOrigin(thing, thing->x, thing->y, tm.thing->z + tm.thing->height + FixedMul(FRACUNIT, tm.thing->scale)); if (thing->flags & MF_SHOOTABLE) - P_DamageMobj(thing, tmthing, tmthing, 1, 0); + P_DamageMobj(thing, tm.thing, tm.thing, 1, 0); return BMIT_CONTINUE; } if (thing->flags & MF_PAIN) { // Player touches painful thing sitting on the floor // see if it went over / under - if (thing->z > tmthing->z + tmthing->height) + if (thing->z > tm.thing->z + tm.thing->height) return BMIT_CONTINUE; // overhead - if (thing->z + thing->height < tmthing->z) + if (thing->z + thing->height < tm.thing->z) return BMIT_CONTINUE; // underneath - if (tmthing->flags & MF_SHOOTABLE && thing->health > 0) + if (tm.thing->flags & MF_SHOOTABLE && thing->health > 0) { UINT32 damagetype = (thing->info->mass & 0xFF); - if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8))) + if (P_DamageMobj(tm.thing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8))) S_StartSound(thing, damagetype); } return BMIT_CONTINUE; } - else if (tmthing->flags & MF_PAIN && thing->player) + else if (tm.thing->flags & MF_PAIN && thing->player) { // Painful thing splats player in the face // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (thing->flags & MF_SHOOTABLE && tmthing->health > 0) + if (thing->flags & MF_SHOOTABLE && tm.thing->health > 0) { - UINT32 damagetype = (tmthing->info->mass & 0xFF); + UINT32 damagetype = (tm.thing->info->mass & 0xFF); - if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && (damagetype = (tmthing->info->mass>>8))) - S_StartSound(tmthing, damagetype); + if (P_DamageMobj(thing, tm.thing, tm.thing, 1, damagetype) && (damagetype = (tm.thing->info->mass>>8))) + S_StartSound(tm.thing, damagetype); } return BMIT_CONTINUE; } // check for skulls slamming into things - if (tmthing->flags2 & MF2_SKULLFLY) + if (tm.thing->flags2 & MF2_SKULLFLY) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - tmthing->flags2 &= ~MF2_SKULLFLY; - tmthing->momx = tmthing->momy = tmthing->momz = 0; + tm.thing->flags2 &= ~MF2_SKULLFLY; + tm.thing->momx = tm.thing->momy = tm.thing->momz = 0; return BMIT_ABORT; // stop moving } @@ -717,7 +688,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (thing->type == MT_SHRINK_GUN || thing->type == MT_SHRINK_PARTICLE) { - if (tmthing->type != MT_PLAYER) + if (tm.thing->type != MT_PLAYER) { return BMIT_CONTINUE; } @@ -727,334 +698,334 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // Use special collision for the laser gun. // The laser sprite itself is just a visual, // the gun itself does the colliding for us. - if (tmthing->z > thing->z) + if (tm.thing->z > thing->z) { return BMIT_CONTINUE; // overhead } - if (tmthing->z + tmthing->height < thing->floorz) + if (tm.thing->z + tm.thing->height < thing->floorz) { return BMIT_CONTINUE; // underneath } } else { - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) { return BMIT_CONTINUE; // underneath } } - return Obj_ShrinkLaserCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_ShrinkLaserCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if (tmthing->type == MT_SHRINK_GUN || tmthing->type == MT_SHRINK_PARTICLE) + else if (tm.thing->type == MT_SHRINK_GUN || tm.thing->type == MT_SHRINK_PARTICLE) { if (thing->type != MT_PLAYER) { return BMIT_CONTINUE; } - if (tmthing->type == MT_SHRINK_GUN) + if (tm.thing->type == MT_SHRINK_GUN) { // Use special collision for the laser gun. // The laser sprite itself is just a visual, // the gun itself does the colliding for us. - if (thing->z > tmthing->z) + if (thing->z > tm.thing->z) { return BMIT_CONTINUE; // overhead } - if (thing->z + thing->height < tmthing->floorz) + if (thing->z + thing->height < tm.thing->floorz) { return BMIT_CONTINUE; // underneath } } else { - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) { return BMIT_CONTINUE; // overhead } - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) { return BMIT_CONTINUE; // underneath } } - return Obj_ShrinkLaserCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_ShrinkLaserCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_SMK_ICEBLOCK) + if (tm.thing->type == MT_SMK_ICEBLOCK) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_SMKIceBlockCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_SMKIceBlockCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SMK_ICEBLOCK) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_SMKIceBlockCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_SMKIceBlockCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_EGGMANITEM || tmthing->type == MT_EGGMANITEM_SHIELD) + if (tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_EggItemCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_EggItemCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_EGGMANITEM || thing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_EggItemCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_EggItemCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_RANDOMITEM) + if (tm.thing->type == MT_RANDOMITEM) return BMIT_CONTINUE; // Bubble Shield reflect if (((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->bubbleblowup) || (thing->player && thing->player->bubbleblowup)) - && (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ - || tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG - || tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK - || tmthing->type == MT_GARDENTOP - || (tmthing->type == MT_PLAYER && thing->target != tmthing))) + && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ + || tm.thing->type == MT_BANANA || tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_BALLHOG + || tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK + || tm.thing->type == MT_GARDENTOP + || (tm.thing->type == MT_PLAYER && thing->target != tm.thing))) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if (((tmthing->type == MT_BUBBLESHIELD && tmthing->target->player && tmthing->target->player->bubbleblowup) - || (tmthing->player && tmthing->player->bubbleblowup)) + else if (((tm.thing->type == MT_BUBBLESHIELD && tm.thing->target->player && tm.thing->target->player->bubbleblowup) + || (tm.thing->player && tm.thing->player->bubbleblowup)) && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG - || thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK + || thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || thing->type == MT_SINK || thing->type == MT_GARDENTOP - || (thing->type == MT_PLAYER && tmthing->target != thing))) + || (thing->type == MT_PLAYER && tm.thing->target != thing))) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } // double make sure bubbles won't collide with anything else - if (thing->type == MT_BUBBLESHIELD || tmthing->type == MT_BUBBLESHIELD) + if (thing->type == MT_BUBBLESHIELD || tm.thing->type == MT_BUBBLESHIELD) return BMIT_CONTINUE; // Droptarget reflect if ((thing->type == MT_DROPTARGET || thing->type == MT_DROPTARGET_SHIELD) - && (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ - || tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG - || tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK - || tmthing->type == MT_GARDENTOP - || (tmthing->type == MT_PLAYER))) + && (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ + || tm.thing->type == MT_BANANA || tm.thing->type == MT_EGGMANITEM || tm.thing->type == MT_BALLHOG + || tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK + || tm.thing->type == MT_GARDENTOP + || (tm.thing->type == MT_PLAYER))) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_DropTargetCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_DropTargetCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - else if ((tmthing->type == MT_DROPTARGET || tmthing->type == MT_DROPTARGET_SHIELD) + else if ((tm.thing->type == MT_DROPTARGET || tm.thing->type == MT_DROPTARGET_SHIELD) && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG - || thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK + || thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || thing->type == MT_SINK || thing->type == MT_GARDENTOP || (thing->type == MT_PLAYER))) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_DropTargetCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_DropTargetCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } // double make sure drop targets won't collide with anything else - if (thing->type == MT_DROPTARGET || tmthing->type == MT_DROPTARGET - || thing->type == MT_DROPTARGET_SHIELD || tmthing->type == MT_DROPTARGET_SHIELD) + if (thing->type == MT_DROPTARGET || tm.thing->type == MT_DROPTARGET + || thing->type == MT_DROPTARGET_SHIELD || tm.thing->type == MT_DROPTARGET_SHIELD) return BMIT_CONTINUE; - if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ - || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD - || tmthing->type == MT_GARDENTOP) + if (tm.thing->type == MT_ORBINAUT || tm.thing->type == MT_JAWZ + || tm.thing->type == MT_ORBINAUT_SHIELD || tm.thing->type == MT_JAWZ_SHIELD + || tm.thing->type == MT_GARDENTOP) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return Obj_OrbinautJawzCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_OrbinautJawzCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD || thing->type == MT_GARDENTOP) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return Obj_OrbinautJawzCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return Obj_OrbinautJawzCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD || tmthing->type == MT_BALLHOG) + if (tm.thing->type == MT_BANANA || tm.thing->type == MT_BANANA_SHIELD || tm.thing->type == MT_BALLHOG) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BananaBallhogCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BananaBallhogCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD || thing->type == MT_BALLHOG) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_BananaBallhogCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_BananaBallhogCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_SSMINE || tmthing->type == MT_SSMINE_SHIELD) + if (tm.thing->type == MT_SSMINE || tm.thing->type == MT_SSMINE_SHIELD) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_MineCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_MineCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SSMINE || thing->type == MT_SSMINE_SHIELD) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_MineCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_MineCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_LANDMINE) + if (tm.thing->type == MT_LANDMINE) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_LandMineCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_LandMineCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_LANDMINE) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_LandMineCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_LandMineCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_SINK) + if (tm.thing->type == MT_SINK) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_KitchenSinkCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_KitchenSinkCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SINK) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_KitchenSinkCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_KitchenSinkCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } - if (tmthing->type == MT_FALLINGROCK) + if (tm.thing->type == MT_FALLINGROCK) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_FallingRockCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_FallingRockCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_FALLINGROCK) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - return K_FallingRockCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; + return K_FallingRockCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT; } //} if ((thing->type == MT_SPRINGSHELL || thing->type == MT_YELLOWSHELL) && thing->health > 0 - && (tmthing->player || (tmthing->flags & MF_PUSHABLE)) && tmthing->health > 0) + && (tm.thing->player || (tm.thing->flags & MF_PUSHABLE)) && tm.thing->health > 0) { // Multiplying by -1 inherently flips "less than" and "greater than" - fixed_t tmz = ((thing->eflags & MFE_VERTICALFLIP) ? -(tmthing->z + tmthing->height) : tmthing->z); - fixed_t tmznext = ((thing->eflags & MFE_VERTICALFLIP) ? -tmthing->momz : tmthing->momz) + tmz; + fixed_t tmz = ((thing->eflags & MFE_VERTICALFLIP) ? -(tm.thing->z + tm.thing->height) : tm.thing->z); + fixed_t tmznext = ((thing->eflags & MFE_VERTICALFLIP) ? -tm.thing->momz : tm.thing->momz) + tmz; fixed_t thzh = ((thing->eflags & MFE_VERTICALFLIP) ? -thing->z : thing->z + thing->height); //fixed_t sprarea = FixedMul(8*FRACUNIT, thing->scale) * P_MobjFlip(thing); //if ((tmznext <= thzh && tmz > thzh) || (tmznext > thzh - sprarea && tmznext < thzh)) if (tmznext <= thzh) { - P_DoSpring(thing, tmthing); + P_DoSpring(thing, tm.thing); // return BMIT_CONTINUE; } //else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down @@ -1062,20 +1033,20 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // missiles can hit other things - if (tmthing->flags & MF_MISSILE) + if (tm.thing->flags & MF_MISSILE) { - UINT8 damagetype = (tmthing->info->mass ^ DMG_WOMBO); + UINT8 damagetype = (tm.thing->info->mass ^ DMG_WOMBO); // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (tmthing->target && tmthing->target->type == thing->type) + if (tm.thing->target && tm.thing->target->type == thing->type) { // Don't hit same species as originator. - if (thing == tmthing->target) + if (thing == tm.thing->target) return BMIT_CONTINUE; if (thing->type != MT_PLAYER) @@ -1093,40 +1064,40 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // damage / explode - P_DamageMobj(thing, tmthing, tmthing->target, 1, damagetype); + P_DamageMobj(thing, tm.thing, tm.thing->target, 1, damagetype); // don't traverse any more return BMIT_ABORT; } - if (thing->flags & MF_PUSHABLE && (tmthing->player || tmthing->flags & MF_PUSHABLE) - && tmthing->z + tmthing->height > thing->z && tmthing->z < thing->z + thing->height - && !(netgame && tmthing->player && tmthing->player->spectator)) // Push thing! + if (thing->flags & MF_PUSHABLE && (tm.thing->player || tm.thing->flags & MF_PUSHABLE) + && tm.thing->z + tm.thing->height > thing->z && tm.thing->z < thing->z + thing->height + && !(netgame && tm.thing->player && tm.thing->player->spectator)) // Push thing! { if (thing->flags2 & MF2_SLIDEPUSH) // Make it slide { - if (tmthing->momy > 0 && tmthing->momy > FixedMul(4*FRACUNIT, thing->scale) && tmthing->momy > thing->momy) + if (tm.thing->momy > 0 && tm.thing->momy > FixedMul(4*FRACUNIT, thing->scale) && tm.thing->momy > thing->momy) { thing->momy += FixedMul(PUSHACCEL, thing->scale); - tmthing->momy -= FixedMul(PUSHACCEL, thing->scale); + tm.thing->momy -= FixedMul(PUSHACCEL, thing->scale); } - else if (tmthing->momy < 0 && tmthing->momy < FixedMul(-4*FRACUNIT, thing->scale) - && tmthing->momy < thing->momy) + else if (tm.thing->momy < 0 && tm.thing->momy < FixedMul(-4*FRACUNIT, thing->scale) + && tm.thing->momy < thing->momy) { thing->momy -= FixedMul(PUSHACCEL, thing->scale); - tmthing->momy += FixedMul(PUSHACCEL, thing->scale); + tm.thing->momy += FixedMul(PUSHACCEL, thing->scale); } - if (tmthing->momx > 0 && tmthing->momx > FixedMul(4*FRACUNIT, thing->scale) - && tmthing->momx > thing->momx) + if (tm.thing->momx > 0 && tm.thing->momx > FixedMul(4*FRACUNIT, thing->scale) + && tm.thing->momx > thing->momx) { thing->momx += FixedMul(PUSHACCEL, thing->scale); - tmthing->momx -= FixedMul(PUSHACCEL, thing->scale); + tm.thing->momx -= FixedMul(PUSHACCEL, thing->scale); } - else if (tmthing->momx < 0 && tmthing->momx < FixedMul(-4*FRACUNIT, thing->scale) - && tmthing->momx < thing->momx) + else if (tm.thing->momx < 0 && tm.thing->momx < FixedMul(-4*FRACUNIT, thing->scale) + && tm.thing->momx < thing->momx) { thing->momx -= FixedMul(PUSHACCEL, thing->scale); - tmthing->momx += FixedMul(PUSHACCEL, thing->scale); + tm.thing->momx += FixedMul(PUSHACCEL, thing->scale); } if (thing->momx > FixedMul(thing->info->speed, thing->scale)) @@ -1140,88 +1111,88 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } else { - if (tmthing->momx > FixedMul(4*FRACUNIT, thing->scale)) - tmthing->momx = FixedMul(4*FRACUNIT, thing->scale); - else if (tmthing->momx < FixedMul(-4*FRACUNIT, thing->scale)) - tmthing->momx = FixedMul(-4*FRACUNIT, thing->scale); - if (tmthing->momy > FixedMul(4*FRACUNIT, thing->scale)) - tmthing->momy = FixedMul(4*FRACUNIT, thing->scale); - else if (tmthing->momy < FixedMul(-4*FRACUNIT, thing->scale)) - tmthing->momy = FixedMul(-4*FRACUNIT, thing->scale); + if (tm.thing->momx > FixedMul(4*FRACUNIT, thing->scale)) + tm.thing->momx = FixedMul(4*FRACUNIT, thing->scale); + else if (tm.thing->momx < FixedMul(-4*FRACUNIT, thing->scale)) + tm.thing->momx = FixedMul(-4*FRACUNIT, thing->scale); + if (tm.thing->momy > FixedMul(4*FRACUNIT, thing->scale)) + tm.thing->momy = FixedMul(4*FRACUNIT, thing->scale); + else if (tm.thing->momy < FixedMul(-4*FRACUNIT, thing->scale)) + tm.thing->momy = FixedMul(-4*FRACUNIT, thing->scale); - thing->momx = tmthing->momx; - thing->momy = tmthing->momy; + thing->momx = tm.thing->momx; + thing->momy = tm.thing->momy; } if (thing->type != MT_GARGOYLE || P_IsObjectOnGround(thing)) S_StartSound(thing, thing->info->activesound); - P_SetTarget(&thing->target, tmthing); + P_SetTarget(&thing->target, tm.thing); } // check for special pickup - if (thing->flags & MF_SPECIAL && tmthing->player) + if (thing->flags & MF_SPECIAL && tm.thing->player) { - P_TouchSpecialThing(thing, tmthing, true); // can remove thing + P_TouchSpecialThing(thing, tm.thing, true); // can remove thing return BMIT_CONTINUE; } // check again for special pickup - if (tmthing->flags & MF_SPECIAL && thing->player) + if (tm.thing->flags & MF_SPECIAL && thing->player) { - P_TouchSpecialThing(tmthing, thing, true); // can remove thing + P_TouchSpecialThing(tm.thing, thing, true); // can remove thing return BMIT_CONTINUE; } // Sprite Spikes! // Do not return because solidity code comes below. - if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID && thing->player) // moving spike rams into player?! + if (tm.thing->type == MT_SPIKE && tm.thing->flags & MF_SOLID && thing->player) // moving spike rams into player?! { - if (tmthing->eflags & MFE_VERTICALFLIP) + if (tm.thing->eflags & MFE_VERTICALFLIP) { - if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) - && thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) - P_DamageMobj(thing, tmthing, tmthing, 1, DMG_NORMAL); + if (thing->z + thing->height <= tm.thing->z + FixedMul(FRACUNIT, tm.thing->scale) + && thing->z + thing->height + thing->momz >= tm.thing->z + FixedMul(FRACUNIT, tm.thing->scale) + tm.thing->momz) + P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL); } - else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) - && thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) - P_DamageMobj(thing, tmthing, tmthing, 1, DMG_NORMAL); + else if (thing->z >= tm.thing->z + tm.thing->height - FixedMul(FRACUNIT, tm.thing->scale) + && thing->z + thing->momz <= tm.thing->z + tm.thing->height - FixedMul(FRACUNIT, tm.thing->scale) + tm.thing->momz) + P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL); } - else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?! + else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tm.thing->player) // unfortunate player falls into spike?! { if (thing->eflags & MFE_VERTICALFLIP) { - if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale) - && tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale)) - P_DamageMobj(tmthing, thing, thing, 1, DMG_NORMAL); + if (tm.thing->z + tm.thing->height <= thing->z - FixedMul(FRACUNIT, thing->scale) + && tm.thing->z + tm.thing->height + tm.thing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale)) + P_DamageMobj(tm.thing, thing, thing, 1, DMG_NORMAL); } - else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) - && tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)) - P_DamageMobj(tmthing, thing, thing, 1, DMG_NORMAL); + else if (tm.thing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) + && tm.thing->z + tm.thing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)) + P_DamageMobj(tm.thing, thing, thing, 1, DMG_NORMAL); } - if (tmthing->type == MT_WALLSPIKE && tmthing->flags & MF_SOLID && thing->player) // wall spike impales player + if (tm.thing->type == MT_WALLSPIKE && tm.thing->flags & MF_SOLID && thing->player) // wall spike impales player { fixed_t bottomz, topz; - bottomz = tmthing->z; - topz = tmthing->z + tmthing->height; - if (tmthing->eflags & MFE_VERTICALFLIP) - bottomz -= FixedMul(FRACUNIT, tmthing->scale); + bottomz = tm.thing->z; + topz = tm.thing->z + tm.thing->height; + if (tm.thing->eflags & MFE_VERTICALFLIP) + bottomz -= FixedMul(FRACUNIT, tm.thing->scale); else - topz += FixedMul(FRACUNIT, tmthing->scale); + topz += FixedMul(FRACUNIT, tm.thing->scale); if (thing->z + thing->height > bottomz // above bottom && thing->z < topz) // below top // don't check angle, the player was clearly in the way in this case - P_DamageMobj(thing, tmthing, tmthing, 1, DMG_NORMAL); + P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL); } - else if (thing->type == MT_WALLSPIKE && thing->flags & MF_SOLID && tmthing->player) + else if (thing->type == MT_WALLSPIKE && thing->flags & MF_SOLID && tm.thing->player) { fixed_t bottomz, topz; - angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tmthing->x, tmthing->y); + angle_t touchangle = R_PointToAngle2(thing->tracer->x, thing->tracer->y, tm.thing->x, tm.thing->y); - if (P_PlayerInPain(tmthing->player) && (tmthing->momx || tmthing->momy)) + if (P_PlayerInPain(tm.thing->player) && (tm.thing->momx || tm.thing->momy)) { - angle_t playerangle = R_PointToAngle2(0, 0, tmthing->momx, tmthing->momy) - touchangle; + angle_t playerangle = R_PointToAngle2(0, 0, tm.thing->momx, tm.thing->momy) - touchangle; if (playerangle > ANGLE_180) playerangle = InvAngle(playerangle); if (playerangle < ANGLE_90) @@ -1236,103 +1207,103 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) else topz += FixedMul(FRACUNIT, thing->scale); - if (tmthing->z + tmthing->height > bottomz // above bottom - && tmthing->z < topz // below top + if (tm.thing->z + tm.thing->height > bottomz // above bottom + && tm.thing->z < topz // below top && !P_MobjWasRemoved(thing->tracer)) // this probably wouldn't work if we didn't have a tracer { // use base as a reference point to determine what angle you touched the spike at touchangle = thing->angle - touchangle; if (touchangle > ANGLE_180) touchangle = InvAngle(touchangle); if (touchangle <= ANGLE_22h) // if you touched it at this close an angle, you get poked! - P_DamageMobj(tmthing, thing, thing, 1, DMG_NORMAL); + P_DamageMobj(tm.thing, thing, thing, 1, DMG_NORMAL); } } if (thing->flags & MF_PUSHABLE) { - if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM) - P_DoFanAndGasJet(tmthing, thing); + if (tm.thing->type == MT_FAN || tm.thing->type == MT_STEAM) + P_DoFanAndGasJet(tm.thing, thing); } - if (tmthing->flags & MF_PUSHABLE) + if (tm.thing->flags & MF_PUSHABLE) { if (thing->type == MT_FAN || thing->type == MT_STEAM) { - P_DoFanAndGasJet(thing, tmthing); + P_DoFanAndGasJet(thing, tm.thing); return BMIT_CONTINUE; } else if (thing->flags & MF_SPRING) { - if ( thing->z <= tmthing->z + tmthing->height - && tmthing->z <= thing->z + thing->height) - if (P_DoSpring(thing, tmthing)) + if ( thing->z <= tm.thing->z + tm.thing->height + && tm.thing->z <= thing->z + thing->height) + if (P_DoSpring(thing, tm.thing)) return BMIT_ABORT; return BMIT_CONTINUE; } } // thanks to sal for solidenemies dot lua - if (thing->flags & (MF_ENEMY|MF_BOSS) && tmthing->flags & (MF_ENEMY|MF_BOSS)) + if (thing->flags & (MF_ENEMY|MF_BOSS) && tm.thing->flags & (MF_ENEMY|MF_BOSS)) { - if ((thing->z + thing->height >= tmthing->z) - && (tmthing->z + tmthing->height >= thing->z)) + if ((thing->z + thing->height >= tm.thing->z) + && (tm.thing->z + tm.thing->height >= thing->z)) return BMIT_ABORT; } if (thing->player) { - if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM) - P_DoFanAndGasJet(tmthing, thing); + if (tm.thing->type == MT_FAN || tm.thing->type == MT_STEAM) + P_DoFanAndGasJet(tm.thing, thing); } - if (tmthing->player) // Is the moving/interacting object the player? + if (tm.thing->player) // Is the moving/interacting object the player? { - if (!tmthing->health) + if (!tm.thing->health) return BMIT_CONTINUE; if (thing->type == MT_FAN || thing->type == MT_STEAM) - P_DoFanAndGasJet(thing, tmthing); + P_DoFanAndGasJet(thing, tm.thing); else if (thing->flags & MF_SPRING) { - if ( thing->z <= tmthing->z + tmthing->height - && tmthing->z <= thing->z + thing->height) - if (P_DoSpring(thing, tmthing)) + if ( thing->z <= tm.thing->z + tm.thing->height + && tm.thing->z <= thing->z + thing->height) + if (P_DoSpring(thing, tm.thing)) return BMIT_ABORT; return BMIT_CONTINUE; } else if (thing->player) // bounce when players collide { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - if (thing->player->hyudorotimer || tmthing->player->hyudorotimer) + if (thing->player->hyudorotimer || tm.thing->player->hyudorotimer) { return BMIT_CONTINUE; } if ((gametyperules & GTR_BUMPERS) - && ((thing->player->bumpers && !tmthing->player->bumpers) - || (tmthing->player->bumpers && !thing->player->bumpers))) + && ((thing->player->bumpers && !tm.thing->player->bumpers) + || (tm.thing->player->bumpers && !thing->player->bumpers))) { return BMIT_CONTINUE; } // The bump has to happen last - if (P_IsObjectOnGround(thing) && tmthing->momz < 0 && tmthing->player->trickpanel) + if (P_IsObjectOnGround(thing) && tm.thing->momz < 0 && tm.thing->player->trickpanel) { - P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL); + P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_WIPEOUT|DMG_STEAL); } - else if (P_IsObjectOnGround(tmthing) && thing->momz < 0 && thing->player->trickpanel) + else if (P_IsObjectOnGround(tm.thing) && thing->momz < 0 && thing->player->trickpanel) { - P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); + P_DamageMobj(tm.thing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); } - if (K_KartBouncing(tmthing, thing) == true) + if (K_KartBouncing(tm.thing, thing) == true) { - K_PvPTouchDamage(tmthing, thing); + K_PvPTouchDamage(tm.thing, thing); } return BMIT_CONTINUE; @@ -1340,48 +1311,48 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) else if (thing->type == MT_BLUEROBRA_HEAD || thing->type == MT_BLUEROBRA_JOINT) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath if (!thing->health) return BMIT_CONTINUE; // dead - if (tmthing->player->invincibilitytimer > 0 - || K_IsBigger(tmthing, thing) == true) + if (tm.thing->player->invincibilitytimer > 0 + || K_IsBigger(tm.thing, thing) == true) { if (thing->type == MT_BLUEROBRA_JOINT) - P_KillMobj(thing->target, tmthing, tmthing, DMG_NORMAL); + P_KillMobj(thing->target, tm.thing, tm.thing, DMG_NORMAL); else - P_KillMobj(thing, tmthing, tmthing, DMG_NORMAL); + P_KillMobj(thing, tm.thing, tm.thing, DMG_NORMAL); return BMIT_CONTINUE; } else { - K_KartSolidBounce(tmthing, thing); + K_KartSolidBounce(tm.thing, thing); return BMIT_CONTINUE; } } else if (thing->type == MT_SMK_PIPE) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath if (!thing->health) return BMIT_CONTINUE; // dead - if (tmthing->player->invincibilitytimer > 0 - || K_IsBigger(tmthing, thing) == true) + if (tm.thing->player->invincibilitytimer > 0 + || K_IsBigger(tm.thing, thing) == true) { - P_KillMobj(thing, tmthing, tmthing, DMG_NORMAL); + P_KillMobj(thing, tm.thing, tm.thing, DMG_NORMAL); return BMIT_CONTINUE; // kill } - K_KartSolidBounce(tmthing, thing); + K_KartSolidBounce(tm.thing, thing); return BMIT_CONTINUE; } else if (thing->type == MT_SMK_THWOMP) @@ -1392,38 +1363,38 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (!thwompsactive) return BMIT_CONTINUE; // not active yet - if ((tmthing->z < thing->z) && (thing->z >= thing->movefactor-(256<z < thing->z) && (thing->z >= thing->movefactor-(256<extravalue1 = 1; // purposely try to stomp on players early //S_StartSound(thing, sfx_s1bb); } // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath // kill - if (tmthing->player->invincibilitytimer > 0 - || K_IsBigger(tmthing, thing) == true) + if (tm.thing->player->invincibilitytimer > 0 + || K_IsBigger(tm.thing, thing) == true) { - P_KillMobj(thing, tmthing, tmthing, DMG_NORMAL); + P_KillMobj(thing, tm.thing, tm.thing, DMG_NORMAL); return BMIT_CONTINUE; } // no interaction - if (tmthing->player->flashing > 0 || tmthing->player->hyudorotimer > 0 || tmthing->player->spinouttimer > 0) + if (tm.thing->player->flashing > 0 || tm.thing->player->hyudorotimer > 0 || tm.thing->player->spinouttimer > 0) return BMIT_CONTINUE; // collide - if (tmthing->z < thing->z && thing->momz < 0) - P_DamageMobj(tmthing, thing, thing, 1, DMG_TUMBLE); + if (tm.thing->z < thing->z && thing->momz < 0) + P_DamageMobj(tm.thing, thing, thing, 1, DMG_TUMBLE); else { - if ((K_KartSolidBounce(tmthing, thing) == true) && (thing->flags2 & MF2_AMBUSH)) + if ((K_KartSolidBounce(tm.thing, thing) == true) && (thing->flags2 & MF2_AMBUSH)) { - P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT); + P_DamageMobj(tm.thing, thing, thing, 1, DMG_WIPEOUT); } } @@ -1432,49 +1403,49 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) else if (thing->type == MT_KART_LEFTOVER) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - K_KartBouncing(tmthing, thing); + K_KartBouncing(tm.thing, thing); return BMIT_CONTINUE; } else if (thing->flags & MF_SOLID) { // see if it went over / under - if (tmthing->z > thing->z + thing->height) + if (tm.thing->z > thing->z + thing->height) return BMIT_CONTINUE; // overhead - if (tmthing->z + tmthing->height < thing->z) + if (tm.thing->z + tm.thing->height < thing->z) return BMIT_CONTINUE; // underneath - K_KartSolidBounce(tmthing, thing); + K_KartSolidBounce(tm.thing, thing); return BMIT_CONTINUE; } } - if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player)) + if ((tm.thing->flags & MF_SPRING || tm.thing->type == MT_STEAM || tm.thing->type == MT_SPIKE || tm.thing->type == MT_WALLSPIKE) && (thing->player)) ; // springs, gas jets and springs should never be able to step up onto a player // z checking at last // Treat noclip things as non-solid! else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID - && (tmthing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID) + && (tm.thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID) { fixed_t topz, tmtopz; - if (tmthing->eflags & MFE_VERTICALFLIP) + if (tm.thing->eflags & MFE_VERTICALFLIP) { // pass under - tmtopz = tmthing->z; + tmtopz = tm.thing->z; if (tmtopz > thing->z + thing->height) { - if (thing->z + thing->height > tmfloorz) + if (thing->z + thing->height > tm.floorz) { - tmfloorz = thing->z + thing->height; - tmfloorrover = NULL; - tmfloorslope = NULL; - tmfloorpic = -1; + tm.floorz = thing->z + thing->height; + tm.floorrover = NULL; + tm.floorslope = NULL; + tm.floorpic = -1; } return BMIT_CONTINUE; } @@ -1485,40 +1456,40 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // (dont climb max. 24units while already in air) // since return false doesn't handle momentum properly, // we lie to P_TryMove() so it's always too high - if (tmthing->player && tmthing->z + tmthing->height > topz - && tmthing->z + tmthing->height < tmthing->ceilingz) + if (tm.thing->player && tm.thing->z + tm.thing->height > topz + && tm.thing->z + tm.thing->height < tm.thing->ceilingz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... return BMIT_ABORT; - tmfloorz = tmceilingz = topz; // block while in air - tmceilingrover = NULL; - tmceilingslope = NULL; - tmceilingpic = -1; - tmfloorthing = thing; // needed for side collision + tm.floorz = tm.ceilingz = topz; // block while in air + tm.ceilingrover = NULL; + tm.ceilingslope = NULL; + tm.ceilingpic = -1; + tm.floorthing = thing; // needed for side collision } - else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height) + else if (topz < tm.ceilingz && tm.thing->z <= thing->z+thing->height) { - tmceilingz = topz; - tmceilingrover = NULL; - tmceilingslope = NULL; - tmceilingpic = -1; - tmfloorthing = thing; // thing we may stand on + tm.ceilingz = topz; + tm.ceilingrover = NULL; + tm.ceilingslope = NULL; + tm.ceilingpic = -1; + tm.floorthing = thing; // thing we may stand on } } else { // pass under - tmtopz = tmthing->z + tmthing->height; + tmtopz = tm.thing->z + tm.thing->height; if (tmtopz < thing->z) { - if (thing->z < tmceilingz) + if (thing->z < tm.ceilingz) { - tmceilingz = thing->z; - tmceilingrover = NULL; - tmceilingslope = NULL; - tmceilingpic = -1; + tm.ceilingz = thing->z; + tm.ceilingrover = NULL; + tm.ceilingslope = NULL; + tm.ceilingpic = -1; } return BMIT_CONTINUE; } @@ -1529,25 +1500,25 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // (dont climb max. 24units while already in air) // since return false doesn't handle momentum properly, // we lie to P_TryMove() so it's always too high - if (tmthing->player && tmthing->z < topz - && tmthing->z > tmthing->floorz) + if (tm.thing->player && tm.thing->z < topz + && tm.thing->z > tm.thing->floorz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... return BMIT_ABORT; - tmfloorz = tmceilingz = topz; // block while in air - tmfloorrover = NULL; - tmfloorslope = NULL; - tmfloorpic = -1; - tmfloorthing = thing; // needed for side collision + tm.floorz = tm.ceilingz = topz; // block while in air + tm.floorrover = NULL; + tm.floorslope = NULL; + tm.floorpic = -1; + tm.floorthing = thing; // needed for side collision } - else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z) + else if (topz > tm.floorz && tm.thing->z+tm.thing->height >= thing->z) { - tmfloorz = topz; - tmfloorrover = NULL; - tmfloorslope = NULL; - tmfloorpic = -1; - tmfloorthing = thing; // thing we may stand on + tm.floorz = topz; + tm.floorrover = NULL; + tm.floorslope = NULL; + tm.floorpic = -1; + tm.floorthing = thing; // thing we may stand on } } } @@ -1557,19 +1528,19 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) } // PIT_CheckCameraLine -// Adjusts tmfloorz and tmceilingz as lines are contacted - FOR CAMERA ONLY +// Adjusts tm.floorz and tm.ceilingz as lines are contacted - FOR CAMERA ONLY static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) { if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) return BMIT_CONTINUE; - if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] - || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { return BMIT_CONTINUE; } - if (P_BoxOnLineSide(tmbbox, ld) != -1) + if (P_BoxOnLineSide(tm.bbox, ld) != -1) return BMIT_CONTINUE; // A line has been hit @@ -1584,7 +1555,7 @@ static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) // could be crossed in either order. // this line is out of the if so upper and lower textures can be hit by a splat - blockingline = ld; + tm.blockingline = ld; if (!ld->backsector) // one sided line { if (P_PointOnLineSide(mapcampointer->x, mapcampointer->y, ld)) @@ -1596,22 +1567,22 @@ static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) P_CameraLineOpening(ld); // adjust floor / ceiling heights - if (opentop < tmceilingz) + if (opentop < tm.ceilingz) { - tmceilingz = opentop; - ceilingline = ld; + tm.ceilingz = opentop; + tm.ceilingline = ld; } - if (openbottom > tmfloorz) + if (openbottom > tm.floorz) { - tmfloorz = openbottom; + tm.floorz = openbottom; } - if (highceiling > tmdrpoffceilz) - tmdrpoffceilz = highceiling; + if (highceiling > tm.drpoffceilz) + tm.drpoffceilz = highceiling; - if (lowfloor < tmdropoffz) - tmdropoffz = lowfloor; + if (lowfloor < tm.dropoffz) + tm.dropoffz = lowfloor; return BMIT_CONTINUE; } @@ -1657,44 +1628,44 @@ boolean P_IsLineTripWire(const line_t *ld) // // PIT_CheckLine -// Adjusts tmfloorz and tmceilingz as lines are contacted +// Adjusts tm.floorz and tm.ceilingz as lines are contacted // static BlockItReturn_t PIT_CheckLine(line_t *ld) { - const fixed_t thingtop = tmthing->z + tmthing->height; + const fixed_t thingtop = tm.thing->z + tm.thing->height; if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) return BMIT_CONTINUE; - if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] - || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] + || tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) return BMIT_CONTINUE; - if (P_BoxOnLineSide(tmbbox, ld) != -1) + if (P_BoxOnLineSide(tm.bbox, ld) != -1) return BMIT_CONTINUE; - if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. + if (tm.thing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. { fixed_t cosradius, sinradius; - cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); - sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); - if (P_PointOnLineSide(tmx - cosradius, tmy - sinradius, ld) - == P_PointOnLineSide(tmx + cosradius, tmy + sinradius, ld)) + cosradius = FixedMul(tm.thing->radius, FINECOSINE(tm.thing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tm.thing->radius, FINESINE(tm.thing->angle>>ANGLETOFINESHIFT)); + if (P_PointOnLineSide(tm.x - cosradius, tm.y - sinradius, ld) + == P_PointOnLineSide(tm.x + cosradius, tm.y + sinradius, ld)) return BMIT_CONTINUE; // the line doesn't cross between collider's start or end #ifdef PAPER_COLLISIONCORRECTION { fixed_t dist; vertex_t result; angle_t langle; - P_ClosestPointOnLine(tmx, tmy, ld, &result); + P_ClosestPointOnLine(tm.x, tm.y, ld, &result); langle = R_PointToAngle2(ld->v1->x, ld->v1->y, ld->v2->x, ld->v2->y); - langle += ANGLE_90*(P_PointOnLineSide(tmx, tmy, ld) ? -1 : 1); - dist = abs(FixedMul(tmthing->radius, FINECOSINE((tmthing->angle - langle)>>ANGLETOFINESHIFT))); + langle += ANGLE_90*(P_PointOnLineSide(tm.x, tm.y, ld) ? -1 : 1); + dist = abs(FixedMul(tm.thing->radius, FINECOSINE((tm.thing->angle - langle)>>ANGLETOFINESHIFT))); cosradius = FixedMul(dist, FINECOSINE(langle>>ANGLETOFINESHIFT)); sinradius = FixedMul(dist, FINESINE(langle>>ANGLETOFINESHIFT)); - tmthing->flags |= MF_NOCLIP; - P_MoveOrigin(tmthing, result.x + cosradius - tmthing->momx, result.y + sinradius - tmthing->momy, tmthing->z); - tmthing->flags &= ~MF_NOCLIP; + tm.thing->flags |= MF_NOCLIP; + P_MoveOrigin(tm.thing, result.x + cosradius - tm.thing->momx, result.y + sinradius - tm.thing->momy, tm.thing->z); + tm.thing->flags &= ~MF_NOCLIP; } #endif } @@ -1711,11 +1682,11 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) // could be crossed in either order. // this line is out of the if so upper and lower textures can be hit by a splat - blockingline = ld; + tm.blockingline = ld; { - UINT8 shouldCollide = LUA_HookMobjLineCollide(tmthing, blockingline); // checks hook for thing's type - if (P_MobjWasRemoved(tmthing)) + UINT8 shouldCollide = LUA_HookMobjLineCollide(tm.thing, tm.blockingline); // checks hook for thing's type + if (P_MobjWasRemoved(tm.thing)) return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) return BMIT_ABORT; // force collide @@ -1725,50 +1696,50 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) if (!ld->backsector) // one sided line { - if (P_PointOnLineSide(tmthing->x, tmthing->y, ld)) + if (P_PointOnLineSide(tm.thing->x, tm.thing->y, ld)) return BMIT_CONTINUE; // don't hit the back side return BMIT_ABORT; } - if (P_IsLineBlocking(ld, tmthing)) + if (P_IsLineBlocking(ld, tm.thing)) return BMIT_ABORT; // set openrange, opentop, openbottom - P_LineOpening(ld, tmthing); + P_LineOpening(ld, tm.thing); // adjust floor / ceiling heights - if (opentop < tmceilingz) + if (opentop < tm.ceilingz) { - tmceilingz = opentop; - ceilingline = ld; - tmceilingrover = openceilingrover; - tmceilingslope = opentopslope; - tmceilingpic = opentoppic; - tmceilingstep = openceilingstep; - if (thingtop == tmthing->ceilingz) + tm.ceilingz = opentop; + tm.ceilingline = ld; + tm.ceilingrover = openceilingrover; + tm.ceilingslope = opentopslope; + tm.ceilingpic = opentoppic; + tm.ceilingstep = openceilingstep; + if (thingtop == tm.thing->ceilingz) { - tmthing->ceilingdrop = openceilingdrop; + tm.thing->ceilingdrop = openceilingdrop; } } - if (openbottom > tmfloorz) + if (openbottom > tm.floorz) { - tmfloorz = openbottom; - tmfloorrover = openfloorrover; - tmfloorslope = openbottomslope; - tmfloorpic = openbottompic; - tmfloorstep = openfloorstep; - if (tmthing->z == tmthing->floorz) + tm.floorz = openbottom; + tm.floorrover = openfloorrover; + tm.floorslope = openbottomslope; + tm.floorpic = openbottompic; + tm.floorstep = openfloorstep; + if (tm.thing->z == tm.thing->floorz) { - tmthing->floordrop = openfloordrop; + tm.thing->floordrop = openfloordrop; } } - if (highceiling > tmdrpoffceilz) - tmdrpoffceilz = highceiling; + if (highceiling > tm.drpoffceilz) + tm.drpoffceilz = highceiling; - if (lowfloor < tmdropoffz) - tmdropoffz = lowfloor; + if (lowfloor < tm.dropoffz) + tm.dropoffz = lowfloor; // we've crossed the line if (P_SpecialIsLinedefCrossType(ld)) @@ -1779,14 +1750,14 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) { fixed_t textop, texbottom; - P_GetMidtextureTopBottom(ld, tmx, tmy, + P_GetMidtextureTopBottom(ld, tm.x, tm.y, &textop, &texbottom); /* The effect handling is done later but it won't know the height values anymore. So don't even add this line to the list unless this thing clips the tripwire's midtexture. */ - if (tmthing->z <= textop && thingtop >= texbottom) + if (tm.thing->z <= textop && thingtop >= texbottom) add_spechit(ld); } @@ -1813,20 +1784,20 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) // // out: // newsubsec -// tmfloorz -// tmceilingz -// tmdropoffz -// tmdrpoffceilz +// tm.floorz +// tm.ceilingz +// tm.dropoffz +// tm.drpoffceilz // the lowest point contacted // (monsters won't move to a dropoff) // speciallines[] // numspeciallines // -// tmfloorz -// the nearest floor or thing's top under tmthing -// tmceilingz -// the nearest ceiling or thing's bottom over tmthing +// tm.floorz +// the nearest floor or thing's top under tm.thing +// tm.ceilingz +// the nearest ceiling or thing's bottom over tm.thing // boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { @@ -1843,35 +1814,35 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) I_Error("Previously-removed Thing of type %u crashes P_CheckPosition!", thing->type); #endif - P_SetTarget(&tmthing, thing); - tmflags = thing->flags; + P_SetTarget(&tm.thing, thing); + tm.flags = thing->flags; - tmx = x; - tmy = y; + tm.x = x; + tm.y = y; - tmbbox[BOXTOP] = y + tmthing->radius; - tmbbox[BOXBOTTOM] = y - tmthing->radius; - tmbbox[BOXRIGHT] = x + tmthing->radius; - tmbbox[BOXLEFT] = x - tmthing->radius; + tm.bbox[BOXTOP] = y + tm.thing->radius; + tm.bbox[BOXBOTTOM] = y - tm.thing->radius; + tm.bbox[BOXRIGHT] = x + tm.thing->radius; + tm.bbox[BOXLEFT] = x - tm.thing->radius; newsubsec = R_PointInSubsector(x, y); - ceilingline = blockingline = NULL; + tm.ceilingline = tm.blockingline = NULL; // The base floor / ceiling is from the subsector // that contains the point. // Any contacted lines the step closer together // will adjust them. - tmfloorz = tmdropoffz = P_GetFloorZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->floorheight; - tmceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; - tmfloorrover = NULL; - tmceilingrover = NULL; - tmfloorslope = newsubsec->sector->f_slope; - tmceilingslope = newsubsec->sector->c_slope; - tmfloorpic = newsubsec->sector->floorpic; - tmceilingpic = newsubsec->sector->ceilingpic; + tm.floorz = tm.dropoffz = P_GetFloorZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->floorheight; + tm.ceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight; + tm.floorrover = NULL; + tm.ceilingrover = NULL; + tm.floorslope = newsubsec->sector->f_slope; + tm.ceilingslope = newsubsec->sector->c_slope; + tm.floorpic = newsubsec->sector->floorpic; + tm.ceilingpic = newsubsec->sector->ceilingpic; - tmfloorstep = 0; - tmceilingstep = 0; + tm.floorstep = 0; + tm.ceilingstep = 0; if (thingtop < thing->ceilingz) { @@ -1883,7 +1854,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) thing->floordrop = 0; } - // Check list of fake floors and see if tmfloorz/tmceilingz need to be altered. + // Check list of fake floors and see if tm.floorz/tm.ceilingz need to be altered. if (newsubsec->sector->ffloors) { ffloor_t *rover; @@ -1918,20 +1889,22 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) // Land on the top or the bottom, depending on gravity flip. if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z >= topheight - sinklevel && thing->momz <= 0) { - if (tmfloorz < topheight - sinklevel) { - tmfloorz = topheight - sinklevel; - tmfloorrover = rover; - tmfloorslope = *rover->t_slope; - tmfloorpic = *rover->toppic; + if (tm.floorz < topheight - sinklevel) + { + tm.floorz = topheight - sinklevel; + tm.floorrover = rover; + tm.floorslope = *rover->t_slope; + tm.floorpic = *rover->toppic; } } else if (thing->eflags & MFE_VERTICALFLIP && thingtop <= bottomheight + sinklevel && thing->momz >= 0) { - if (tmceilingz > bottomheight + sinklevel) { - tmceilingz = bottomheight + sinklevel; - tmceilingrover = rover; - tmceilingslope = *rover->b_slope; - tmceilingpic = *rover->bottompic; + if (tm.ceilingz > bottomheight + sinklevel) + { + tm.ceilingz = bottomheight + sinklevel; + tm.ceilingrover = rover; + tm.ceilingslope = *rover->b_slope; + tm.ceilingpic = *rover->bottompic; } } } @@ -1951,11 +1924,12 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { if (thing->z < topheight && bottomheight < thingtop) { - if (tmfloorz < thing->z) { - tmfloorz = thing->z; - tmfloorrover = rover; - tmfloorslope = NULL; - tmfloorpic = *rover->toppic; + if (tm.floorz < thing->z) + { + tm.floorz = thing->z; + tm.floorrover = rover; + tm.floorslope = NULL; + tm.floorpic = *rover->toppic; } } // Quicksand blocks never change heights otherwise. @@ -1967,22 +1941,23 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); - if (topheight > tmfloorz && abs(delta1) < abs(delta2) + if (topheight > tm.floorz && abs(delta1) < abs(delta2) && !(rover->fofflags & FOF_REVERSEPLATFORM)) { - tmfloorz = tmdropoffz = topheight; - tmfloorrover = rover; - tmfloorslope = *rover->t_slope; - tmfloorpic = *rover->toppic; + tm.floorz = tm.dropoffz = topheight; + tm.floorrover = rover; + tm.floorslope = *rover->t_slope; + tm.floorpic = *rover->toppic; } - if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2) + + if (bottomheight < tm.ceilingz && abs(delta1) >= abs(delta2) && !(rover->fofflags & FOF_PLATFORM) && !(thing->type == MT_SKIM && (rover->fofflags & FOF_SWIMMABLE))) { - tmceilingz = tmdrpoffceilz = bottomheight; - tmceilingrover = rover; - tmceilingslope = *rover->b_slope; - tmceilingpic = *rover->bottompic; + tm.ceilingz = tm.drpoffceilz = bottomheight; + tm.ceilingrover = rover; + tm.ceilingslope = *rover->b_slope; + tm.ceilingpic = *rover->bottompic; } } } @@ -1992,18 +1967,19 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); - // Check polyobjects and see if tmfloorz/tmceilingz need to be altered + // Check polyobjects and see if tm.floorz/tm.ceilingz need to be altered { validcount++; for (by = yl; by <= yh; by++) + { for (bx = xl; bx <= xh; bx++) { INT32 offset; @@ -2029,7 +2005,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) po->validcount = validcount; - if (!P_BBoxInsidePolyobj(po, tmbbox) + if (!P_BBoxInsidePolyobj(po, tm.bbox) || !(po->flags & POF_SOLID)) { plink = (polymaplink_t *)(plink->link.next); @@ -2053,35 +2029,38 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) delta1 = thing->z - (polybottom + ((polytop - polybottom)/2)); delta2 = thingtop - (polybottom + ((polytop - polybottom)/2)); - if (polytop > tmfloorz && abs(delta1) < abs(delta2)) { - tmfloorz = tmdropoffz = polytop; - tmfloorslope = NULL; - tmfloorrover = NULL; - tmfloorpic = polysec->ceilingpic; + if (polytop > tm.floorz && abs(delta1) < abs(delta2)) + { + tm.floorz = tm.dropoffz = polytop; + tm.floorslope = NULL; + tm.floorrover = NULL; + tm.floorpic = polysec->ceilingpic; } - if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) { - tmceilingz = tmdrpoffceilz = polybottom; - tmceilingslope = NULL; - tmceilingrover = NULL; - tmceilingpic = polysec->floorpic; + if (polybottom < tm.ceilingz && abs(delta1) >= abs(delta2)) + { + tm.ceilingz = tm.drpoffceilz = polybottom; + tm.ceilingslope = NULL; + tm.ceilingrover = NULL; + tm.ceilingpic = polysec->floorpic; } } plink = (polymaplink_t *)(plink->link.next); } } + } } - // tmfloorthing is set when tmfloorz comes from a thing's top - tmfloorthing = NULL; - tmhitthing = NULL; + // tm.floorthing is set when tm.floorz comes from a thing's top + tm.floorthing = NULL; + tm.hitthing = NULL; validcount++; // reset special lines numspechit = 0U; - if (tmflags & MF_NOCLIP) + if (tm.flags & MF_NOCLIP) return true; // Check things first, possibly picking things up. @@ -2095,8 +2074,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (!P_BlockThingsIterator(bx, by, PIT_CheckThing)) blockval = false; else - tmhitthing = tmfloorthing; - if (P_MobjWasRemoved(tmthing)) + tm.hitthing = tm.floorthing; + if (P_MobjWasRemoved(tm.thing)) return false; } } @@ -2105,9 +2084,15 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) // check lines for (bx = xl; bx <= xh; bx++) + { for (by = yl; by <= yh; by++) + { if (!P_BlockLinesIterator(bx, by, PIT_CheckLine)) + { blockval = false; + } + } + } return blockval; } @@ -2147,23 +2132,23 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) INT32 xl, xh, yl, yh, bx, by; subsector_t *newsubsec; - tmx = x; - tmy = y; + tm.x = x; + tm.y = y; - tmbbox[BOXTOP] = y + thiscam->radius; - tmbbox[BOXBOTTOM] = y - thiscam->radius; - tmbbox[BOXRIGHT] = x + thiscam->radius; - tmbbox[BOXLEFT] = x - thiscam->radius; + tm.bbox[BOXTOP] = y + thiscam->radius; + tm.bbox[BOXBOTTOM] = y - thiscam->radius; + tm.bbox[BOXRIGHT] = x + thiscam->radius; + tm.bbox[BOXLEFT] = x - thiscam->radius; newsubsec = R_PointInSubsector(x, y); - ceilingline = blockingline = NULL; + tm.ceilingline = tm.blockingline = NULL; mapcampointer = thiscam; if (newsubsec->sector->flags & MSF_NOCLIPCAMERA) { // Camera noclip on entire sector. - tmfloorz = tmdropoffz = thiscam->z; - tmceilingz = tmdrpoffceilz = thiscam->z + thiscam->height; + tm.floorz = tm.dropoffz = thiscam->z; + tm.ceilingz = tm.drpoffceilz = thiscam->z + thiscam->height; return true; } @@ -2171,26 +2156,26 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) // that contains the point. // Any contacted lines the step closer together // will adjust them. - tmfloorz = tmdropoffz = P_CameraGetFloorZ(thiscam, newsubsec->sector, x, y, NULL); + tm.floorz = tm.dropoffz = P_CameraGetFloorZ(thiscam, newsubsec->sector, x, y, NULL); - tmceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, x, y, NULL); + tm.ceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, x, y, NULL); // Cameras use the heightsec's heights rather then the actual sector heights. // If you can see through it, why not move the camera through it too? if (newsubsec->sector->heightsec >= 0) { - tmfloorz = tmdropoffz = sectors[newsubsec->sector->heightsec].floorheight; - tmceilingz = tmdrpoffceilz = sectors[newsubsec->sector->heightsec].ceilingheight; + tm.floorz = tm.dropoffz = sectors[newsubsec->sector->heightsec].floorheight; + tm.ceilingz = tm.drpoffceilz = sectors[newsubsec->sector->heightsec].ceilingheight; } // Use preset camera clipping heights if set with Sector Special Parameters whose control sector has Camera Intangible special -Red if (newsubsec->sector->camsec >= 0) { - tmfloorz = tmdropoffz = sectors[newsubsec->sector->camsec].floorheight; - tmceilingz = tmdrpoffceilz = sectors[newsubsec->sector->camsec].ceilingheight; + tm.floorz = tm.dropoffz = sectors[newsubsec->sector->camsec].floorheight; + tm.ceilingz = tm.drpoffceilz = sectors[newsubsec->sector->camsec].ceilingheight; } - // Check list of fake floors and see if tmfloorz/tmceilingz need to be altered. + // Check list of fake floors and see if tm.floorz/tm.ceilingz need to be altered. if (newsubsec->sector->ffloors) { ffloor_t *rover; @@ -2210,13 +2195,13 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) + ((topheight - bottomheight)/2)); delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); - if (topheight > tmfloorz && abs(delta1) < abs(delta2)) + if (topheight > tm.floorz && abs(delta1) < abs(delta2)) { - tmfloorz = tmdropoffz = topheight; + tm.floorz = tm.dropoffz = topheight; } - if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2)) + if (bottomheight < tm.ceilingz && abs(delta1) >= abs(delta2)) { - tmceilingz = tmdrpoffceilz = bottomheight; + tm.ceilingz = tm.drpoffceilz = bottomheight; } } } @@ -2226,14 +2211,14 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) // based on their origin point, and can overlap // into adjacent blocks by up to MAXRADIUS units. - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); - // Check polyobjects and see if tmfloorz/tmceilingz need to be altered + // Check polyobjects and see if tm.floorz/tm.ceilingz need to be altered { validcount++; @@ -2293,11 +2278,11 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) delta1 = thiscam->z - (polybottom + ((polytop - polybottom)/2)); delta2 = thingtop - (polybottom + ((polytop - polybottom)/2)); - if (polytop > tmfloorz && abs(delta1) < abs(delta2)) - tmfloorz = tmdropoffz = polytop; + if (polytop > tm.floorz && abs(delta1) < abs(delta2)) + tm.floorz = tm.dropoffz = polytop; - if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) - tmceilingz = tmdrpoffceilz = polybottom; + if (polybottom < tm.ceilingz && abs(delta1) >= abs(delta2)) + tm.ceilingz = tm.drpoffceilz = polybottom; } plink = (polymaplink_t *)(plink->link.next); } @@ -2330,7 +2315,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) UINT8 i; - floatok = false; + tm.floatok = false; for (i = 0; i <= r_splitscreen; i++) { @@ -2354,7 +2339,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) if (!(players[displayplayers[i]].pflags & PF_NOCONTEST)) // Time Over should not clip through walls { - floatok = true; + tm.floatok = true; thiscam->floorz = thiscam->z; thiscam->ceilingz = thiscam->z + thiscam->height; thiscam->x = x; @@ -2380,18 +2365,18 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) if (!P_CheckCameraPosition(tryx, tryy, thiscam)) return false; // solid wall or thing - if (tmceilingz - tmfloorz < thiscam->height) + if (tm.ceilingz - tm.floorz < thiscam->height) return false; // doesn't fit - floatok = true; + tm.floatok = true; - if (tmceilingz - thiscam->z < thiscam->height) + if (tm.ceilingz - thiscam->z < thiscam->height) { - if (s == thiscam->subsector && tmceilingz >= thiscam->z) + if (s == thiscam->subsector && tm.ceilingz >= thiscam->z) { - floatok = true; - thiscam->floorz = tmfloorz; - thiscam->ceilingz = tmfloorz + thiscam->height; + tm.floatok = true; + thiscam->floorz = tm.floorz; + thiscam->ceilingz = tm.floorz + thiscam->height; thiscam->x = x; thiscam->y = y; thiscam->subsector = s; @@ -2401,21 +2386,21 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) return false; // mobj must lower itself to fit } - if ((tmfloorz - thiscam->z > MAXCAMERASTEPMOVE)) + if ((tm.floorz - thiscam->z > MAXCAMERASTEPMOVE)) return false; // too big a step up } while(tryx != x || tryy != y); } else { - tmfloorz = P_CameraGetFloorZ(thiscam, thiscam->subsector->sector, x, y, NULL); - tmceilingz = P_CameraGetCeilingZ(thiscam, thiscam->subsector->sector, x, y, NULL); + tm.floorz = P_CameraGetFloorZ(thiscam, thiscam->subsector->sector, x, y, NULL); + tm.ceilingz = P_CameraGetCeilingZ(thiscam, thiscam->subsector->sector, x, y, NULL); } // the move is ok, // so link the thing into its new position - thiscam->floorz = tmfloorz; - thiscam->ceilingz = tmceilingz; + thiscam->floorz = tm.floorz; + thiscam->ceilingz = tm.ceilingz; thiscam->x = x; thiscam->y = y; thiscam->subsector = s; @@ -2467,37 +2452,14 @@ BlockItReturn_t PIT_PushableMoved(mobj_t *thing) // These are all non-static map variables that are changed for each and every single mobj // See, changing player's momx/y would possibly trigger stuff as if the player were running somehow, so this must be done to keep the player standing // All this so players can ride gargoyles! - boolean oldfltok = floatok; - fixed_t oldflrz = tmfloorz; - fixed_t oldceilz = tmceilingz; - mobj_t *oldflrthing = tmfloorthing; - mobj_t *oldthing = tmthing; - line_t *oldceilline = ceilingline; - line_t *oldblockline = blockingline; - ffloor_t *oldflrrover = tmfloorrover; - ffloor_t *oldceilrover = tmceilingrover; - pslope_t *oldfslope = tmfloorslope; - pslope_t *oldcslope = tmceilingslope; - INT32 oldfpic = tmfloorpic; - INT32 oldcpic = tmceilingpic; + tm_t oldtm = {0}; // Move the player - P_TryMove(thing, thing->x+stand->momx, thing->y+stand->momy, true); + P_TryMove(thing, thing->x + stand->momx, thing->y + stand->momy, true); // Now restore EVERYTHING so the gargoyle doesn't keep the player's tmstuff and break - floatok = oldfltok; - tmfloorz = oldflrz; - tmceilingz = oldceilz; - tmfloorthing = oldflrthing; - P_SetTarget(&tmthing, oldthing); - ceilingline = oldceilline; - blockingline = oldblockline; - tmfloorrover = oldflrrover; - tmceilingrover = oldceilrover; - tmfloorslope = oldfslope; - tmceilingslope = oldcslope; - tmfloorpic = oldfpic; - tmceilingpic = oldcpic; + tm = oldtm; + thing->momz = stand->momz; } else @@ -2566,7 +2528,7 @@ increment_move fixed_t radius = thing->radius; fixed_t thingtop; fixed_t stairjank = 0; - floatok = false; + tm.floatok = false; // reset this to 0 at the start of each trymove call as it's only used here numspechitint = 0U; @@ -2578,14 +2540,6 @@ increment_move // And Big Large (tm) movements can skip over slopes. radius = min(radius, 16*mapobjectscale); -#if 0 - if (thing->hitlag > 0) - { - // Do not move during hitlag - return false; - } -#endif - do { if (thing->flags & MF_NOCLIP) { @@ -2620,14 +2574,14 @@ increment_move //All things are affected by their scale. fixed_t maxstep = P_GetThingStepUp(thing, tryx, tryy); - if (tmceilingz - tmfloorz < thing->height) + if (tm.ceilingz - tm.floorz < thing->height) { - if (tmfloorthing) - tmhitthing = tmfloorthing; + if (tm.floorthing) + tm.hitthing = tm.floorthing; return false; // doesn't fit } - floatok = true; + tm.floatok = true; if (maxstep > 0) { @@ -2637,15 +2591,15 @@ increment_move thingtop = thing->z + thing->height; // Step up - if (thing->z < tmfloorz) + if (thing->z < tm.floorz) { - if (tmfloorstep <= maxstep) + if (tm.floorstep <= maxstep) { if (!flipped) - stairjank = tmfloorstep; + stairjank = tm.floorstep; - thing->z = thing->floorz = tmfloorz; - thing->floorrover = tmfloorrover; + thing->z = thing->floorz = tm.floorz; + thing->floorrover = tm.floorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } else @@ -2653,15 +2607,15 @@ increment_move return false; // mobj must raise itself to fit } } - else if (tmceilingz < thingtop) + else if (tm.ceilingz < thingtop) { - if (tmceilingstep <= maxstep) + if (tm.ceilingstep <= maxstep) { if (flipped) - stairjank = tmceilingstep; + stairjank = tm.ceilingstep; - thing->z = ( thing->ceilingz = tmceilingz ) - thing->height; - thing->ceilingrover = tmceilingrover; + thing->z = ( thing->ceilingz = tm.ceilingz ) - thing->height; + thing->ceilingrover = tm.ceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; } else @@ -2676,37 +2630,37 @@ increment_move // If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS // step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more. - if (thingtop == thing->ceilingz && tmceilingz > thingtop && tmceilingz - thingtop <= maxstep) + if (thingtop == thing->ceilingz && tm.ceilingz > thingtop && tm.ceilingz - thingtop <= maxstep) { if (flipped) - stairjank = (tmceilingz - thingtop); + stairjank = (tm.ceilingz - thingtop); - thing->z = (thing->ceilingz = tmceilingz) - thing->height; - thing->ceilingrover = tmceilingrover; + thing->z = (thing->ceilingz = tm.ceilingz) - thing->height; + thing->ceilingrover = tm.ceilingrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; thing->ceilingdrop = 0; } - else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->z - tmfloorz <= maxstep) + else if (thing->z == thing->floorz && tm.floorz < thing->z && thing->z - tm.floorz <= maxstep) { if (!flipped) - stairjank = (thing->z - tmfloorz); + stairjank = (thing->z - tm.floorz); - thing->z = thing->floorz = tmfloorz; - thing->floorrover = tmfloorrover; + thing->z = thing->floorz = tm.floorz; + thing->floorrover = tm.floorrover; thing->eflags |= MFE_JUSTSTEPPEDDOWN; thing->floordrop = 0; } } } - if (!allowdropoff && !(thing->flags & MF_FLOAT) && thing->type != MT_SKIM && !tmfloorthing) + if (!allowdropoff && !(thing->flags & MF_FLOAT) && thing->type != MT_SKIM && !tm.floorthing) { if (thing->eflags & MFE_VERTICALFLIP) { - if (tmdrpoffceilz - tmceilingz > maxstep) + if (tm.drpoffceilz - tm.ceilingz > maxstep) return false; } - else if (tmfloorz - tmdropoffz > maxstep) + else if (tm.floorz - tm.dropoffz > maxstep) return false; // don't stand over a dropoff } } @@ -2724,7 +2678,7 @@ increment_move // boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) { - boolean moveok; + boolean moveok = false; mobj_t *hack = P_SpawnMobjFromMobj(thing, 0, 0, 0, MT_RAY); hack->radius = thing->radius; @@ -2748,9 +2702,11 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) fixed_t stairjank = 0; pslope_t *oldslope = thing->standingslope; - // The move is ok! - if (!increment_move(thing, x, y, allowdropoff, &stairjank)) + // Is the move OK? + if (increment_move(thing, x, y, allowdropoff, &stairjank) == false) + { return false; + } // If it's a pushable object, check if anything is // standing on top and move it, too. @@ -2777,21 +2733,21 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) // Link the thing into its new position P_UnsetThingPosition(thing); - thing->floorz = tmfloorz; - thing->ceilingz = tmceilingz; - thing->floorrover = tmfloorrover; - thing->ceilingrover = tmceilingrover; + thing->floorz = tm.floorz; + thing->ceilingz = tm.ceilingz; + thing->floorrover = tm.floorrover; + thing->ceilingrover = tm.ceilingrover; if (!(thing->flags & MF_NOCLIPHEIGHT)) { // Assign thing's standingslope if needed - if (thing->z <= tmfloorz && !(thing->eflags & MFE_VERTICALFLIP)) + if (thing->z <= tm.floorz && !(thing->eflags & MFE_VERTICALFLIP)) { - K_UpdateMobjTerrain(thing, tmfloorpic); + K_UpdateMobjTerrain(thing, tm.floorpic); - if (!startingonground && tmfloorslope) + if (!startingonground && tm.floorslope) { - P_HandleSlopeLanding(thing, tmfloorslope); + P_HandleSlopeLanding(thing, tm.floorslope); } if (thing->momz <= 0) @@ -2799,7 +2755,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) angle_t oldPitch = thing->pitch; angle_t oldRoll = thing->roll; - thing->standingslope = tmfloorslope; + thing->standingslope = tm.floorslope; P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->player) @@ -2808,13 +2764,13 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } } } - else if (thing->z+thing->height >= tmceilingz && (thing->eflags & MFE_VERTICALFLIP)) + else if (thing->z+thing->height >= tm.ceilingz && (thing->eflags & MFE_VERTICALFLIP)) { - K_UpdateMobjTerrain(thing, tmceilingpic); + K_UpdateMobjTerrain(thing, tm.ceilingpic); - if (!startingonground && tmceilingslope) + if (!startingonground && tm.ceilingslope) { - P_HandleSlopeLanding(thing, tmceilingslope); + P_HandleSlopeLanding(thing, tm.ceilingslope); } if (thing->momz >= 0) @@ -2822,7 +2778,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) angle_t oldPitch = thing->pitch; angle_t oldRoll = thing->roll; - thing->standingslope = tmceilingslope; + thing->standingslope = tm.ceilingslope; P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->player) @@ -2869,7 +2825,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) thing->x = x; thing->y = y; - if (tmfloorthing) + if (tm.floorthing) thing->eflags &= ~MFE_ONGROUND; // not on real floor else thing->eflags |= MFE_ONGROUND; @@ -2926,13 +2882,13 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) { const fixed_t maxstep = P_BaseStepUp(); - if (tmceilingz - tmfloorz < thing->height) + if (tm.ceilingz - tm.floorz < thing->height) return false; // doesn't fit - if (tmceilingz - thing->z < thing->height) + if (tm.ceilingz - thing->z < thing->height) return false; // mobj must lower itself to fit - if (tmfloorz - thing->z > maxstep) + if (tm.floorz - thing->z > maxstep) return false; // too big a step up } } while(tryx != x || tryy != y); @@ -2941,14 +2897,14 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) // so link the thing into its new position P_UnsetThingPosition(thing); - thing->floorz = tmfloorz; - thing->ceilingz = tmceilingz; - thing->floorrover = tmfloorrover; - thing->ceilingrover = tmceilingrover; + thing->floorz = tm.floorz; + thing->ceilingz = tm.ceilingz; + thing->floorrover = tm.floorrover; + thing->ceilingrover = tm.ceilingrover; thing->x = x; thing->y = y; - if (tmfloorthing) + if (tm.floorthing) thing->eflags &= ~MFE_ONGROUND; // not on real floor else thing->eflags |= MFE_ONGROUND; @@ -3076,17 +3032,17 @@ static boolean P_ThingHeightClip(mobj_t *thing) if (P_MobjWasRemoved(thing)) return true; - floormoved = (thing->eflags & MFE_VERTICALFLIP && tmceilingz != thing->ceilingz) - || (!(thing->eflags & MFE_VERTICALFLIP) && tmfloorz != thing->floorz); + floormoved = (thing->eflags & MFE_VERTICALFLIP && tm.ceilingz != thing->ceilingz) + || (!(thing->eflags & MFE_VERTICALFLIP) && tm.floorz != thing->floorz); - thing->floorz = tmfloorz; - thing->ceilingz = tmceilingz; - thing->floorrover = tmfloorrover; - thing->ceilingrover = tmceilingrover; + thing->floorz = tm.floorz; + thing->ceilingz = tm.ceilingz; + thing->floorrover = tm.floorrover; + thing->ceilingrover = tm.ceilingrover; // Ugly hack?!?! As long as just ceilingz is the lowest, // you'll still get crushed, right? - if (tmfloorz > oldfloorz+thing->height) + if (tm.floorz > oldfloorz+thing->height) return true; if (onfloor && !(thing->flags & MF_NOGRAVITY) && floormoved) @@ -3110,15 +3066,15 @@ static boolean P_ThingHeightClip(mobj_t *thing) thing->z = thing->floorz; } } - else if (!tmfloorthing) + else if (!tm.floorthing) { // don't adjust a floating monster unless forced to if (thing->eflags & MFE_VERTICALFLIP) { - if (!onfloor && thing->z < tmfloorz) + if (!onfloor && thing->z < tm.floorz) thing->z = thing->floorz; } - else if (!onfloor && thing->z + thing->height > tmceilingz) + else if (!onfloor && thing->z + thing->height > tm.ceilingz) thing->z = thing->ceilingz - thing->height; } @@ -3590,13 +3546,13 @@ void P_SlideMove(mobj_t *mo) if (P_MobjWasRemoved(mo)) return; - if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) + if (tm.hitthing && mo->z + mo->height > tm.hitthing->z && mo->z < tm.hitthing->z + tm.hitthing->height) { // Don't mess with your momentum if it's a pushable object. Pushables do their own crazy things already. - if (tmhitthing->flags & MF_PUSHABLE) + if (tm.hitthing->flags & MF_PUSHABLE) return; - if (tmhitthing->flags & MF_PAPERCOLLISION) + if (tm.hitthing->flags & MF_PAPERCOLLISION) { fixed_t cosradius, sinradius, num, den; @@ -3627,13 +3583,13 @@ void P_SlideMove(mobj_t *mo) slidemo = mo; bestslideline = &junk; - cosradius = FixedMul(tmhitthing->radius, FINECOSINE(tmhitthing->angle>>ANGLETOFINESHIFT)); - sinradius = FixedMul(tmhitthing->radius, FINESINE(tmhitthing->angle>>ANGLETOFINESHIFT)); + cosradius = FixedMul(tm.hitthing->radius, FINECOSINE(tm.hitthing->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(tm.hitthing->radius, FINESINE(tm.hitthing->angle>>ANGLETOFINESHIFT)); - v1.x = tmhitthing->x - cosradius; - v1.y = tmhitthing->y - sinradius; - v2.x = tmhitthing->x + cosradius; - v2.y = tmhitthing->y + sinradius; + v1.x = tm.hitthing->x - cosradius; + v1.y = tm.hitthing->y - sinradius; + v2.x = tm.hitthing->x + cosradius; + v2.y = tm.hitthing->y + sinradius; // Can we box collision our way into smooth movement..? if (sinradius && mo->y + mo->radius <= min(v1.y, v2.y)) @@ -3694,25 +3650,25 @@ void P_SlideMove(mobj_t *mo) } // Thankfully box collisions are a lot simpler than arbitrary lines. There's only four possible cases. - if (mo->y + mo->radius <= tmhitthing->y - tmhitthing->radius) + if (mo->y + mo->radius <= tm.hitthing->y - tm.hitthing->radius) { mo->momy = 0; - P_TryMove(mo, mo->x + mo->momx, tmhitthing->y - tmhitthing->radius - mo->radius, true); + P_TryMove(mo, mo->x + mo->momx, tm.hitthing->y - tm.hitthing->radius - mo->radius, true); } - else if (mo->y - mo->radius >= tmhitthing->y + tmhitthing->radius) + else if (mo->y - mo->radius >= tm.hitthing->y + tm.hitthing->radius) { mo->momy = 0; - P_TryMove(mo, mo->x + mo->momx, tmhitthing->y + tmhitthing->radius + mo->radius, true); + P_TryMove(mo, mo->x + mo->momx, tm.hitthing->y + tm.hitthing->radius + mo->radius, true); } - else if (mo->x + mo->radius <= tmhitthing->x - tmhitthing->radius) + else if (mo->x + mo->radius <= tm.hitthing->x - tm.hitthing->radius) { mo->momx = 0; - P_TryMove(mo, tmhitthing->x - tmhitthing->radius - mo->radius, mo->y + mo->momy, true); + P_TryMove(mo, tm.hitthing->x - tm.hitthing->radius - mo->radius, mo->y + mo->momy, true); } - else if (mo->x - mo->radius >= tmhitthing->x + tmhitthing->radius) + else if (mo->x - mo->radius >= tm.hitthing->x + tm.hitthing->radius) { mo->momx = 0; - P_TryMove(mo, tmhitthing->x + tmhitthing->radius + mo->radius, mo->y + mo->momy, true); + P_TryMove(mo, tm.hitthing->x + tm.hitthing->radius + mo->radius, mo->y + mo->momy, true); } else mo->momx = mo->momy = 0; @@ -4779,13 +4735,13 @@ void P_DelPrecipSeclist(mprecipsecnode_t *node) static inline BlockItReturn_t PIT_GetSectors(line_t *ld) { - if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || - tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || - tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || - tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (tm.bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || + tm.bbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || + tm.bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || + tm.bbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) return BMIT_CONTINUE; - if (P_BoxOnLineSide(tmbbox, ld) != -1) + if (P_BoxOnLineSide(tm.bbox, ld) != -1) return BMIT_CONTINUE; if (ld->polyobj) // line belongs to a polyobject, don't add it @@ -4798,7 +4754,7 @@ static inline BlockItReturn_t PIT_GetSectors(line_t *ld) // allowed to move to this position, then the sector_list // will be attached to the Thing's mobj_t at touching_sectorlist. - sector_list = P_AddSecnode(ld->frontsector,tmthing,sector_list); + sector_list = P_AddSecnode(ld->frontsector,tm.thing,sector_list); // Don't assume all lines are 2-sided, since some Things // like MT_TFOG are allowed regardless of whether their radius takes @@ -4806,7 +4762,7 @@ static inline BlockItReturn_t PIT_GetSectors(line_t *ld) // Use sidedefs instead of 2s flag to determine two-sidedness. if (ld->backsector) - sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list); + sector_list = P_AddSecnode(ld->backsector, tm.thing, sector_list); return BMIT_CONTINUE; } @@ -4814,13 +4770,13 @@ static inline BlockItReturn_t PIT_GetSectors(line_t *ld) // Tails 08-25-2002 static inline BlockItReturn_t PIT_GetPrecipSectors(line_t *ld) { - if (preciptmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || - preciptmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || - preciptmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || - preciptmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) + if (tm.precipbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || + tm.precipbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || + tm.precipbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || + tm.precipbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) return BMIT_CONTINUE; - if (P_BoxOnLineSide(preciptmbbox, ld) != -1) + if (P_BoxOnLineSide(tm.precipbbox, ld) != -1) return BMIT_CONTINUE; if (ld->polyobj) // line belongs to a polyobject, don't add it @@ -4833,7 +4789,7 @@ static inline BlockItReturn_t PIT_GetPrecipSectors(line_t *ld) // allowed to move to this position, then the sector_list // will be attached to the Thing's mobj_t at touching_sectorlist. - precipsector_list = P_AddPrecipSecnode(ld->frontsector, tmprecipthing, precipsector_list); + precipsector_list = P_AddPrecipSecnode(ld->frontsector, tm.precipthing, precipsector_list); // Don't assume all lines are 2-sided, since some Things // like MT_TFOG are allowed regardless of whether their radius takes @@ -4841,7 +4797,7 @@ static inline BlockItReturn_t PIT_GetPrecipSectors(line_t *ld) // Use sidedefs instead of 2s flag to determine two-sidedness. if (ld->backsector) - precipsector_list = P_AddPrecipSecnode(ld->backsector, tmprecipthing, precipsector_list); + precipsector_list = P_AddPrecipSecnode(ld->backsector, tm.precipthing, precipsector_list); return BMIT_CONTINUE; } @@ -4853,8 +4809,7 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y) { INT32 xl, xh, yl, yh, bx, by; msecnode_t *node = sector_list; - mobj_t *saved_tmthing = tmthing; /* cph - see comment at func end */ - fixed_t saved_tmx = tmx, saved_tmy = tmy; /* ditto */ + tm_t ptm = tm; /* cph - see comment at func end */ // First, clear out the existing m_thing fields. As each node is // added or verified as needed, m_thing will be set properly. When @@ -4867,23 +4822,23 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y) node = node->m_sectorlist_next; } - P_SetTarget(&tmthing, thing); - tmflags = thing->flags; + P_SetTarget(&tm.thing, thing); + tm.flags = thing->flags; - tmx = x; - tmy = y; + tm.x = x; + tm.y = y; - tmbbox[BOXTOP] = y + tmthing->radius; - tmbbox[BOXBOTTOM] = y - tmthing->radius; - tmbbox[BOXRIGHT] = x + tmthing->radius; - tmbbox[BOXLEFT] = x - tmthing->radius; + tm.bbox[BOXTOP] = y + tm.thing->radius; + tm.bbox[BOXBOTTOM] = y - tm.thing->radius; + tm.bbox[BOXRIGHT] = x + tm.thing->radius; + tm.bbox[BOXLEFT] = x - tm.thing->radius; validcount++; // used to make sure we only process a line once - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); @@ -4910,26 +4865,14 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y) } /* cph - - * This is the strife we get into for using global variables. tmthing + * This is the strife we get into for using global variables. tm.thing * is being used by several different functions calling * P_BlockThingIterator, including functions that can be called *from* - * P_BlockThingIterator. Using a global tmthing is not reentrant. + * P_BlockThingIterator. Using a global tm.thing is not reentrant. * OTOH for Boom/MBF demos we have to preserve the buggy behavior. * Fun. We restore its previous value unless we're in a Boom/MBF demo. */ - P_SetTarget(&tmthing, saved_tmthing); - - /* And, duh, the same for tmx/y - cph 2002/09/22 - * And for tmbbox - cph 2003/08/10 */ - tmx = saved_tmx, tmy = saved_tmy; - - if (tmthing) - { - tmbbox[BOXTOP] = tmy + tmthing->radius; - tmbbox[BOXBOTTOM] = tmy - tmthing->radius; - tmbbox[BOXRIGHT] = tmx + tmthing->radius; - tmbbox[BOXLEFT] = tmx - tmthing->radius; - } + tm = ptm; } // More crazy crap Tails 08-25-2002 @@ -4937,7 +4880,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) { INT32 xl, xh, yl, yh, bx, by; mprecipsecnode_t *node = precipsector_list; - precipmobj_t *saved_tmthing = tmprecipthing; /* cph - see comment at func end */ + tm_t ptm = tm; /* cph - see comment at func end */ // First, clear out the existing m_thing fields. As each node is // added or verified as needed, m_thing will be set properly. When @@ -4950,19 +4893,19 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) node = node->m_sectorlist_next; } - tmprecipthing = thing; + tm.precipthing = thing; - preciptmbbox[BOXTOP] = y + 2*FRACUNIT; - preciptmbbox[BOXBOTTOM] = y - 2*FRACUNIT; - preciptmbbox[BOXRIGHT] = x + 2*FRACUNIT; - preciptmbbox[BOXLEFT] = x - 2*FRACUNIT; + tm.precipbbox[BOXTOP] = y + 2*FRACUNIT; + tm.precipbbox[BOXBOTTOM] = y - 2*FRACUNIT; + tm.precipbbox[BOXRIGHT] = x + 2*FRACUNIT; + tm.precipbbox[BOXLEFT] = x - 2*FRACUNIT; validcount++; // used to make sure we only process a line once - xl = (unsigned)(preciptmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(preciptmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(preciptmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(preciptmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(tm.precipbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(tm.precipbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(tm.precipbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(tm.precipbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); @@ -4989,27 +4932,27 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) } /* cph - - * This is the strife we get into for using global variables. tmthing + * This is the strife we get into for using global variables. tm.thing * is being used by several different functions calling * P_BlockThingIterator, including functions that can be called *from* - * P_BlockThingIterator. Using a global tmthing is not reentrant. + * P_BlockThingIterator. Using a global tm.thing is not reentrant. * OTOH for Boom/MBF demos we have to preserve the buggy behavior. * Fun. We restore its previous value unless we're in a Boom/MBF demo. */ - tmprecipthing = saved_tmthing; + tm = ptm; } /* cphipps 2004/08/30 - - * Must clear tmthing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */ + * Must clear tm.thing at tic end, as it might contain a pointer to a removed thinker, or the level might have ended/been ended and we clear the objects it was pointing too. Hopefully we don't need to carry this between tics for sync. */ void P_MapStart(void) { - if (tmthing) - I_Error("P_MapStart: tmthing set!"); + if (tm.thing) + I_Error("P_MapStart: tm.thing set!"); } void P_MapEnd(void) { - P_SetTarget(&tmthing, NULL); + P_SetTarget(&tm.thing, NULL); } // P_FloorzAtPos diff --git a/src/p_maputl.c b/src/p_maputl.c index ab810e437..7eb4a7e19 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -379,8 +379,8 @@ void P_CameraLineOpening(line_t *linedef) } else { - frontfloor = P_CameraGetFloorZ (mapcampointer, front, tmx, tmy, linedef); - frontceiling = P_CameraGetCeilingZ(mapcampointer, front, tmx, tmy, linedef); + frontfloor = P_CameraGetFloorZ (mapcampointer, front, tm.x, tm.y, linedef); + frontceiling = P_CameraGetCeilingZ(mapcampointer, front, tm.x, tm.y, linedef); } if (back->camsec >= 0) @@ -397,8 +397,8 @@ void P_CameraLineOpening(line_t *linedef) } else { - backfloor = P_CameraGetFloorZ(mapcampointer, back, tmx, tmy, linedef); - backceiling = P_CameraGetCeilingZ(mapcampointer, back, tmx, tmy, linedef); + backfloor = P_CameraGetFloorZ(mapcampointer, back, tm.x, tm.y, linedef); + backceiling = P_CameraGetCeilingZ(mapcampointer, back, tm.x, tm.y, linedef); } { @@ -440,8 +440,8 @@ void P_CameraLineOpening(line_t *linedef) if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; - topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tmx, tmy, linedef); - bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tmx, tmy, linedef); + topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tm.x, tm.y, linedef); + bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tm.x, tm.y, linedef); delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); @@ -464,8 +464,8 @@ void P_CameraLineOpening(line_t *linedef) if (!(rover->fofflags & FOF_BLOCKOTHERS) || !(rover->fofflags & FOF_RENDERALL) || !(rover->fofflags & FOF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; - topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tmx, tmy, linedef); - bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tmx, tmy, linedef); + topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tm.x, tm.y, linedef); + bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tm.x, tm.y, linedef); delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); @@ -614,7 +614,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) return; } - P_ClosestPointOnLine(tmx, tmy, linedef, &cross); + P_ClosestPointOnLine(tm.x, tm.y, linedef, &cross); // Treat polyobjects kind of like 3D Floors if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) @@ -656,8 +656,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) fixed_t height[2]; const sector_t * sector[2] = { front, back }; - height[FRONT] = P_GetCeilingZ(mobj, front, tmx, tmy, linedef); - height[BACK] = P_GetCeilingZ(mobj, back, tmx, tmy, linedef); + height[FRONT] = P_GetCeilingZ(mobj, front, tm.x, tm.y, linedef); + height[BACK] = P_GetCeilingZ(mobj, back, tm.x, tm.y, linedef); hi = ( height[0] < height[1] ); lo = ! hi; @@ -676,8 +676,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) openceilingdrop = ( topedge[hi] - topedge[lo] ); } - height[FRONT] = P_GetFloorZ(mobj, front, tmx, tmy, linedef); - height[BACK] = P_GetFloorZ(mobj, back, tmx, tmy, linedef); + height[FRONT] = P_GetFloorZ(mobj, front, tm.x, tm.y, linedef); + height[BACK] = P_GetFloorZ(mobj, back, tm.x, tm.y, linedef); hi = ( height[0] < height[1] ); lo = ! hi; @@ -818,8 +818,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) || (rover->fofflags & FOF_BLOCKOTHERS && !mobj->player))) continue; - topheight = P_GetFOFTopZ(mobj, front, rover, tmx, tmy, linedef); - bottomheight = P_GetFOFBottomZ(mobj, front, rover, tmx, tmy, linedef); + topheight = P_GetFOFTopZ(mobj, front, rover, tm.x, tm.y, linedef); + bottomheight = P_GetFOFBottomZ(mobj, front, rover, tm.x, tm.y, linedef); delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); @@ -862,8 +862,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) || (rover->fofflags & FOF_BLOCKOTHERS && !mobj->player))) continue; - topheight = P_GetFOFTopZ(mobj, back, rover, tmx, tmy, linedef); - bottomheight = P_GetFOFBottomZ(mobj, back, rover, tmx, tmy, linedef); + topheight = P_GetFOFTopZ(mobj, back, rover, tm.x, tm.y, linedef); + bottomheight = P_GetFOFBottomZ(mobj, back, rover, tm.x, tm.y, linedef); delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2))); delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2))); @@ -1596,16 +1596,16 @@ boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y, INT32 xl, xh, yl, yh; INT32 bx, by; - tmbbox[BOXTOP] = y + radius; - tmbbox[BOXBOTTOM] = y - radius; - tmbbox[BOXRIGHT] = x + radius; - tmbbox[BOXLEFT] = x - radius; + tm.bbox[BOXTOP] = y + radius; + tm.bbox[BOXBOTTOM] = y - radius; + tm.bbox[BOXRIGHT] = x + radius; + tm.bbox[BOXLEFT] = x - radius; // check lines - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(tm.bbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(tm.bbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(tm.bbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(tm.bbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; for (bx = xl; bx <= xh; bx++) for (by = yl; by <= yh; by++) diff --git a/src/p_maputl.h b/src/p_maputl.h index 29e7d4de9..7ac6baa3f 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -85,8 +85,6 @@ boolean P_BlockThingsIterator(INT32 x, INT32 y, BlockItReturn_t(*func)(mobj_t *) extern divline_t trace; -extern fixed_t tmbbox[4]; // p_map.c - // call your user function for each line of the blockmap in the // bbox defined by the radius //boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y, diff --git a/src/p_mobj.c b/src/p_mobj.c index d5924de51..7723616e5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1491,12 +1491,12 @@ bustupdone: // static boolean P_CheckSkyHit(mobj_t *mo) { - if (ceilingline && ceilingline->backsector - && ceilingline->backsector->ceilingpic == skyflatnum - && ceilingline->frontsector - && ceilingline->frontsector->ceilingpic == skyflatnum - && (mo->z >= ceilingline->frontsector->ceilingheight - || mo->z >= ceilingline->backsector->ceilingheight)) + if (tm.ceilingline && tm.ceilingline->backsector + && tm.ceilingline->backsector->ceilingpic == skyflatnum + && tm.ceilingline->frontsector + && tm.ceilingline->frontsector->ceilingpic == skyflatnum + && (mo->z >= tm.ceilingline->frontsector->ceilingheight + || mo->z >= tm.ceilingline->backsector->ceilingheight)) return true; return false; } @@ -1601,7 +1601,7 @@ void P_XYMovement(mobj_t *mo) // blocked move moved = false; - if (LUA_HookMobjMoveBlocked(mo, tmhitthing, blockingline)) + if (LUA_HookMobjMoveBlocked(mo, tm.hitthing, tm.blockingline)) { if (P_MobjWasRemoved(mo)) return; @@ -1626,7 +1626,7 @@ void P_XYMovement(mobj_t *mo) // draw damage on wall //SPLAT TEST ---------------------------------------------------------- #ifdef WALLSPLATS - if (blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL + if (tm.blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL && !(mo->flags2 & (MF2_AUTOMATIC|MF2_RAILRING|MF2_BOUNCERING|MF2_EXPLOSION|MF2_SCATTER))) // set by last P_TryMove() that failed { @@ -1634,13 +1634,13 @@ void P_XYMovement(mobj_t *mo) divline_t misl; fixed_t frac; - P_MakeDivline(blockingline, &divl); + P_MakeDivline(tm.blockingline, &divl); misl.x = mo->x; misl.y = mo->y; misl.dx = mo->momx; misl.dy = mo->momy; frac = P_InterceptVector(&divl, &misl); - R_AddWallSplat(blockingline, P_PointOnLineSide(mo->x,mo->y,blockingline), + R_AddWallSplat(tm.blockingline, P_PointOnLineSide(mo->x,mo->y,tm.blockingline), "A_DMG3", mo->z, frac, SPLATDRAWMODE_SHADE); } #endif @@ -2371,11 +2371,11 @@ boolean P_ZMovement(mobj_t *mo) if (P_MobjWasRemoved(mo)) // mobjs can be removed by P_CheckPosition -- Monster Iestyn 31/07/21 return false; - K_UpdateMobjTerrain(mo, ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingpic : tmfloorpic)); + K_UpdateMobjTerrain(mo, ((mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingpic : tm.floorpic)); - if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM)) + if (((mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingslope : tm.floorslope) && (mo->type != MT_STEAM)) { - mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; + mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tm.ceilingslope : tm.floorslope; P_SetPitchRollFromSlope(mo, mo->standingslope); P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope); } @@ -2591,11 +2591,11 @@ boolean P_ZMovement(mobj_t *mo) } } else - mom.z = (tmfloorthing ? tmfloorthing->momz : 0); + mom.z = (tm.floorthing ? tm.floorthing->momz : 0); } - else if (tmfloorthing) - mom.z = tmfloorthing->momz; + else if (tm.floorthing) + mom.z = tm.floorthing->momz; if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above. P_QuantizeMomentumToSlope(&mom, mo->standingslope); @@ -2834,7 +2834,7 @@ void P_PlayerZMovement(mobj_t *mo) mo->z = mo->floorz; } - K_UpdateMobjTerrain(mo, (mo->eflags & MFE_VERTICALFLIP ? tmceilingpic : tmfloorpic)); + K_UpdateMobjTerrain(mo, (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingpic : tm.floorpic)); // Get up if you fell. if (mo->player->panim == PA_HURT && mo->player->spinouttimer == 0 && mo->player->tumbleBounces == 0) @@ -2842,10 +2842,10 @@ void P_PlayerZMovement(mobj_t *mo) P_SetPlayerMobjState(mo, S_KART_STILL); } - if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) + if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingslope : tm.floorslope)) { // Handle landing on slope during Z movement - P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)); + P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tm.ceilingslope : tm.floorslope)); } if (P_MobjFlip(mo) * mo->momz < 0) // falling @@ -2860,12 +2860,12 @@ void P_PlayerZMovement(mobj_t *mo) if (clipmomz) { - mo->momz = (tmfloorthing ? tmfloorthing->momz : 0); + mo->momz = (tm.floorthing ? tm.floorthing->momz : 0); } } - else if (tmfloorthing) + else if (tm.floorthing) { - mo->momz = tmfloorthing->momz; + mo->momz = tm.floorthing->momz; } } else @@ -3083,9 +3083,9 @@ boolean P_SceneryZMovement(mobj_t *mo) { mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack - if (tmfloorthing) - mo->momz = tmfloorthing->momz; - else if (!tmfloorthing) + if (tm.floorthing) + mo->momz = tm.floorthing->momz; + else if (!tm.floorthing) mo->momz = 0; } } @@ -3801,8 +3801,8 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled } thiscam->subsector = R_PointInSubsector(thiscam->x, thiscam->y); - thiscam->floorz = tmfloorz; - thiscam->ceilingz = tmceilingz; + thiscam->floorz = tm.floorz; + thiscam->ceilingz = tm.ceilingz; if (thiscam->momz || player->mo->pmomz) { @@ -3960,8 +3960,8 @@ static void P_PlayerMobjThinker(mobj_t *mobj) mobj->z += mobj->momz; P_SetThingPosition(mobj); P_CheckPosition(mobj, mobj->x, mobj->y); - mobj->floorz = tmfloorz; - mobj->ceilingz = tmceilingz; + mobj->floorz = tm.floorz; + mobj->ceilingz = tm.ceilingz; goto animonly; } @@ -9451,7 +9451,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED); - tmfloorthing = tmhitthing = NULL; + tm.floorthing = tm.hitthing = NULL; // Sector flag MSF_TRIGGERLINE_MOBJ allows ANY mobj to trigger a linedef exec P_CheckMobjTrigger(mobj, false); @@ -9809,10 +9809,10 @@ void P_SceneryThinker(mobj_t *mobj) P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! if (P_MobjWasRemoved(mobj)) return; - mobj->floorz = tmfloorz; - mobj->ceilingz = tmceilingz; - mobj->floorrover = tmfloorrover; - mobj->ceilingrover = tmceilingrover; + mobj->floorz = tm.floorz; + mobj->ceilingz = tm.ceilingz; + mobj->floorrover = tm.floorrover; + mobj->ceilingrover = tm.ceilingrover; } else { diff --git a/src/p_polyobj.c b/src/p_polyobj.c index cd946e5ee..04f2c0d0c 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -762,7 +762,7 @@ static void Polyobj_removeFromBlockmap(polyobj_t *po) // Movement functions // A version of Lee's routine from p_maputl.c that accepts an mobj pointer -// argument instead of using tmthing. Returns true if the line isn't contacted +// argument instead of using tm.thing. Returns true if the line isn't contacted // and false otherwise. static inline boolean Polyobj_untouched(line_t *ld, mobj_t *mo) { @@ -806,10 +806,10 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) if (po->damage && (mo->flags & MF_SHOOTABLE)) { P_CheckPosition(mo, mo->x + momx, mo->y + momy); - mo->floorz = tmfloorz; - mo->ceilingz = tmceilingz; - mo->floorrover = tmfloorrover; - mo->ceilingrover = tmceilingrover; + mo->floorz = tm.floorz; + mo->ceilingz = tm.ceilingz; + mo->floorrover = tm.floorrover; + mo->ceilingrover = tm.ceilingrover; } } diff --git a/src/p_setup.c b/src/p_setup.c index efadfedd9..92f054eb6 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7465,7 +7465,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_ResetTubeWaypoints(); - P_MapStart(); // tmthing can be used starting from this point + P_MapStart(); // tm.thing can be used starting from this point // init anything that P_SpawnSlopes/P_LoadThings needs to know P_InitSpecials(); @@ -7570,7 +7570,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_RunCachedActions(); - P_MapEnd(); // tmthing is no longer needed from this point onwards + P_MapEnd(); // tm.thing is no longer needed from this point onwards // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... if (!titlemapinaction) @@ -7629,9 +7629,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); } P_PreTicker(2); - P_MapStart(); // just in case MapLoad modifies tmthing + P_MapStart(); // just in case MapLoad modifies tm.thing LUA_HookInt(gamemap, HOOK(MapLoad)); - P_MapEnd(); // just in case MapLoad modifies tmthing + P_MapEnd(); // just in case MapLoad modifies tm.thing } K_TimerReset(); diff --git a/src/p_sight.c b/src/p_sight.c index 4a8ccab39..64bba3969 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -749,10 +749,10 @@ static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t } // set openrange, opentop, openbottom - tmx = tb->compareThing->x; - tmy = tb->compareThing->y; + tm.x = tb->compareThing->x; + tm.y = tb->compareThing->y; P_LineOpening(line, tb->compareThing); - maxstep = P_GetThingStepUp(tb->compareThing, tmx, tmy); + maxstep = P_GetThingStepUp(tb->compareThing, tm.x, tm.y); if ((openrange < tb->compareThing->height) // doesn't fit || (opentop - tb->compareThing->z < tb->compareThing->height) // mobj is too high From 11a6287c80d9122d1cbcad6b3cd10372a9560d09 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 21 Nov 2022 15:41:24 -0500 Subject: [PATCH 41/67] Reference count tm.floorthing and tm.hitthing --- src/p_map.c | 28 ++++++++++++++++++---------- src/p_mobj.c | 4 +++- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 0fc07d0cf..3d47f2433 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1466,7 +1466,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) tm.ceilingrover = NULL; tm.ceilingslope = NULL; tm.ceilingpic = -1; - tm.floorthing = thing; // needed for side collision + P_SetTarget(&tm.floorthing, thing); // needed for side collision } else if (topz < tm.ceilingz && tm.thing->z <= thing->z+thing->height) { @@ -1474,7 +1474,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) tm.ceilingrover = NULL; tm.ceilingslope = NULL; tm.ceilingpic = -1; - tm.floorthing = thing; // thing we may stand on + P_SetTarget(&tm.floorthing, thing); // thing we may stand on } } else @@ -1510,7 +1510,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) tm.floorrover = NULL; tm.floorslope = NULL; tm.floorpic = -1; - tm.floorthing = thing; // needed for side collision + P_SetTarget(&tm.floorthing, thing); // needed for side collision } else if (topz > tm.floorz && tm.thing->z+tm.thing->height >= thing->z) { @@ -1518,7 +1518,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) tm.floorrover = NULL; tm.floorslope = NULL; tm.floorpic = -1; - tm.floorthing = thing; // thing we may stand on + P_SetTarget(&tm.floorthing, thing); // thing we may stand on } } } @@ -2052,8 +2052,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) } // tm.floorthing is set when tm.floorz comes from a thing's top - tm.floorthing = NULL; - tm.hitthing = NULL; + P_SetTarget(&tm.floorthing, NULL); + P_SetTarget(&tm.hitthing, NULL); validcount++; @@ -2072,9 +2072,14 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) for (by = yl; by <= yh; by++) { if (!P_BlockThingsIterator(bx, by, PIT_CheckThing)) + { blockval = false; + } else - tm.hitthing = tm.floorthing; + { + P_SetTarget(&tm.hitthing, tm.floorthing); + } + if (P_MobjWasRemoved(tm.thing)) return false; } @@ -2452,7 +2457,7 @@ BlockItReturn_t PIT_PushableMoved(mobj_t *thing) // These are all non-static map variables that are changed for each and every single mobj // See, changing player's momx/y would possibly trigger stuff as if the player were running somehow, so this must be done to keep the player standing // All this so players can ride gargoyles! - tm_t oldtm = {0}; + tm_t oldtm = tm; // Move the player P_TryMove(thing, thing->x + stand->momx, thing->y + stand->momy, true); @@ -2576,8 +2581,11 @@ increment_move if (tm.ceilingz - tm.floorz < thing->height) { - if (tm.floorthing) - tm.hitthing = tm.floorthing; + if (tm.floorthing != NULL) + { + P_SetTarget(&tm.hitthing, tm.floorthing); + } + return false; // doesn't fit } diff --git a/src/p_mobj.c b/src/p_mobj.c index 7723616e5..88d9c3994 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9451,7 +9451,9 @@ void P_MobjThinker(mobj_t *mobj) mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED); - tm.floorthing = tm.hitthing = NULL; + // sal: what the hell? is there any reason this isn't done, like, literally ANYWHERE else? + P_SetTarget(&tm.floorthing, NULL); + P_SetTarget(&tm.hitthing, NULL); // Sector flag MSF_TRIGGERLINE_MOBJ allows ANY mobj to trigger a linedef exec P_CheckMobjTrigger(mobj, false); From 35f1fe580ce99fc1100d30e4f77a3c10db9b3974 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 21 Nov 2022 15:59:19 -0500 Subject: [PATCH 42/67] P_RestoreTMStruct --- src/lua_baselib.c | 30 +++++++++++++++--------------- src/lua_maplib.c | 8 ++++---- src/lua_mobjlib.c | 6 +++--- src/p_local.h | 2 ++ src/p_map.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 57a260374..5120223cc 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1010,7 +1010,7 @@ static int lib_pRailThinker(lua_State *L) if (!mobj) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_RailThinker(mobj)); - tm = ptm; + P_RestoreTMStruct(ptm); return 1; } @@ -1023,7 +1023,7 @@ static int lib_pXYMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_XYMovement(actor); - tm = ptm; + P_RestoreTMStruct(ptm); return 0; } @@ -1036,7 +1036,7 @@ static int lib_pRingXYMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_RingXYMovement(actor); - tm = ptm; + P_RestoreTMStruct(ptm); return 0; } @@ -1049,7 +1049,7 @@ static int lib_pSceneryXYMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_SceneryXYMovement(actor); - tm = ptm; + P_RestoreTMStruct(ptm); return 0; } @@ -1063,7 +1063,7 @@ static int lib_pZMovement(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_ZMovement(actor)); P_CheckPosition(actor, actor->x, actor->y); - tm = ptm; + P_RestoreTMStruct(ptm); return 1; } @@ -1077,7 +1077,7 @@ static int lib_pRingZMovement(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); P_RingZMovement(actor); P_CheckPosition(actor, actor->x, actor->y); - tm = ptm; + P_RestoreTMStruct(ptm); return 0; } @@ -1091,7 +1091,7 @@ static int lib_pSceneryZMovement(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SceneryZMovement(actor)); P_CheckPosition(actor, actor->x, actor->y); - tm = ptm; + P_RestoreTMStruct(ptm); return 1; } @@ -1105,7 +1105,7 @@ static int lib_pPlayerZMovement(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); P_PlayerZMovement(actor); P_CheckPosition(actor, actor->x, actor->y); - tm = ptm; + P_RestoreTMStruct(ptm); return 0; } @@ -1313,7 +1313,7 @@ static int lib_pMovePlayer(lua_State *L) if (!player) return LUA_ErrInvalid(L, "player_t"); P_MovePlayer(player); - tm = ptm; + P_RestoreTMStruct(ptm); return 0; } @@ -1395,7 +1395,7 @@ static int lib_pCheckPosition(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_CheckPosition(thing, x, y)); LUA_PushUserdata(L, tm.thing, META_MOBJ); - tm = ptm; + P_RestoreTMStruct(ptm); return 2; } @@ -1412,7 +1412,7 @@ static int lib_pTryMove(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff)); LUA_PushUserdata(L, tm.thing, META_MOBJ); - tm = ptm; + P_RestoreTMStruct(ptm); return 2; } @@ -1427,7 +1427,7 @@ static int lib_pMove(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_Move(actor, speed)); LUA_PushUserdata(L, tm.thing, META_MOBJ); - tm = ptm; + P_RestoreTMStruct(ptm); return 2; } @@ -1445,7 +1445,7 @@ static int lib_pTeleportMove(lua_State *L) LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin"); lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); LUA_PushUserdata(L, tm.thing, META_MOBJ); - tm = ptm; + P_RestoreTMStruct(ptm); return 2; } @@ -1462,7 +1462,7 @@ static int lib_pSetOrigin(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SetOrigin(thing, x, y, z)); LUA_PushUserdata(L, tm.thing, META_MOBJ); - tm = ptm; + P_RestoreTMStruct(ptm); return 2; } @@ -1479,7 +1479,7 @@ static int lib_pMoveOrigin(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); LUA_PushUserdata(L, tm.thing, META_MOBJ); - tm = ptm; + P_RestoreTMStruct(ptm); return 2; } diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 209e8732e..0557456b2 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -731,7 +731,7 @@ static int sector_set(lua_State *L) sector->floorheight = lastpos; P_CheckSector(sector, true); } - tm = ptm; + P_RestoreTMStruct(ptm); break; } case sector_ceilingheight: { // ceilingheight @@ -745,7 +745,7 @@ static int sector_set(lua_State *L) sector->ceilingheight = lastpos; P_CheckSector(sector, true); } - tm = ptm; + P_RestoreTMStruct(ptm); break; } case sector_floorpic: @@ -2136,7 +2136,7 @@ static int ffloor_set(lua_State *L) *ffloor->topheight = lastpos; P_CheckSector(sector, true); } - tm = ptm; + P_RestoreTMStruct(ptm); break; } case ffloor_toppic: @@ -2157,7 +2157,7 @@ static int ffloor_set(lua_State *L) *ffloor->bottomheight = lastpos; P_CheckSector(sector, true); } - tm = ptm; + P_RestoreTMStruct(ptm); break; } case ffloor_bottompic: diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 8dcf20ac5..8f38df115 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -522,7 +522,7 @@ static int mobj_set(lua_State *L) mo->ceilingz = tm.ceilingz; mo->floorrover = tm.floorrover; mo->ceilingrover = tm.ceilingrover; - tm = ptm; + P_RestoreTMStruct(ptm); break; } case mobj_snext: @@ -592,7 +592,7 @@ static int mobj_set(lua_State *L) mo->ceilingz = tm.ceilingz; mo->floorrover = tm.floorrover; mo->ceilingrover = tm.ceilingrover; - tm = ptm; + P_RestoreTMStruct(ptm); break; } case mobj_height: @@ -606,7 +606,7 @@ static int mobj_set(lua_State *L) mo->ceilingz = tm.ceilingz; mo->floorrover = tm.floorrover; mo->ceilingrover = tm.ceilingrover; - tm = ptm; + P_RestoreTMStruct(ptm); break; } case mobj_momx: diff --git a/src/p_local.h b/src/p_local.h index 79fb6f3e2..61a836c09 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -415,6 +415,8 @@ typedef struct tm_s extern tm_t tm; +void P_RestoreTMStruct(tm_t tmrestore); + extern camera_t *mapcampointer; /* cphipps 2004/08/30 */ diff --git a/src/p_map.c b/src/p_map.c index 3d47f2433..13a814dda 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -46,6 +46,45 @@ tm_t tm = {0}; +void P_RestoreTMStruct(tm_t tmrestore) +{ + // Reference count management + if (tm.thing != tmrestore.thing) + { + P_SetTarget(&tm.thing, NULL); + } + + if (tm.floorthing != tmrestore.floorthing) + { + P_SetTarget(&tm.floorthing, NULL); + } + + if (tm.hitthing != tmrestore.hitthing) + { + P_SetTarget(&tm.hitthing, NULL); + } + + // Restore state + tm = tmrestore; + + // Validation + if (tm.thing && P_MobjWasRemoved(tm.thing) == true) + { + P_SetTarget(&tm.thing, NULL); + } + + if (tm.floorthing && P_MobjWasRemoved(tm.floorthing) == true) + { + P_SetTarget(&tm.floorthing, NULL); + } + + if (tm.hitthing && P_MobjWasRemoved(tm.hitthing) == true) + { + P_SetTarget(&tm.hitthing, NULL); + } +} + + // Mostly re-ported from DOOM Legacy // Keep track of special lines as they are hit, process them when the move is valid static size_t *spechit = NULL; @@ -2463,7 +2502,7 @@ BlockItReturn_t PIT_PushableMoved(mobj_t *thing) P_TryMove(thing, thing->x + stand->momx, thing->y + stand->momy, true); // Now restore EVERYTHING so the gargoyle doesn't keep the player's tmstuff and break - tm = oldtm; + P_RestoreTMStruct(oldtm); thing->momz = stand->momz; } @@ -4880,7 +4919,7 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y) * OTOH for Boom/MBF demos we have to preserve the buggy behavior. * Fun. We restore its previous value unless we're in a Boom/MBF demo. */ - tm = ptm; + P_RestoreTMStruct(ptm); } // More crazy crap Tails 08-25-2002 @@ -4947,7 +4986,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y) * OTOH for Boom/MBF demos we have to preserve the buggy behavior. * Fun. We restore its previous value unless we're in a Boom/MBF demo. */ - tm = ptm; + P_RestoreTMStruct(ptm); } /* cphipps 2004/08/30 - From 8f5e0f63e9d2b71cff049d151cbe422925da9fa1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 20 Nov 2022 21:36:00 -0500 Subject: [PATCH 43/67] Evict the wall gremlin Gremlins happened whenever P_TryMove and P_SlideMove/P_BounceMove disagreed on what an object collided with. When TryMove said you collided with a line, but P_BounceMove said that you didn't, then you'd get gremlin'd. To fix this, P_TryMove now can edit a struct to contain information on what it collides with. P_SlideMove and P_BounceMove no longer try to detect walls on their own and now requires this result from P_TryMove. If a slide/bounce is needed without moving the object, then you'd want to use P_CheckMove to get the result. Lua is not supported right now. --- src/g_game.c | 2 +- src/lua_baselib.c | 20 +- src/lua_mobjlib.c | 6 +- src/objects/orbinaut.c | 4 +- src/p_enemy.c | 42 ++-- src/p_local.h | 20 +- src/p_map.c | 486 ++++++++++++----------------------------- src/p_maputl.h | 1 - src/p_mobj.c | 48 ++-- src/p_polyobj.c | 4 +- 10 files changed, 222 insertions(+), 411 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index db838ab91..9472c400f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2549,7 +2549,7 @@ static boolean G_CheckSpot(INT32 playernum, mapthing_t *mthing) if (!K_CheckPlayersRespawnColliding(playernum, x, y)) return false; - if (!P_CheckPosition(players[playernum].mo, x, y)) + if (!P_CheckPosition(players[playernum].mo, x, y, NULL)) return false; return true; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 5120223cc..82f78c711 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1062,7 +1062,7 @@ static int lib_pZMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_ZMovement(actor)); - P_CheckPosition(actor, actor->x, actor->y); + P_CheckPosition(actor, actor->x, actor->y, NULL); P_RestoreTMStruct(ptm); return 1; } @@ -1076,7 +1076,7 @@ static int lib_pRingZMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_RingZMovement(actor); - P_CheckPosition(actor, actor->x, actor->y); + P_CheckPosition(actor, actor->x, actor->y, NULL); P_RestoreTMStruct(ptm); return 0; } @@ -1090,7 +1090,7 @@ static int lib_pSceneryZMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SceneryZMovement(actor)); - P_CheckPosition(actor, actor->x, actor->y); + P_CheckPosition(actor, actor->x, actor->y, NULL); P_RestoreTMStruct(ptm); return 1; } @@ -1104,7 +1104,7 @@ static int lib_pPlayerZMovement(lua_State *L) if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_PlayerZMovement(actor); - P_CheckPosition(actor, actor->x, actor->y); + P_CheckPosition(actor, actor->x, actor->y, NULL); P_RestoreTMStruct(ptm); return 0; } @@ -1393,7 +1393,7 @@ static int lib_pCheckPosition(lua_State *L) INLEVEL if (!thing) return LUA_ErrInvalid(L, "mobj_t"); - lua_pushboolean(L, P_CheckPosition(thing, x, y)); + lua_pushboolean(L, P_CheckPosition(thing, x, y, NULL)); LUA_PushUserdata(L, tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; @@ -1410,7 +1410,7 @@ static int lib_pTryMove(lua_State *L) INLEVEL if (!thing) return LUA_ErrInvalid(L, "mobj_t"); - lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff)); + lua_pushboolean(L, P_TryMove(thing, x, y, allowdropoff, NULL)); LUA_PushUserdata(L, tm.thing, META_MOBJ); P_RestoreTMStruct(ptm); return 2; @@ -1525,23 +1525,31 @@ static int lib_pSetRoll(lua_State *L) static int lib_pSlideMove(lua_State *L) { + /* mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); NOHUD INLEVEL if (!mo) return LUA_ErrInvalid(L, "mobj_t"); P_SlideMove(mo); + */ + LUA_UsageWarning(L, "FIXME: P_SlideMove needs updated to use result from P_TryMove"); + (void)L; return 0; } static int lib_pBounceMove(lua_State *L) { + /* mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); NOHUD INLEVEL if (!mo) return LUA_ErrInvalid(L, "mobj_t"); P_BounceMove(mo); + */ + LUA_UsageWarning(L, "FIXME: P_BounceMove needs updated to use result from P_TryMove"); + (void)L; return 0; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 8f38df115..b87ad7234 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -517,7 +517,7 @@ static int mobj_set(lua_State *L) // z doesn't cross sector bounds so it's okay. tm_t ptm = tm; mo->z = luaL_checkfixed(L, 3); - P_CheckPosition(mo, mo->x, mo->y); + P_CheckPosition(mo, mo->x, mo->y, NULL); mo->floorz = tm.floorz; mo->ceilingz = tm.ceilingz; mo->floorrover = tm.floorrover; @@ -587,7 +587,7 @@ static int mobj_set(lua_State *L) mo->radius = luaL_checkfixed(L, 3); if (mo->radius < 0) mo->radius = 0; - P_CheckPosition(mo, mo->x, mo->y); + P_CheckPosition(mo, mo->x, mo->y, NULL); mo->floorz = tm.floorz; mo->ceilingz = tm.ceilingz; mo->floorrover = tm.floorrover; @@ -601,7 +601,7 @@ static int mobj_set(lua_State *L) mo->height = luaL_checkfixed(L, 3); if (mo->height < 0) mo->height = 0; - P_CheckPosition(mo, mo->x, mo->y); + P_CheckPosition(mo, mo->x, mo->y, NULL); mo->floorz = tm.floorz; mo->ceilingz = tm.ceilingz; mo->floorrover = tm.floorrover; diff --git a/src/objects/orbinaut.c b/src/objects/orbinaut.c index ee6e72ed5..b4daefb9b 100644 --- a/src/objects/orbinaut.c +++ b/src/objects/orbinaut.c @@ -358,9 +358,9 @@ void Obj_OrbinautJawzMoveHeld(player_t *player) cur->momy = FixedMul(FINESINE(cur->angle >> ANGLETOFINESHIFT), orbinaut_shield_dist(cur)); cur->flags &= ~MF_NOCLIPTHING; - if (!P_TryMove(cur, player->mo->x + cur->momx, player->mo->y + cur->momy, true)) + if (!P_TryMove(cur, player->mo->x + cur->momx, player->mo->y + cur->momy, true, NULL)) { - P_SlideMove(cur); + P_SlideMove(cur, NULL); } if (P_IsObjectOnGround(player->mo)) diff --git a/src/p_enemy.c b/src/p_enemy.c index eb2098280..3b8ebb9ce 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -541,7 +541,7 @@ boolean P_Move(mobj_t *actor, fixed_t speed) if (actor->type == MT_SKIM && !P_WaterInSector(actor, tryx, tryy)) // bail out if sector lacks water return false; - if (!P_TryMove(actor, tryx, tryy, false)) + if (!P_TryMove(actor, tryx, tryy, false, NULL)) { if (actor->flags & MF_FLOAT && tm.floatok) { @@ -1074,7 +1074,7 @@ void A_FaceStabRev(mobj_t *actor) } else { - P_TryMove(actor, actor->x - P_ReturnThrustX(actor, actor->angle, 2<y - P_ReturnThrustY(actor, actor->angle, 2<x - P_ReturnThrustX(actor, actor->angle, 2<y - P_ReturnThrustY(actor, actor->angle, 2<x + P_ReturnThrustX(actor, dirang, actor->extravalue2<y + P_ReturnThrustY(actor, dirang, actor->extravalue2<extravalue2 <= 0 || !P_TryMove(actor, actor->x + P_ReturnThrustX(actor, actor->angle, actor->extravalue2<y + P_ReturnThrustY(actor, actor->angle, actor->extravalue2<extravalue2 = 0; P_SetMobjState(actor, locvar2); @@ -1821,7 +1821,7 @@ void A_CrushstaceanWalk(mobj_t *actor) if (!P_TryMove(actor, actor->x + P_ReturnThrustX(actor, ang, locvar1*actor->scale), actor->y + P_ReturnThrustY(actor, ang, locvar1*actor->scale), - false) + false, NULL) || (actor->reactiontime-- <= 0)) { actor->flags2 ^= MF2_AMBUSH; @@ -2000,7 +2000,7 @@ void A_CrushclawLaunch(mobj_t *actor) if (!P_TryMove(actor, actor->target->x + P_ReturnThrustX(actor, actor->target->angle, actor->extravalue2*actor->scale), actor->target->y + P_ReturnThrustY(actor, actor->target->angle, actor->extravalue2*actor->scale), - true) + true, NULL) && !locvar1) { actor->extravalue1 = 0; @@ -2946,9 +2946,9 @@ void A_Boss1Laser(mobj_t *actor) { fixed_t distx = P_ReturnThrustX(point, point->angle, point->radius); fixed_t disty = P_ReturnThrustY(point, point->angle, point->radius); - if (P_TryMove(point, point->x + distx, point->y + disty, false) // prevents the sprite from clipping into the wall or dangling off ledges - && P_TryMove(point, point->x - 2*distx, point->y - 2*disty, false) - && P_TryMove(point, point->x + distx, point->y + disty, false)) + if (P_TryMove(point, point->x + distx, point->y + disty, false, NULL) // prevents the sprite from clipping into the wall or dangling off ledges + && P_TryMove(point, point->x - 2*distx, point->y - 2*disty, false, NULL) + && P_TryMove(point, point->x + distx, point->y + disty, false, NULL)) { if (point->info->seesound) S_StartSound(point, point->info->seesound); @@ -3012,7 +3012,7 @@ void A_FocusTarget(mobj_t *actor) { actor->momx = 0, actor->momy = 0, actor->momz = 0; actor->z = actor->target->z + (actor->target->height>>1); - P_TryMove(actor, actor->target->x, actor->target->y, true); + P_TryMove(actor, actor->target->x, actor->target->y, true, NULL); } break; default: @@ -3168,7 +3168,7 @@ void A_SkullAttack(mobj_t *actor) if (P_CheckMove(actor,\ P_ReturnThrustX(actor, testang, dist + 2*actor->radius),\ P_ReturnThrustY(actor, testang, dist + 2*actor->radius),\ - true)) break; + true, NULL)) break; if (P_RandomChance(PR_UNDEFINED, FRACUNIT/2)) // port priority 2? { @@ -4483,13 +4483,13 @@ void A_MinusDigging(mobj_t *actor) par = P_SpawnMobj(actor->x, actor->y, mz, MT_MINUSDIRT); if (actor->eflags & MFE_VERTICALFLIP) par->eflags |= MFE_VERTICALFLIP; - P_TryMove(par, x, y, false); + P_TryMove(par, x, y, false, NULL); // If close enough, prepare to attack if (P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) < actor->radius*2) { P_SetMobjState(actor, actor->info->meleestate); - P_TryMove(actor, actor->target->x, actor->target->y, false); + P_TryMove(actor, actor->target->x, actor->target->y, false, NULL); S_StartSound(actor, actor->info->attacksound); // Spawn growing dirt pile. @@ -4532,7 +4532,7 @@ void A_MinusDigging(mobj_t *actor) } else { - if (P_TryMove(actor->tracer, actor->x, actor->y, false)) + if (P_TryMove(actor->tracer, actor->x, actor->y, false, NULL)) actor->tracer->z = mz; else P_SetTarget(&actor->tracer, NULL); @@ -5702,7 +5702,7 @@ void A_MixUp(mobj_t *actor) players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL); - P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y); + P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y, NULL); } } } @@ -6470,7 +6470,7 @@ void A_GuardChase(mobj_t *actor) && !P_TryMove(actor, actor->x + P_ReturnThrustX(actor, actor->angle, speed), actor->y + P_ReturnThrustY(actor, actor->angle, speed), - false) + false, NULL) && speed > 0) // can't be the same check as previous so that P_TryMove gets to happen. { INT32 direction = actor->spawnpoint ? actor->spawnpoint->args[0] : TMGD_BACK; @@ -9273,7 +9273,7 @@ void A_SpikeRetract(mobj_t *actor) actor->flags &= ~MF_NOCLIPTHING; } if (actor->flags & MF_SOLID) - P_CheckPosition(actor, actor->x, actor->y); + P_CheckPosition(actor, actor->x, actor->y, NULL); } // Function: A_InfoState @@ -11511,7 +11511,7 @@ void A_DoNPCSkid(mobj_t *actor) locvar2 = FRACUNIT/2; if ((FixedHypot(actor->momx, actor->momy) < locvar2) - || !P_TryMove(actor, actor->x + actor->momx, actor->y + actor->momy, false)) + || !P_TryMove(actor, actor->x + actor->momx, actor->y + actor->momy, false, NULL)) { actor->momx = actor->momy = 0; P_SetMobjState(actor, locvar1); @@ -12286,7 +12286,7 @@ static void P_SnapperLegPlace(mobj_t *mo) INT32 necklen = (32*(mo->info->reactiontime - mo->reactiontime))/mo->info->reactiontime; // Not in FU seg->z = mo->z + ((mo->eflags & MFE_VERTICALFLIP) ? (((mo->height<<1)/3) - seg->height) : mo->height/3); - P_TryMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, true); + P_TryMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, true, NULL); seg->angle = a; // Move as many legs as available. @@ -12307,7 +12307,7 @@ static void P_SnapperLegPlace(mobj_t *mo) x = c*o2 + s*o1; y = s*o2 - c*o1; seg->z = mo->z + (((mo->eflags & MFE_VERTICALFLIP) ? (mo->height - seg->height) : 0)); - P_TryMove(seg, mo->x + x, mo->y + y, true); + P_TryMove(seg, mo->x + x, mo->y + y, true, NULL); P_SetMobjState(seg, seg->info->raisestate); } else @@ -12442,7 +12442,7 @@ void A_SnapperThinker(mobj_t *actor) c = FINECOSINE(fa); s = FINESINE(fa); - P_TryMove(actor, actor->x + c*speed, actor->y + s*speed, false); + P_TryMove(actor, actor->x + c*speed, actor->y + s*speed, false, NULL); // The snapper spawns dust if going fast! if (actor->reactiontime < 4) diff --git a/src/p_local.h b/src/p_local.h index 61a836c09..1042f1193 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -431,20 +431,28 @@ void P_UnsetThingPosition(mobj_t *thing); void P_SetThingPosition(mobj_t *thing); void P_SetUnderlayPosition(mobj_t *thing); +typedef struct TryMoveResult_s +{ + boolean success; + line_t *line; + mobj_t *mo; +} TryMoveResult_t; + +boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *result); +boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, TryMoveResult_t *result); +boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, TryMoveResult_t *result); +boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *result); + boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing); boolean P_IsLineTripWire(const line_t *ld); -boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y); boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam); -boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); fixed_t P_BaseStepUp(void); fixed_t P_GetThingStepUp(mobj_t *thing, fixed_t destX, fixed_t destY); -boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_Move(mobj_t *actor, fixed_t speed); boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); -void P_SlideMove(mobj_t *mo); -void P_BouncePlayerMove(mobj_t *mo); -void P_BounceMove(mobj_t *mo); +void P_SlideMove(mobj_t *mo, TryMoveResult_t *result); +void P_BounceMove(mobj_t *mo, TryMoveResult_t *result); boolean P_CheckSight(mobj_t *t1, mobj_t *t2); boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2); boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2); diff --git a/src/p_map.c b/src/p_map.c index 13a814dda..0e1f5fbc1 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -131,7 +131,7 @@ static boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) P_SetThingPosition(thing); - P_CheckPosition(thing, thing->x, thing->y); + P_CheckPosition(thing, thing->x, thing->y, NULL); if (P_MobjWasRemoved(thing)) return true; @@ -302,7 +302,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (horizspeed && vertispeed) // Mimic SA { object->momx = object->momy = 0; - P_TryMove(object, spring->x, spring->y, true); + P_TryMove(object, spring->x, spring->y, true, NULL); } #endif @@ -352,7 +352,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) else if (offx < -(spring->radius + object->radius + 1)) offx = -(spring->radius + object->radius + 1); - P_TryMove(object, spring->x + offx, spring->y + offy, true); + P_TryMove(object, spring->x + offx, spring->y + offy, true, NULL); } if (vertispeed) @@ -1838,7 +1838,7 @@ static BlockItReturn_t PIT_CheckLine(line_t *ld) // tm.ceilingz // the nearest ceiling or thing's bottom over tm.thing // -boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) +boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *result) { INT32 thingtop = thing->z + thing->height; INT32 xl, xh, yl, yh, bx, by; @@ -2108,6 +2108,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) if (!(thing->flags & MF_NOCLIPTHING)) { for (bx = xl; bx <= xh; bx++) + { for (by = yl; by <= yh; by++) { if (!P_BlockThingsIterator(bx, by, PIT_CheckThing)) @@ -2120,8 +2121,11 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) } if (P_MobjWasRemoved(tm.thing)) + { return false; + } } + } } validcount++; @@ -2138,6 +2142,12 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) } } + if (result != NULL) + { + result->line = tm.blockingline; + P_SetTarget(&result->mo, tm.hitthing); + } + return blockval; } @@ -2499,7 +2509,7 @@ BlockItReturn_t PIT_PushableMoved(mobj_t *thing) tm_t oldtm = tm; // Move the player - P_TryMove(thing, thing->x + stand->momx, thing->y + stand->momy, true); + P_TryMove(thing, thing->x + stand->momx, thing->y + stand->momy, true, NULL); // Now restore EVERYTHING so the gargoyle doesn't keep the player's tmstuff and break P_RestoreTMStruct(oldtm); @@ -2565,7 +2575,8 @@ increment_move fixed_t x, fixed_t y, boolean allowdropoff, - fixed_t * return_stairjank) + fixed_t * return_stairjank, + TryMoveResult_t * result) { fixed_t tryx = thing->x; fixed_t tryy = thing->y; @@ -2607,15 +2618,17 @@ increment_move tryy = y; } - if (!P_CheckPosition(thing, tryx, tryy)) + if (!P_CheckPosition(thing, tryx, tryy, result)) + { return false; // solid wall or thing + } // copy into the spechitint buffer from spechit spechitint_copyinto(); if (!(thing->flags & MF_NOCLIP)) { - //All things are affected by their scale. + // All things are affected by their scale. fixed_t maxstep = P_GetThingStepUp(thing, tryx, tryy); if (tm.ceilingz - tm.floorz < thing->height) @@ -2714,7 +2727,9 @@ increment_move } while (tryx != x || tryy != y); if (return_stairjank) + { *return_stairjank = stairjank; + } return true; } @@ -2723,7 +2738,7 @@ increment_move // P_CheckMove // Check if a P_TryMove would be successful. // -boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, TryMoveResult_t *result) { boolean moveok = false; mobj_t *hack = P_SpawnMobjFromMobj(thing, 0, 0, 0, MT_RAY); @@ -2731,7 +2746,7 @@ boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) hack->radius = thing->radius; hack->height = thing->height; - moveok = increment_move(hack, x, y, allowdropoff, NULL); + moveok = increment_move(hack, x, y, allowdropoff, NULL, result); P_RemoveMobj(hack); return moveok; @@ -2741,7 +2756,7 @@ boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) // P_TryMove // Attempt to move to a new position. // -boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, TryMoveResult_t *result) { fixed_t oldx = thing->x; fixed_t oldy = thing->y; @@ -2750,8 +2765,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) pslope_t *oldslope = thing->standingslope; // Is the move OK? - if (increment_move(thing, x, y, allowdropoff, &stairjank) == false) + if (increment_move(thing, x, y, allowdropoff, &stairjank, result) == false) { + if (result != NULL) + { + result->success = false; + } return false; } @@ -2899,10 +2918,15 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } } + if (result != NULL) + { + result->success = true; + } + return true; } -boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) +boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *result) { fixed_t tryx, tryy; @@ -2922,7 +2946,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) else tryy = y; - if (!P_CheckPosition(thing, tryx, tryy)) + if (!P_CheckPosition(thing, tryx, tryy, result)) return false; // solid wall or thing if (!(thing->flags & MF_NOCLIP)) @@ -3074,7 +3098,7 @@ static boolean P_ThingHeightClip(mobj_t *thing) if (thing->flags & MF_NOCLIPHEIGHT) return true; - P_CheckPosition(thing, thing->x, thing->y); + P_CheckPosition(thing, thing->x, thing->y, NULL); if (P_MobjWasRemoved(thing)) return true; @@ -3202,42 +3226,25 @@ static void P_HitCameraSlideLine(line_t *ld, camera_t *thiscam) static void P_HitSlideLine(line_t *ld) { INT32 side; - angle_t lineangle, moveangle, deltaangle; - fixed_t movelen, newlen; - - if (ld->slopetype == ST_HORIZONTAL) - { - tmymove = 0; - return; - } - - if (ld->slopetype == ST_VERTICAL) - { - tmxmove = 0; - return; - } + angle_t lineangle; + fixed_t nx, ny; + fixed_t d; side = P_PointOnLineSide(slidemo->x, slidemo->y, ld); - - lineangle = ld->angle; + lineangle = ld->angle - ANGLE_90; if (side == 1) lineangle += ANGLE_180; - moveangle = R_PointToAngle2(0, 0, tmxmove, tmymove); - deltaangle = moveangle-lineangle; - - if (deltaangle > ANGLE_180) - deltaangle += ANGLE_180; - lineangle >>= ANGLETOFINESHIFT; - deltaangle >>= ANGLETOFINESHIFT; - movelen = R_PointToDist2(0, 0, tmxmove, tmymove); - newlen = FixedMul(movelen, FINECOSINE(deltaangle)); + nx = FINECOSINE(lineangle); + ny = FINESINE(lineangle); - tmxmove = FixedMul(newlen, FINECOSINE(lineangle)); - tmymove = FixedMul(newlen, FINESINE(lineangle)); + d = FixedMul(tmxmove, nx) + FixedMul(tmymove, ny); + + tmxmove -= FixedMul(nx, d); + tmymove -= FixedMul(ny, d); } // @@ -3371,6 +3378,7 @@ isblocking: return false; // stop } +/* static boolean PTR_LineIsBlocking(line_t *li) { // one-sided linedefs are always solid to sliding movement. @@ -3394,7 +3402,9 @@ static boolean PTR_LineIsBlocking(line_t *li) return false; } +*/ +/* static boolean PTR_SlideTraverse(intercept_t *in) { line_t *li; @@ -3424,6 +3434,7 @@ static boolean PTR_SlideTraverse(intercept_t *in) return false; // stop } +*/ // // P_SlideCameraMove @@ -3580,186 +3591,85 @@ static void P_CheckLavaWall(mobj_t *mo, sector_t *sec) // // This is a kludgy mess. // -void P_SlideMove(mobj_t *mo) +void P_SlideMove(mobj_t *mo, TryMoveResult_t *result) { - fixed_t leadx, leady, trailx, traily, newx, newy; - INT16 hitcount = 0; + fixed_t newx, newy; boolean success = false; - boolean papercol = false; vertex_t v1, v2; // fake vertexes line_t junk; // fake linedef if (P_MobjWasRemoved(mo)) return; - if (tm.hitthing && mo->z + mo->height > tm.hitthing->z && mo->z < tm.hitthing->z + tm.hitthing->height) + if (result == NULL) + return; + + if (result->mo && mo->z + mo->height > result->mo->z && mo->z < result->mo->z + result->mo->height) { // Don't mess with your momentum if it's a pushable object. Pushables do their own crazy things already. - if (tm.hitthing->flags & MF_PUSHABLE) + if (result->mo->flags & MF_PUSHABLE) return; - if (tm.hitthing->flags & MF_PAPERCOLLISION) + if (result->mo->flags & MF_PAPERCOLLISION) { - fixed_t cosradius, sinradius, num, den; + fixed_t cosradius, sinradius; - // trace along the three leading corners - if (mo->momx > 0) - { - leadx = mo->x + mo->radius; - trailx = mo->x - mo->radius; - } - else - { - leadx = mo->x - mo->radius; - trailx = mo->x + mo->radius; - } - - if (mo->momy > 0) - { - leady = mo->y + mo->radius; - traily = mo->y - mo->radius; - } - else - { - leady = mo->y - mo->radius; - traily = mo->y + mo->radius; - } - - papercol = true; slidemo = mo; bestslideline = &junk; - cosradius = FixedMul(tm.hitthing->radius, FINECOSINE(tm.hitthing->angle>>ANGLETOFINESHIFT)); - sinradius = FixedMul(tm.hitthing->radius, FINESINE(tm.hitthing->angle>>ANGLETOFINESHIFT)); + cosradius = FixedMul(result->mo->radius, FINECOSINE(result->mo->angle>>ANGLETOFINESHIFT)); + sinradius = FixedMul(result->mo->radius, FINESINE(result->mo->angle>>ANGLETOFINESHIFT)); - v1.x = tm.hitthing->x - cosradius; - v1.y = tm.hitthing->y - sinradius; - v2.x = tm.hitthing->x + cosradius; - v2.y = tm.hitthing->y + sinradius; + v1.x = result->mo->x - cosradius; + v1.y = result->mo->y - sinradius; + v2.x = result->mo->x + cosradius; + v2.y = result->mo->y + sinradius; - // Can we box collision our way into smooth movement..? - if (sinradius && mo->y + mo->radius <= min(v1.y, v2.y)) - { - mo->momy = 0; - P_TryMove(mo, mo->x + mo->momx, min(v1.y, v2.y) - mo->radius, true); - return; - } - else if (sinradius && mo->y - mo->radius >= max(v1.y, v2.y)) - { - mo->momy = 0; - P_TryMove(mo, mo->x + mo->momx, max(v1.y, v2.y) + mo->radius, true); - return; - } - else if (cosradius && mo->x + mo->radius <= min(v1.x, v2.x)) - { - mo->momx = 0; - P_TryMove(mo, min(v1.x, v2.x) - mo->radius, mo->y + mo->momy, true); - return; - } - else if (cosradius && mo->x - mo->radius >= max(v1.x, v2.x)) - { - mo->momx = 0; - P_TryMove(mo, max(v1.x, v2.x) + mo->radius, mo->y + mo->momy, true); - return; - } - - // nope, gotta fuck around with a fake linedef! + // gotta fuck around with a fake linedef! junk.v1 = &v1; junk.v2 = &v2; junk.dx = 2*cosradius; // v2.x - v1.x; junk.dy = 2*sinradius; // v2.y - v1.y; junk.slopetype = !cosradius ? ST_VERTICAL : !sinradius ? ST_HORIZONTAL : - ((sinradius > 0) == (cosradius > 0)) ? ST_POSITIVE : ST_NEGATIVE; - - bestslidefrac = FRACUNIT+1; - - den = FixedMul(junk.dy>>8, mo->momx) - FixedMul(junk.dx>>8, mo->momy); - - if (!den) - bestslidefrac = 0; - else - { - fixed_t frac; -#define P_PaperTraverse(startx, starty) \ - num = FixedMul((v1.x - leadx)>>8, junk.dy) + FixedMul((leady - v1.y)>>8, junk.dx); \ - frac = FixedDiv(num, den); \ - if (frac < bestslidefrac) \ - bestslidefrac = frac - P_PaperTraverse(leadx, leady); - P_PaperTraverse(trailx, leady); - P_PaperTraverse(leadx, traily); -#undef dowork - } + ((sinradius > 0) == (cosradius > 0)) ? ST_POSITIVE : ST_NEGATIVE; goto papercollision; } // Thankfully box collisions are a lot simpler than arbitrary lines. There's only four possible cases. - if (mo->y + mo->radius <= tm.hitthing->y - tm.hitthing->radius) + if (mo->y + mo->radius <= result->mo->y - result->mo->radius) { mo->momy = 0; - P_TryMove(mo, mo->x + mo->momx, tm.hitthing->y - tm.hitthing->radius - mo->radius, true); + P_TryMove(mo, mo->x + mo->momx, result->mo->y - result->mo->radius - mo->radius, true, NULL); } - else if (mo->y - mo->radius >= tm.hitthing->y + tm.hitthing->radius) + else if (mo->y - mo->radius >= result->mo->y + result->mo->radius) { mo->momy = 0; - P_TryMove(mo, mo->x + mo->momx, tm.hitthing->y + tm.hitthing->radius + mo->radius, true); + P_TryMove(mo, mo->x + mo->momx, result->mo->y + result->mo->radius + mo->radius, true, NULL); } - else if (mo->x + mo->radius <= tm.hitthing->x - tm.hitthing->radius) + else if (mo->x + mo->radius <= result->mo->x - result->mo->radius) { mo->momx = 0; - P_TryMove(mo, tm.hitthing->x - tm.hitthing->radius - mo->radius, mo->y + mo->momy, true); + P_TryMove(mo, result->mo->x - result->mo->radius - mo->radius, mo->y + mo->momy, true, NULL); } - else if (mo->x - mo->radius >= tm.hitthing->x + tm.hitthing->radius) + else if (mo->x - mo->radius >= result->mo->x + result->mo->radius) { mo->momx = 0; - P_TryMove(mo, tm.hitthing->x + tm.hitthing->radius + mo->radius, mo->y + mo->momy, true); + P_TryMove(mo, result->mo->x + result->mo->radius + mo->radius, mo->y + mo->momy, true, NULL); } else mo->momx = mo->momy = 0; + return; } slidemo = mo; - bestslideline = NULL; + bestslideline = result->line; -retry: - if ((++hitcount == 3) || papercol) - goto stairstep; // don't loop forever - - // trace along the three leading corners - if (mo->momx > 0) - { - leadx = mo->x + mo->radius; - trailx = mo->x - mo->radius; - } - else - { - leadx = mo->x - mo->radius; - trailx = mo->x + mo->radius; - } - - if (mo->momy > 0) - { - leady = mo->y + mo->radius; - traily = mo->y - mo->radius; - } - else - { - leady = mo->y - mo->radius; - traily = mo->y + mo->radius; - } - - bestslidefrac = FRACUNIT+1; - - P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy, - PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy, - PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy, - PT_ADDLINES, PTR_SlideTraverse); + if (bestslideline == NULL) + return; if (bestslideline && mo->player && bestslideline->sidenum[1] != 0xffff) { @@ -3768,39 +3678,8 @@ retry: } papercollision: - // move up to the wall - if (bestslidefrac == FRACUNIT+1) - { - // the move must have hit the middle, so stairstep -stairstep: - if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true)) //Allow things to drop off. - P_TryMove(mo, mo->x + mo->momx, mo->y, true); - return; - } - - // fudge a bit to make sure it doesn't hit - bestslidefrac -= 0x800; - if (bestslidefrac > 0) - { - newx = FixedMul(mo->momx, bestslidefrac); - newy = FixedMul(mo->momy, bestslidefrac); - - if (!P_TryMove(mo, mo->x + newx, mo->y + newy, true)) - goto stairstep; - } - - // Now continue along the wall. - // First calculate remainder. - bestslidefrac = FRACUNIT - (bestslidefrac+0x800); - - if (bestslidefrac > FRACUNIT) - bestslidefrac = FRACUNIT; - - if (bestslidefrac <= 0) - return; - - tmxmove = FixedMul(mo->momx, bestslidefrac); - tmymove = FixedMul(mo->momy, bestslidefrac); + tmxmove = mo->momx; + tmymove = mo->momy; P_HitSlideLine(bestslideline); // clip the moves @@ -3808,31 +3687,47 @@ stairstep: mo->momy = tmymove; do { - if (tmxmove > mo->radius) { + if (tmxmove > mo->radius) + { newx = mo->x + mo->radius; tmxmove -= mo->radius; - } else if (tmxmove < -mo->radius) { + } + else if (tmxmove < -mo->radius) + { newx = mo->x - mo->radius; tmxmove += mo->radius; - } else { + } + else + { newx = mo->x + tmxmove; tmxmove = 0; } - if (tmymove > mo->radius) { + + if (tmymove > mo->radius) + { newy = mo->y + mo->radius; tmymove -= mo->radius; - } else if (tmymove < -mo->radius) { + } + else if (tmymove < -mo->radius) + { newy = mo->y - mo->radius; tmymove += mo->radius; - } else { + } + else + { newy = mo->y + tmymove; tmymove = 0; } - if (!P_TryMove(mo, newx, newy, true)) { - if (success || P_MobjWasRemoved(mo)) + + if (!P_TryMove(mo, newx, newy, true, NULL)) + { + if (success || P_MobjWasRemoved(mo)) return; // Good enough!! - else - goto retry; + + // the move must have hit the middle, so stairstep + if (!P_TryMove(mo, mo->x, mo->y + mo->momy, true, NULL)) // Allow things to drop off. + P_TryMove(mo, mo->x + mo->momx, mo->y, true, NULL); + return; } success = true; } while(tmxmove || tmymove); @@ -3844,64 +3739,33 @@ stairstep: // Bounce move, for players. // -void P_BouncePlayerMove(mobj_t *mo) +static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result) { - fixed_t leadx, leady; - fixed_t trailx, traily; fixed_t mmomx = 0, mmomy = 0; fixed_t oldmomx = mo->momx, oldmomy = mo->momy; - if (!mo->player) + if (P_MobjWasRemoved(mo) == true) + return; + + if (mo->player == NULL) + return; + + if (result == NULL) return; if (mo->player->spectator) { - P_SlideMove(mo); + P_SlideMove(mo, result); return; } - slidemo = mo; - mmomx = mo->player->rmomx; mmomy = mo->player->rmomy; - // trace along the three leading corners - if (mo->momx > 0) - { - leadx = mo->x + mo->radius; - trailx = mo->x - mo->radius; - } - else - { - leadx = mo->x - mo->radius; - trailx = mo->x + mo->radius; - } + slidemo = mo; + bestslideline = result->line; - if (mo->momy > 0) - { - leady = mo->y + mo->radius; - traily = mo->y - mo->radius; - } - else - { - leady = mo->y - mo->radius; - traily = mo->y + mo->radius; - } - - bestslidefrac = FRACUNIT + 1; - - P_PathTraverse(leadx, leady, leadx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(trailx, leady, trailx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(leadx, traily, leadx + mmomx, traily + mmomy, PT_ADDLINES, PTR_SlideTraverse); - - // Now continue along the wall. - // First calculate remainder. - bestslidefrac = FRACUNIT - bestslidefrac; - - if (bestslidefrac > FRACUNIT) - bestslidefrac = FRACUNIT; - - if (bestslidefrac <= 0) + if (bestslideline == NULL) return; if (mo->eflags & MFE_JUSTBOUNCEDWALL) // Stronger push-out @@ -3926,7 +3790,7 @@ void P_BouncePlayerMove(mobj_t *mo) if (bestslideline && (bestslideline->flags & ML_NOTBOUNCY)) { // SRB2Kart: Non-bouncy line! - P_SlideMove(mo); + P_SlideMove(mo, result); return; } @@ -3943,8 +3807,9 @@ void P_BouncePlayerMove(mobj_t *mo) if (!P_IsLineTripWire(bestslideline)) { - if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true)) { - P_TryMove(mo, mo->x - oldmomx, mo->y - oldmomy, true); + if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true, NULL)) + { + P_TryMove(mo, mo->x - oldmomx, mo->y - oldmomy, true, NULL); } } } @@ -3954,12 +3819,8 @@ void P_BouncePlayerMove(mobj_t *mo) // // The momx / momy move is bad, so try to bounce off a wall. // -void P_BounceMove(mobj_t *mo) +void P_BounceMove(mobj_t *mo, TryMoveResult_t *result) { - fixed_t leadx, leady; - fixed_t trailx, traily; - fixed_t newx, newy; - INT32 hitcount; fixed_t mmomx = 0, mmomy = 0; if (P_MobjWasRemoved(mo)) @@ -3967,89 +3828,23 @@ void P_BounceMove(mobj_t *mo) if (mo->player) { - P_BouncePlayerMove(mo); + P_BouncePlayerMove(mo, result); return; } if (mo->eflags & MFE_JUSTBOUNCEDWALL) { - P_SlideMove(mo); + P_SlideMove(mo, result); return; } - slidemo = mo; - hitcount = 0; - -retry: - if (++hitcount == 3) - goto bounceback; // don't loop forever - mmomx = mo->momx; mmomy = mo->momy; - // trace along the three leading corners - if (mo->momx > 0) - { - leadx = mo->x + mo->radius; - trailx = mo->x - mo->radius; - } - else - { - leadx = mo->x - mo->radius; - trailx = mo->x + mo->radius; - } + slidemo = mo; + bestslideline = result->line; - if (mo->momy > 0) - { - leady = mo->y + mo->radius; - traily = mo->y - mo->radius; - } - else - { - leady = mo->y - mo->radius; - traily = mo->y + mo->radius; - } - - bestslidefrac = FRACUNIT + 1; - - P_PathTraverse(leadx, leady, leadx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(trailx, leady, trailx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse); - P_PathTraverse(leadx, traily, leadx + mmomx, traily + mmomy, PT_ADDLINES, PTR_SlideTraverse); - - // move up to the wall - if (bestslidefrac == FRACUNIT + 1) - { - // the move must have hit the middle, so bounce straight back -bounceback: - if (P_TryMove(mo, mo->x - mmomx, mo->y - mmomy, true)) - { - mo->momx *= -1; - mo->momy *= -1; - mo->momx = FixedMul(mo->momx, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); - mo->momy = FixedMul(mo->momy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); - } - return; - } - - // fudge a bit to make sure it doesn't hit - bestslidefrac -= 0x800; - if (bestslidefrac > 0) - { - newx = FixedMul(mmomx, bestslidefrac); - newy = FixedMul(mmomy, bestslidefrac); - - if (!P_TryMove(mo, mo->x + newx, mo->y + newy, true)) - goto bounceback; - } - - // Now continue along the wall. - // First calculate remainder. - bestslidefrac = FRACUNIT - bestslidefrac; - - if (bestslidefrac > FRACUNIT) - bestslidefrac = FRACUNIT; - - if (bestslidefrac <= 0) + if (bestslideline == NULL) return; if (mo->type == MT_SHELL) @@ -4074,24 +3869,21 @@ bounceback: tmymove = FixedMul(mmomy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); } - // Some walls aren't bouncy even if you are - if (bestslideline && (bestslideline->flags & ML_NOTBOUNCY)) - { - // SRB2Kart: Non-bouncy line! - P_SlideMove(mo); - return; - } - P_HitBounceLine(bestslideline); // clip the moves mo->momx = tmxmove; mo->momy = tmymove; - if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true)) + if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true, NULL)) { if (P_MobjWasRemoved(mo)) return; - goto retry; + + // the move must have hit the middle, so bounce straight back + mo->momx *= -1; + mo->momy *= -1; + mo->momx = FixedMul(mo->momx, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); + mo->momy = FixedMul(mo->momy, (FRACUNIT - (FRACUNIT>>2) - (FRACUNIT>>3))); } } diff --git a/src/p_maputl.h b/src/p_maputl.h index 7ac6baa3f..b53bddfd1 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -53,7 +53,6 @@ line_t * P_FindNearestLine(const fixed_t x, const fixed_t y, const sector_t *, c void P_UnsetPrecipThingPosition(precipmobj_t *thing); void P_SetPrecipitationThingPosition(precipmobj_t *thing); void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y); -boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y); void P_HitSpecialLines(mobj_t *thing, fixed_t x, fixed_t y, fixed_t momx, fixed_t momy); boolean P_GetMidtextureTopBottom(line_t *linedef, fixed_t x, fixed_t y, fixed_t *return_top, fixed_t *return_bottom); diff --git a/src/p_mobj.c b/src/p_mobj.c index 88d9c3994..eaa5b058c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1513,6 +1513,7 @@ void P_XYMovement(mobj_t *mo) pslope_t *oldslope = NULL; vector3_t slopemom = {0,0,0}; fixed_t predictedz = 0; + TryMoveResult_t result = {0}; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -1595,7 +1596,7 @@ void P_XYMovement(mobj_t *mo) } //} - if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) + if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true, &result) && !(P_MobjWasRemoved(mo) || mo->eflags & MFE_SPRUNG)) { // blocked move @@ -1691,7 +1692,7 @@ void P_XYMovement(mobj_t *mo) walltransferred = true; - P_SlideMove(mo); + P_SlideMove(mo, &result); xmove = ymove = 0; @@ -1726,14 +1727,14 @@ void P_XYMovement(mobj_t *mo) } else if (mo->flags & MF_SLIDEME) { - P_SlideMove(mo); + P_SlideMove(mo, &result); if (P_MobjWasRemoved(mo)) return; xmove = ymove = 0; } else { - P_BounceMove(mo); + P_BounceMove(mo, &result); if (P_MobjWasRemoved(mo)) return; xmove = ymove = 0; @@ -1895,16 +1896,19 @@ void P_XYMovement(mobj_t *mo) void P_RingXYMovement(mobj_t *mo) { + TryMoveResult_t result = {0}; + I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); - if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy)) - P_BounceMove(mo); + if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy, &result)) + P_BounceMove(mo, &result); } void P_SceneryXYMovement(mobj_t *mo) { fixed_t oldx, oldy; // reducing bobbing/momentum on ice when up against walls + TryMoveResult_t result = {0}; I_Assert(mo != NULL); I_Assert(!P_MobjWasRemoved(mo)); @@ -1912,8 +1916,8 @@ void P_SceneryXYMovement(mobj_t *mo) oldx = mo->x; oldy = mo->y; - if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy)) - P_BounceMove(mo); + if (!P_SceneryTryMove(mo, mo->x + mo->momx, mo->y + mo->momy, &result)) + P_BounceMove(mo, &result); if (P_MobjWasRemoved(mo)) return; @@ -2367,7 +2371,7 @@ boolean P_ZMovement(mobj_t *mo) return true; } - P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly + P_CheckPosition(mo, mo->x, mo->y, NULL); // Sets mo->standingslope correctly if (P_MobjWasRemoved(mo)) // mobjs can be removed by P_CheckPosition -- Monster Iestyn 31/07/21 return false; @@ -2985,7 +2989,7 @@ boolean P_SceneryZMovement(mobj_t *mo) if (!(mo->flags & MF_SLIDEME) && (mo->z <= mo->floorz || mo->z+mo->height >= mo->ceilingz)) { // set standingslope - P_TryMove(mo, mo->x, mo->y, true); + P_TryMove(mo, mo->x, mo->y, true, NULL); mo->momz = -mo->momz; if (mo->standingslope) { @@ -3959,7 +3963,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) mobj->y += mobj->momy; mobj->z += mobj->momz; P_SetThingPosition(mobj); - P_CheckPosition(mobj, mobj->x, mobj->y); + P_CheckPosition(mobj, mobj->x, mobj->y, NULL); mobj->floorz = tm.floorz; mobj->ceilingz = tm.ceilingz; goto animonly; @@ -3976,7 +3980,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) return; } else - P_TryMove(mobj, mobj->x, mobj->y, true); + P_TryMove(mobj, mobj->x, mobj->y, true, NULL); P_CheckCrumblingPlatforms(mobj); @@ -3991,7 +3995,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) || P_IsObjectInGoop(mobj)) { P_PlayerZMovement(mobj); - P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! + P_CheckPosition(mobj, mobj->x, mobj->y, NULL); // Need this to pick up objects! if (P_MobjWasRemoved(mobj)) return; @@ -4181,7 +4185,7 @@ static void P_RingThinker(mobj_t *mobj) if (mobj->momz) { P_RingZMovement(mobj); - P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! + P_CheckPosition(mobj, mobj->x, mobj->y, NULL); // Need this to pick up objects! if (P_MobjWasRemoved(mobj)) return; @@ -5330,7 +5334,7 @@ void P_RunOverlays(void) P_SetUnderlayPosition(mo); else P_SetThingPosition(mo); - P_CheckPosition(mo, mo->x, mo->y); + P_CheckPosition(mo, mo->x, mo->y, NULL); } P_SetTarget(&overlaycap, NULL); } @@ -8408,7 +8412,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->movecount += mobj->lastlook; - if (!(P_TryMove(mobj->tracer, mobj->x + ((mobj->extravalue1<movecount), mobj->y + ((mobj->extravalue2<movecount), true)) + if (!(P_TryMove(mobj->tracer, mobj->x + ((mobj->extravalue1<movecount), mobj->y + ((mobj->extravalue2<movecount), true, NULL)) || (mobj->movecount >= 16) // maximum travel time || (mobj->tracer->z <= mobj->tracer->floorz) // Through the floor || ((mobj->tracer->z + mobj->tracer->height) >= mobj->tracer->ceilingz)) // Through the ceiling @@ -9609,7 +9613,7 @@ void P_MobjThinker(mobj_t *mobj) { if (!P_ZMovement(mobj)) return; // mobj was removed - P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! + P_CheckPosition(mobj, mobj->x, mobj->y, NULL); // Need this to pick up objects! if (P_MobjWasRemoved(mobj)) return; } @@ -9633,7 +9637,7 @@ void P_MobjThinker(mobj_t *mobj) || mobj->type == MT_JAWZ || (mobj->type == MT_DROPTARGET && mobj->reactiontime)) { - P_TryMove(mobj, mobj->x, mobj->y, true); // Sets mo->standingslope correctly + P_TryMove(mobj, mobj->x, mobj->y, true, NULL); // Sets mo->standingslope correctly if (P_MobjWasRemoved(mobj)) // anything that calls checkposition can be lethal return; @@ -9731,7 +9735,7 @@ boolean P_RailThinker(mobj_t *mobj) { if (!P_ZMovement(mobj)) return true; // mobj was removed - //P_CheckPosition(mobj, mobj->x, mobj->y); + //P_CheckPosition(mobj, mobj->x, mobj->y, NULL); } return P_MobjWasRemoved(mobj) || (x == mobj->x && y == mobj->y && z == mobj->z); @@ -9747,7 +9751,7 @@ void P_PushableThinker(mobj_t *mobj) // it has to be pushable RIGHT NOW for this part to happen if (mobj->flags & MF_PUSHABLE && !(mobj->momx || mobj->momy)) - P_TryMove(mobj, mobj->x, mobj->y, true); + P_TryMove(mobj, mobj->x, mobj->y, true, NULL); if (mobj->fuse == 1) // it would explode in the MobjThinker code { @@ -9808,7 +9812,7 @@ void P_SceneryThinker(mobj_t *mobj) { if (!P_SceneryZMovement(mobj)) return; // mobj was removed - P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! + P_CheckPosition(mobj, mobj->x, mobj->y, NULL); // Need this to pick up objects! if (P_MobjWasRemoved(mobj)) return; mobj->floorz = tm.floorz; @@ -13350,7 +13354,7 @@ boolean P_CheckMissileSpawn(mobj_t *th) th->z += th->momz>>1; } - if (!P_TryMove(th, th->x, th->y, true)) + if (!P_TryMove(th, th->x, th->y, true, NULL)) { P_ExplodeMissile(th); return false; diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 04f2c0d0c..de0a36bd1 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -805,7 +805,7 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) // if object doesn't fit at desired location, possibly hurt it if (po->damage && (mo->flags & MF_SHOOTABLE)) { - P_CheckPosition(mo, mo->x + momx, mo->y + momy); + P_CheckPosition(mo, mo->x + momx, mo->y + momy, NULL); mo->floorz = tm.floorz; mo->ceilingz = tm.ceilingz; mo->floorrover = tm.floorrover; @@ -851,7 +851,7 @@ static void Polyobj_slideThing(mobj_t *mo, fixed_t dx, fixed_t dy) mo->player->onconveyor = 1; } else - P_TryMove(mo, mo->x+dx, mo->y+dy, true); + P_TryMove(mo, mo->x+dx, mo->y+dy, true, NULL); } // Causes objects resting on top of the polyobject to 'ride' with its movement. From c41f231de0292102aeafc165de1d0f22a6f89b69 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 21 Nov 2022 16:06:45 -0500 Subject: [PATCH 44/67] No reference count for TryMoveResult_t --- src/p_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index 0e1f5fbc1..97ea69da7 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2145,7 +2145,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re if (result != NULL) { result->line = tm.blockingline; - P_SetTarget(&result->mo, tm.hitthing); + result->mo = tm.hitthing; } return blockval; From b8f59fd2279ec0b9b673068b4096af1291d43444 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 22 Nov 2022 14:28:48 +0000 Subject: [PATCH 45/67] Skin and playerstate code in demos has been partly rewritten to support more than was previously possible. Notable new features: - Guaranteed native compatibility with SF_IRONMAN even with differing # of skins - Bots (todo: can still desync midway through round) Implementation details: - Demo code (skins): - Instead of writing a skin name string, and the player's kartspeed, kartweight, and charflags for each player in the initial player-interpreting loop... - Write a skinlist of EVERY skin's name string, kartspeed, kartweight, and flags next to the file list, to be read into `demo.skinlist`. - If the skin name isn't loaded, find the skin with (in order) - SF_IRONMAN if your skin had SF_IRONMAN, since that's more important to signal - the closest stats otherwise (as per previous implementation) - Just as tolerant to stats AND the number of base skins changing between versions (the bonuschars aegis situation) - Not tolerant to restat, but we can add a DXD or EZT later if we want to natively support that kind of mod - In the initial loop and DXD_SKIN, just write an index that can be used for `demo.skinlist`, and store it in `demo.currentskinid[p]` - The player's skin is now encoded as EZT_IRONMAN for ghosts (and just in case RNG sync fails for unrelated reasons) - In the SF_IRONMAN code when demo.playback is true - everywhere where `skins[player->skin]` is referenced instead uses an index into `demo.skinlist` - SetRandomFakePlayerSkin uses the `demo.skinlist` to build a table to ensure exact random call parity - Also means it no longer double rejection-samples. - `player->fakeskin` and `lastfakeskin` are always == their original recording values, a skin id which can be used into `demo.skinlist` - Demo code (playstate, initial player setup loop): - Add bot flag (`DXD_PST_ISBOT`, `DEMO_BOT`) - Add in-between-level botvars (difficulty, diffincrease, rival) - Don't rely on `PF_WANTSTOJOIN` to activate Additional bugfixes: - Followerskin set to -1 in CL_ClearPlayer so a bad follower isn't recorded on player join without name and color change arriving immediately - Accomodate new joiners in demo code even if they're not on DXD_PST_SPECTATING for one reason or another - Demo extra file list saving is now its own function for code cleanliness - Actually only modify players relevant to the demo at the end of G_DoPlayDemo, not all 16 by supplying and overwriting garbage values (POSSIBLE MEMORY CORRUPTION FIX, mobj_t pointer was previously dereferenced) --- src/d_clisrv.c | 2 + src/d_player.h | 2 + src/g_demo.c | 1111 ++++++++++++++++++++++++++++-------------------- src/g_demo.h | 28 +- src/k_hud.c | 10 +- src/p_spec.c | 11 +- src/p_user.c | 32 +- src/r_skins.c | 74 +++- 8 files changed, 771 insertions(+), 499 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b71ab15a5..3b59d5225 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2550,6 +2550,8 @@ void CL_ClearPlayer(INT32 playernum) memset(&players[playernum], 0, sizeof (player_t)); + players[playernum].followerskin = -1; // don't have a ghost follower + RemoveAdminPlayer(playernum); // don't stay admin after you're gone } diff --git a/src/d_player.h b/src/d_player.h index 23834f7e9..50076e3aa 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -310,6 +310,8 @@ typedef struct botvars_s UINT8 diffincrease; // In GP: bot difficulty will increase this much next round boolean rival; // If true, they're the GP rival + // All entries above persist between rounds and must be recorded in demos + fixed_t rubberband; // Bot rubberband value UINT16 controller; // Special bot controller linedef ID diff --git a/src/g_demo.c b/src/g_demo.c index 482c05aaa..4f56dfd36 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -97,6 +97,9 @@ static struct { // EZT_KART INT32 kartitem, kartamount, kartbumpers; + // EZT_IRONMAN + UINT8 skinid; + UINT8 desyncframes; // Don't try to resync unless we've been off for two frames, to monkeypatch a few trouble spots // EZT_HIT @@ -133,6 +136,7 @@ demoghost *ghosts = NULL; #define DEMO_SPECTATOR 0x01 #define DEMO_KICKSTART 0x02 #define DEMO_SHRINKME 0x04 +#define DEMO_BOT 0x08 // For demos #define ZT_FWD 0x01 @@ -173,12 +177,13 @@ static ticcmd_t oldcmd[MAXPLAYERS]; #define GZT_FOLLOW 0x80 // Followmobj // GZT_EXTRA flags -#define EZT_COLOR 0x001 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.) -#define EZT_FLIP 0x002 // Reversed gravity -#define EZT_SCALE 0x004 // Changed size -#define EZT_HIT 0x008 // Damaged a mobj -#define EZT_SPRITE 0x010 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) -#define EZT_KART 0x020 // SRB2Kart: Changed current held item/quantity and bumpers for battle +#define EZT_COLOR 0x001 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.) +#define EZT_FLIP 0x002 // Reversed gravity +#define EZT_SCALE 0x004 // Changed size +#define EZT_HIT 0x008 // Damaged a mobj +#define EZT_SPRITE 0x010 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) +#define EZT_KART 0x020 // Changed current held item/quantity and bumpers for battle +#define EZT_IRONMAN 0x040 // Changed object skin // GZT_FOLLOW flags #define FZT_SPAWNED 0x01 // just been spawned @@ -206,14 +211,23 @@ void G_LoadMetal(UINT8 **buffer) } // Finds a skin with the closest stats if the expected skin doesn't exist. -static INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight) +static INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight, UINT32 flags) { INT32 i, closest_skin = 0; - UINT8 closest_stats = UINT8_MAX, stat_diff; + UINT8 closest_stats, stat_diff; + boolean doflagcheck = true; + UINT32 flagcheck = flags; + +flaglessretry: + closest_stats = UINT8_MAX; for (i = 0; i < numskins; i++) { stat_diff = abs(skins[i].kartspeed - kartspeed) + abs(skins[i].kartweight - kartweight); + if (doflagcheck && (skins[i].flags & flagcheck) != flagcheck) + { + continue; + } if (stat_diff < closest_stats) { closest_stats = stat_diff; @@ -221,17 +235,22 @@ static INT32 GetSkinNumClosestToStats(UINT8 kartspeed, UINT8 kartweight) } } + if (stat_diff && (doflagcheck || closest_stats == UINT8_MAX)) + { + // Just grab *any* SF_IRONMAN if we don't get it on the first pass. + if ((flagcheck & SF_IRONMAN) && (flagcheck != SF_IRONMAN)) + { + flagcheck = SF_IRONMAN; + } + + doflagcheck = false; + + goto flaglessretry; + } + return closest_skin; } -static void FindClosestSkinForStats(UINT32 p, UINT8 kartspeed, UINT8 kartweight) -{ - INT32 closest_skin = GetSkinNumClosestToStats(kartspeed, kartweight); - - //CONS_Printf("Using %s instead...\n", skins[closest_skin].name); - SetPlayerSkinByNum(p, closest_skin); -} - void G_ReadDemoExtraData(void) { INT32 p, extradata, i; @@ -255,6 +274,64 @@ void G_ReadDemoExtraData(void) { extradata = READUINT8(demo_p); + if (extradata & DXD_PLAYSTATE) + { + i = READUINT8(demo_p); + + if (!playeringame[p]) + { + CL_ClearPlayer(p); + playeringame[p] = true; + G_AddPlayer(p); + players[p].spectator = true; + } + + if ((players[p].bot = !!(i & DXD_PST_ISBOT))) + { + players[p].botvars.difficulty = READUINT8(demo_p); + players[p].botvars.diffincrease = READUINT8(demo_p); // needed to avoid having to duplicate logic + players[p].botvars.rival = (boolean)READUINT8(demo_p); + + i &= ~DXD_PST_ISBOT; + } + + switch (i) { + case DXD_PST_PLAYING: + if (players[p].bot) + { + players[p].spectator = false; + } + else + { + players[p].pflags |= PF_WANTSTOJOIN; + } + //CONS_Printf("player %s is despectating on tic %d\n", player_names[p], leveltime); + break; + + case DXD_PST_SPECTATING: + players[p].pflags &= ~PF_WANTSTOJOIN; // double-fuck you + if (players[p].spectator != true) + { + //CONS_Printf("player %s is spectating on tic %d\n", player_names[p], leveltime); + players[p].spectator = true; + if (players[p].mo) + P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_INSTAKILL); + else + players[p].playerstate = PST_REBORN; + } + break; + + case DXD_PST_LEFT: + CL_RemovePlayer(p, 0); + break; + } + + G_ResetViews(); + + // maybe these are necessary? + K_CheckBumpers(); + P_CheckRacers(); + } if (extradata & DXD_RESPAWN) { if (players[p].mo) @@ -265,24 +342,19 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_SKIN) { - UINT8 kartspeed, kartweight; - UINT32 charflags; + UINT8 skinid; // Skin - M_Memcpy(name, demo_p, 16); - demo_p += 16; - SetPlayerSkin(p, name); - kartspeed = READUINT8(demo_p); - kartweight = READUINT8(demo_p); - charflags = READUINT32(demo_p); + skinid = READUINT8(demo_p); + if (skinid >= demo.numskins) + skinid = 0; + SetPlayerSkinByNum(p, demo.skinlist[skinid].mapping); + demo.currentskinid[p] = skinid; - if (stricmp(skins[players[p].skin].name, name) != 0) - FindClosestSkinForStats(p, kartspeed, kartweight); - - players[p].kartspeed = kartspeed; - players[p].kartweight = kartweight; - players[p].charflags = charflags; + players[p].kartspeed = demo.skinlist[skinid].kartspeed; + players[p].kartweight = demo.skinlist[skinid].kartweight; + players[p].charflags = demo.skinlist[skinid].flags; } if (extradata & DXD_COLOR) { @@ -323,48 +395,6 @@ void G_ReadDemoExtraData(void) } } } - if (extradata & DXD_PLAYSTATE) - { - i = READUINT8(demo_p); - - switch (i) { - case DXD_PST_PLAYING: - players[p].pflags |= PF_WANTSTOJOIN; // fuck you - //CONS_Printf("player %s is despectating on tic %d\n", player_names[p], leveltime); - break; - - case DXD_PST_SPECTATING: - players[p].pflags &= ~PF_WANTSTOJOIN; // double-fuck you - if (!playeringame[p]) - { - CL_ClearPlayer(p); - playeringame[p] = true; - G_AddPlayer(p); - players[p].spectator = true; - //CONS_Printf("player %s is joining server on tic %d\n", player_names[p], leveltime); - } - else - { - //CONS_Printf("player %s is spectating on tic %d\n", player_names[p], leveltime); - players[p].spectator = true; - if (players[p].mo) - P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_INSTAKILL); - else - players[p].playerstate = PST_REBORN; - } - break; - - case DXD_PST_LEFT: - CL_RemovePlayer(p, 0); - break; - } - - G_ResetViews(); - - // maybe these are necessary? - K_CheckBumpers(); - P_CheckRacers(); - } if (extradata & DXD_WEAPONPREF) { WeaponPref_Parse(&demo_p, p); @@ -378,6 +408,7 @@ void G_ReadDemoExtraData(void) while (p != DW_END) { UINT32 rng; + boolean storesynced = demosynced; switch (p) { @@ -391,10 +422,11 @@ void G_ReadDemoExtraData(void) P_SetRandSeed(i, rng); if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (RNG)!\n")); - demosynced = false; + CONS_Alert(CONS_WARNING, "Demo playback has desynced (RNG class %d)!\n", i); + storesynced = false; } } + demosynced = storesynced; } p = READUINT8(demo_p); @@ -420,18 +452,43 @@ void G_WriteDemoExtraData(void) WRITEUINT8(demo_p, i); WRITEUINT8(demo_p, demo_extradata[i]); + if (demo_extradata[i] & DXD_PLAYSTATE) + { + UINT8 pst = DXD_PST_PLAYING; + + demo_writerng = 1; + + if (!playeringame[i]) + { + pst = DXD_PST_LEFT; + } + else if ( + players[i].spectator && + !(players[i].pflags & PF_WANTSTOJOIN) // <= fuck you specifically + ) + { + pst = DXD_PST_SPECTATING; + } + + if (players[i].bot) + { + pst |= DXD_PST_ISBOT; + } + + WRITEUINT8(demo_p, pst); + + if (pst & DXD_PST_ISBOT) + { + WRITEUINT8(demo_p, players[i].botvars.difficulty); + WRITEUINT8(demo_p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic + WRITEUINT8(demo_p, (UINT8)players[i].botvars.rival); + } + } //if (demo_extradata[i] & DXD_RESPAWN) has no extra data if (demo_extradata[i] & DXD_SKIN) { // Skin - memset(name, 0, 16); - strncpy(name, skins[players[i].skin].name, 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; - - WRITEUINT8(demo_p, skins[players[i].skin].kartspeed); - WRITEUINT8(demo_p, skins[players[i].skin].kartweight); - WRITEUINT32(demo_p, skins[players[i].skin].flags); + WRITEUINT8(demo_p, players[i].skin); } if (demo_extradata[i] & DXD_COLOR) { @@ -472,19 +529,6 @@ void G_WriteDemoExtraData(void) demo_p += 16; } - if (demo_extradata[i] & DXD_PLAYSTATE) - { - demo_writerng = 1; - if (!playeringame[i]) - WRITEUINT8(demo_p, DXD_PST_LEFT); - else if ( - players[i].spectator && - !(players[i].pflags & PF_WANTSTOJOIN) // <= fuck you specifically - ) - WRITEUINT8(demo_p, DXD_PST_SPECTATING); - else - WRITEUINT8(demo_p, DXD_PST_PLAYING); - } if (demo_extradata[i] & DXD_WEAPONPREF) { WeaponPref_Save(&demo_p, i); @@ -802,6 +846,14 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) ghostext[playernum].kartbumpers = ghost->player->bumpers; } + if (ghost->player && ( + ghostext[playernum].skinid != (UINT8)(((skin_t *)ghost->skin)-skins) + )) + { + ghostext[playernum].flags |= EZT_IRONMAN; + ghostext[playernum].skinid = (UINT8)(((skin_t *)ghost->skin)-skins); + } + if (ghostext[playernum].flags) { ziptic |= GZT_EXTRA; @@ -849,6 +901,8 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) WRITEINT32(demo_p, ghostext[playernum].kartamount); WRITEINT32(demo_p, ghostext[playernum].kartbumpers); } + if (ghostext[playernum].flags & EZT_IRONMAN) + WRITEUINT8(demo_p,ghostext[playernum].skinid); ghostext[playernum].flags = 0; } @@ -1025,6 +1079,12 @@ void G_ConsGhostTic(INT32 playernum) ghostext[playernum].kartamount = READINT32(demo_p); ghostext[playernum].kartbumpers = READINT32(demo_p); } + if (xziptic & EZT_IRONMAN) + { + ghostext[playernum].skinid = READUINT8(demo_p); + if (ghostext[playernum].skinid >= demo.numskins) + ghostext[playernum].skinid = 0; + } } if (ziptic & GZT_FOLLOW) @@ -1094,6 +1154,18 @@ void G_ConsGhostTic(INT32 playernum) players[playernum].itemamount = ghostext[playernum].kartamount; players[playernum].bumpers = ghostext[playernum].kartbumpers; } + + if (demo.skinlist[ghostext[playernum].skinid].mapping != (UINT8)(((skin_t *)testmo->skin)-skins)) + { + if (demosynced) + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (Character)!\n")); + demosynced = false; + + testmo->skin = &skins[demo.skinlist[ghostext[playernum].skinid].mapping]; + players[playernum].kartspeed = demo.skinlist[ghostext[playernum].skinid].kartspeed; + players[playernum].kartweight = demo.skinlist[ghostext[playernum].skinid].kartweight; + players[playernum].charflags = demo.skinlist[ghostext[playernum].skinid].flags; + } } if (*demo_p == DEMOMARKER) @@ -1118,16 +1190,16 @@ void G_GhostTicker(void) if (ziptic == 0) // Only support player 0 info for now { ziptic = READUINT8(g->p); + if (ziptic & DXD_PLAYSTATE && READUINT8(g->p) != DXD_PST_PLAYING) + I_Error("Ghost is not a record attack ghost PLAYSTATE"); //@TODO lmao don't blow up like this if (ziptic & DXD_SKIN) - g->p += 18; // We _could_ read this info, but it shouldn't change anything in record attack... + g->p++; // We _could_ read this info, but it shouldn't change anything in record attack... if (ziptic & DXD_COLOR) g->p += 16; // Same tbh if (ziptic & DXD_NAME) g->p += 16; // yea if (ziptic & DXD_FOLLOWER) g->p += 32; // ok (32 because there's both the skin and the colour) - if (ziptic & DXD_PLAYSTATE && READUINT8(g->p) != DXD_PST_PLAYING) - I_Error("Ghost is not a record attack ghost PLAYSTATE"); //@TODO lmao don't blow up like this if (ziptic & DXD_WEAPONPREF) g->p++; // ditto } @@ -1204,13 +1276,6 @@ void G_GhostTicker(void) g->mo->z = g->oldmo.z; P_SetThingPosition(g->mo); g->mo->angle = g->oldmo.angle; - g->mo->frame = g->oldmo.frame | tr_trans30<fadein) - { - g->mo->frame += (((--g->fadein)/6)<fadein is bad, and it's only set once, so... - g->mo->renderflags &= ~RF_DONTDRAW; - } - g->mo->sprite2 = g->oldmo.sprite2; if (ziptic & GZT_EXTRA) { // But wait, there's more! @@ -1221,9 +1286,6 @@ void G_GhostTicker(void) switch(g->color) { default: - case GHC_RETURNSKIN: - g->mo->skin = g->oldmo.skin; - /* FALLTHRU */ case GHC_NORMAL: // Go back to skin color g->mo->color = g->oldmo.color; break; @@ -1231,9 +1293,6 @@ void G_GhostTicker(void) case GHC_SUPER: case GHC_INVINCIBLE: break; - case GHC_FIREFLOWER: // Fireflower - g->mo->color = SKINCOLOR_WHITE; - break; } } if (xziptic & EZT_FLIP) @@ -1275,6 +1334,22 @@ void G_GhostTicker(void) g->mo->sprite = READUINT16(g->p); if (xziptic & EZT_KART) g->p += 12; // kartitem, kartamount, kartbumpers + if (xziptic & EZT_IRONMAN) + { + UINT8 skinid = READUINT8(g->p); + if (skinid >= g->numskins) + skinid = 0; + g->mo->skin = &skins[g->skinlist[skinid].mapping]; + } + } + + // todo better defaulting + g->mo->sprite2 = g->oldmo.sprite2; + g->mo->frame = g->oldmo.frame | tr_trans30<fadein) + { + g->mo->frame += (((--g->fadein)/6)<fadein is bad, and it's only set once, so... + g->mo->renderflags &= ~RF_DONTDRAW; } #define follow g->mo->tracer @@ -1384,6 +1459,7 @@ skippedghosttic: p->next = g->next; else ghosts = g->next; + Z_Free(g->skinlist); Z_Free(g); continue; } @@ -1957,293 +2033,24 @@ void G_RecordMetal(void) metalrecording = true; } -void G_BeginRecording(void) +static void G_SaveDemoExtraFiles(UINT8 **pp) { - UINT8 i, j, p; - char name[MAXCOLORNAME+1]; - player_t *player = &players[consoleplayer]; - char *filename; - UINT8 totalfiles; - UINT8 *m; + UINT8 totalfiles = 0, i; + UINT8 *m = (*pp);/* file count */ + (*pp)++; - if (demo_p) - return; - memset(name,0,sizeof(name)); - - demo_p = demobuffer; - demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking<lumpname, MAXMAPLUMPNAME); - M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; - - WRITEUINT8(demo_p, demoflags); - WRITEUINT8(demo_p, gametype & 0xFF); - WRITEUINT8(demo_p, numlaps); - - // file list - m = demo_p;/* file count */ - demo_p += 1; - - totalfiles = 0; for (i = mainwads; ++i < numwadfiles; ) if (wadfiles[i]->important) { nameonly(( filename = va("%s", wadfiles[i]->filename) )); - WRITESTRINGL(demo_p, filename, MAX_WADPATH); - WRITEMEM(demo_p, wadfiles[i]->md5sum, 16); + WRITESTRINGL((*pp), filename, MAX_WADPATH); + WRITEMEM((*pp), wadfiles[i]->md5sum, 16); totalfiles++; } WRITEUINT8(m, totalfiles); - - switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) - { - case ATTACKING_NONE: // 0 - break; - case ATTACKING_TIME: // 1 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time - WRITEUINT32(demo_p,UINT32_MAX); // lap - break; - case ATTACKING_CAPSULES: // 2 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time - break; - default: // 3 - break; - } - - for (i = 0; i < PRNUMCLASS; i++) - { - WRITEUINT32(demo_p, P_GetInitSeed(i)); - } - - // Reserved for extrainfo location from start of file - demoinfo_p = demo_p; - WRITEUINT32(demo_p, 0); - - // Save netvar data - CV_SaveDemoVars(&demo_p); - - // Now store some info for each in-game player - - // Lat' 12/05/19: Do note that for the first game you load, everything that gets saved here is total garbage; - // The name will always be Player , the skin sonic, the color None and the follower 0. This is only correct on subsequent games. - // In the case of said first game, the skin and the likes are updated with Got_NameAndColor, which are then saved in extradata for the demo with DXD_SKIN in r_things.c for instance. - - - for (p = 0; p < MAXPLAYERS; p++) { - if (playeringame[p]) { - player = &players[p]; - WRITEUINT8(demo_p, p); - - i = 0; - if (player->spectator) - i |= DEMO_SPECTATOR; - if (player->pflags & PF_KICKSTARTACCEL) - i |= DEMO_KICKSTART; - if (player->pflags & PF_SHRINKME) - i |= DEMO_SHRINKME; - WRITEUINT8(demo_p, i); - - // Name - memset(name, 0, 16); - strncpy(name, player_names[p], 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Skin - memset(name, 0, 16); - strncpy(name, skins[player->skin].name, 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Color - memset(name, 0, 16); - strncpy(name, skincolors[player->skincolor].name, 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Save follower's skin name - // PS: We must check for 'follower' to determine if the followerskin is valid. It's going to be 0 if we don't have a follower, but 0 is also absolutely a valid follower! - // Doesn't really matter if the follower mobj is valid so long as it exists in a way or another. - - memset(name, 0, 16); - if (player->follower) - strncpy(name, followers[player->followerskin].name, 16); - else - strncpy(name, "None", 16); // Say we don't have one, then. - - M_Memcpy(demo_p,name,16); - demo_p += 16; - - // Save follower's colour - memset(name, 0, 16); - for (j = (numskincolors+2)-1; j > 0; j--) - { - if (Followercolor_cons_t[j].value == players[i].followercolor) - break; - } - strncpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" - M_Memcpy(demo_p, name, 16); - demo_p += 16; - - // Score, since Kart uses this to determine where you start on the map - WRITEUINT32(demo_p, player->score); - - // Power Levels - WRITEUINT16(demo_p, clientpowerlevels[p][gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE]); - - // Kart speed and weight - WRITEUINT8(demo_p, skins[player->skin].kartspeed); - WRITEUINT8(demo_p, skins[player->skin].kartweight); - WRITEUINT8(demo_p, player->lastfakeskin); - WRITEUINT32(demo_p, player->charflags); - - // And mobjtype_t is best with UINT32 too... - WRITEUINT32(demo_p, player->followitem); - } - } - - WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing - - // player lua vars, always saved even if empty - if (demoflags & DF_LUAVARS) - LUA_Archive(&demo_p); - - memset(&oldcmd,0,sizeof(oldcmd)); - memset(&oldghost,0,sizeof(oldghost)); - memset(&ghostext,0,sizeof(ghostext)); - - for (i = 0; i < MAXPLAYERS; i++) - { - ghostext[i].lastcolor = ghostext[i].color = GHC_NORMAL; - ghostext[i].lastscale = ghostext[i].scale = FRACUNIT; - - if (players[i].mo) - { - oldghost[i].x = players[i].mo->x; - oldghost[i].y = players[i].mo->y; - oldghost[i].z = players[i].mo->z; - oldghost[i].angle = players[i].mo->angle; - - // preticker started us gravity flipped - if (players[i].mo->eflags & MFE_VERTICALFLIP) - ghostext[i].flags |= EZT_FLIP; - } - } -} - -void G_BeginMetal(void) -{ - mobj_t *mo = players[consoleplayer].mo; - -#if 0 - if (demo_p) - return; -#endif - - demo_p = demobuffer; - - // Write header. - M_Memcpy(demo_p, DEMOHEADER, 12); demo_p += 12; - WRITEUINT8(demo_p,VERSION); - WRITEUINT8(demo_p,SUBVERSION); - WRITEUINT16(demo_p,DEMOVERSION); - - // demo checksum - demo_p += 16; - - M_Memcpy(demo_p, "METL", 4); demo_p += 4; - - memset(&ghostext,0,sizeof(ghostext)); - ghostext[0].lastscale = ghostext[0].scale = FRACUNIT; - - // Set up our memory. - memset(&oldmetal,0,sizeof(oldmetal)); - oldmetal.x = mo->x; - oldmetal.y = mo->y; - oldmetal.z = mo->z; - oldmetal.angle = mo->angle>>24; -} - -void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT16 color, UINT32 val) -{ - char temp[16]; - - if (demoinfo_p && *(UINT32 *)demoinfo_p == 0) - { - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - *(UINT32 *)demoinfo_p = demo_p - demobuffer; - } - - WRITEUINT8(demo_p, DW_STANDING); - WRITEUINT8(demo_p, ranking); - - // Name - memset(temp, 0, 16); - strncpy(temp, name, 16); - M_Memcpy(demo_p,temp,16); - demo_p += 16; - - // Skin - memset(temp, 0, 16); - strncpy(temp, skins[skinnum].name, 16); - M_Memcpy(demo_p,temp,16); - demo_p += 16; - - // Color - memset(temp, 0, 16); - strncpy(temp, skincolors[color].name, 16); - M_Memcpy(demo_p,temp,16); - demo_p += 16; - - // Score/time/whatever - WRITEUINT32(demo_p, val); -} - -void G_SetDemoTime(UINT32 ptime, UINT32 plap) -{ - if (!demo.recording || !demotime_p) - return; - if (demoflags & DF_TIMEATTACK) - { - WRITEUINT32(demotime_p, ptime); - WRITEUINT32(demotime_p, plap); - demotime_p = NULL; - } - else if (demoflags & DF_BREAKTHECAPSULES) - { - WRITEUINT32(demotime_p, ptime); - (void)plap; - demotime_p = NULL; - } } static void G_LoadDemoExtraFiles(UINT8 **pp) @@ -2408,6 +2215,364 @@ static UINT8 G_CheckDemoExtraFiles(UINT8 **pp, boolean quick) return error; } +static void G_SaveDemoSkins(UINT8 **pp) +{ + char skin[16]; + UINT8 i; + + WRITEUINT8((*pp), numskins); + for (i = 0; i < numskins; i++) + { + // Skinname, for first attempt at identification. + memset(skin, 0, 16); + strncpy(skin, skins[i].name, 16); + WRITEMEM((*pp), skin, 16); + + // Backup information for second pass. + WRITEUINT8((*pp), skins[i].kartspeed); + WRITEUINT8((*pp), skins[i].kartweight); + WRITEUINT32((*pp), skins[i].flags); + } +} + +static democharlist_t *G_LoadDemoSkins(UINT8 **pp, UINT8 *worknumskins, boolean getclosest) +{ + char skin[17]; + UINT8 i; + democharlist_t *skinlist = NULL; + + (*worknumskins) = READUINT8((*pp)); + if (!(*worknumskins)) + return NULL; + + skinlist = Z_Calloc(sizeof(democharlist_t) * (*worknumskins), PU_STATIC, NULL); + if (!skinlist) + { + I_Error("G_LoadDemoSkins: Insufficient memory to allocate list"); + } + + skin[16] = '\0'; + + for (i = 0; i < (*worknumskins); i++) + { + INT32 result = -1; + + READMEM((*pp), skin, 16); + skinlist[i].kartspeed = READUINT8((*pp)); + skinlist[i].kartweight = READUINT8((*pp)); + skinlist[i].flags = READUINT32((*pp)); + + result = R_SkinAvailable(skin); + if (result == -1) + { + if (!getclosest) + { + result = MAXSKINS; + } + else + { + result = GetSkinNumClosestToStats(skinlist[i].kartspeed, skinlist[i].kartweight, skinlist[i].flags); + } + } + + if (result != -1) + { + skinlist[i].mapping = (UINT8)result; + } + } + + return skinlist; +} + +static void G_SkipDemoSkins(UINT8 **pp) +{ + UINT8 demonumskins; + UINT8 i; + + demonumskins = READUINT8((*pp)); + for (i = 0; i < demonumskins; ++i) + { + (*pp) += 16; // name + (*pp)++; // kartspeed + (*pp)++; // kartweight + (*pp) += 4; // flags + } +} + +void G_BeginRecording(void) +{ + UINT8 i, j, p; + char name[MAXCOLORNAME+1]; + player_t *player = &players[consoleplayer]; + + if (demo_p) + return; + memset(name,0,sizeof(name)); + + demo_p = demobuffer; + demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking<lumpname, MAXMAPLUMPNAME); + M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; + + WRITEUINT8(demo_p, demoflags); + WRITEUINT8(demo_p, gametype & 0xFF); + WRITEUINT8(demo_p, numlaps); + + // file list + G_SaveDemoExtraFiles(&demo_p); + + // character list + G_SaveDemoSkins(&demo_p); + + switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) + { + case ATTACKING_NONE: // 0 + break; + case ATTACKING_TIME: // 1 + demotime_p = demo_p; + WRITEUINT32(demo_p,UINT32_MAX); // time + WRITEUINT32(demo_p,UINT32_MAX); // lap + break; + case ATTACKING_CAPSULES: // 2 + demotime_p = demo_p; + WRITEUINT32(demo_p,UINT32_MAX); // time + break; + default: // 3 + break; + } + + for (i = 0; i < PRNUMCLASS; i++) + { + WRITEUINT32(demo_p, P_GetInitSeed(i)); + } + + // Reserved for extrainfo location from start of file + demoinfo_p = demo_p; + WRITEUINT32(demo_p, 0); + + // Save netvar data + CV_SaveDemoVars(&demo_p); + + // Now store some info for each in-game player + + // Lat' 12/05/19: Do note that for the first game you load, everything that gets saved here is total garbage; + // The name will always be Player , the skin sonic, the color None and the follower 0. This is only correct on subsequent games. + // In the case of said first game, the skin and the likes are updated with Got_NameAndColor, which are then saved in extradata for the demo with DXD_SKIN in r_things.c for instance. + + + for (p = 0; p < MAXPLAYERS; p++) { + if (playeringame[p]) { + player = &players[p]; + WRITEUINT8(demo_p, p); + + i = 0; + if (player->spectator == true) + i |= DEMO_SPECTATOR; + if (player->pflags & PF_KICKSTARTACCEL) + i |= DEMO_KICKSTART; + if (player->pflags & PF_SHRINKME) + i |= DEMO_SHRINKME; + if (player->bot == true) + i |= DEMO_BOT; + WRITEUINT8(demo_p, i); + + if (i & DEMO_BOT) + { + WRITEUINT8(demo_p, player->botvars.difficulty); + WRITEUINT8(demo_p, player->botvars.diffincrease); // needed to avoid having to duplicate logic + WRITEUINT8(demo_p, (UINT8)player->botvars.rival); + } + + // Name + memset(name, 0, 16); + strncpy(name, player_names[p], 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Skin (now index into demo.skinlist) + WRITEUINT8(demo_p, player->skin); + WRITEUINT8(demo_p, player->lastfakeskin); + + // Color + memset(name, 0, 16); + strncpy(name, skincolors[player->skincolor].name, 16); + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Save follower's skin name + // PS: We must check for 'follower' to determine if the followerskin is valid. It's going to be 0 if we don't have a follower, but 0 is also absolutely a valid follower! + // Doesn't really matter if the follower mobj is valid so long as it exists in a way or another. + + memset(name, 0, 16); + if (player->follower) + strncpy(name, followers[player->followerskin].name, 16); + else + strncpy(name, "None", 16); // Say we don't have one, then. + + M_Memcpy(demo_p,name,16); + demo_p += 16; + + // Save follower's colour + memset(name, 0, 16); + for (j = (numskincolors+2)-1; j > 0; j--) + { + if (Followercolor_cons_t[j].value == players[i].followercolor) + break; + } + strncpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" + M_Memcpy(demo_p, name, 16); + demo_p += 16; + + // Score, since Kart uses this to determine where you start on the map + WRITEUINT32(demo_p, player->score); + + // Power Levels + j = gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE; + WRITEUINT16(demo_p, clientpowerlevels[p][j]); + + // And mobjtype_t is best with UINT32 too... + WRITEUINT32(demo_p, player->followitem); + } + } + + WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing + + // player lua vars, always saved even if empty + if (demoflags & DF_LUAVARS) + LUA_Archive(&demo_p); + + memset(&oldcmd,0,sizeof(oldcmd)); + memset(&oldghost,0,sizeof(oldghost)); + memset(&ghostext,0,sizeof(ghostext)); + + for (i = 0; i < MAXPLAYERS; i++) + { + ghostext[i].lastcolor = ghostext[i].color = GHC_NORMAL; + ghostext[i].lastscale = ghostext[i].scale = FRACUNIT; + ghostext[i].skinid = players[i].skin; + + if (players[i].mo) + { + oldghost[i].x = players[i].mo->x; + oldghost[i].y = players[i].mo->y; + oldghost[i].z = players[i].mo->z; + oldghost[i].angle = players[i].mo->angle; + + // preticker started us gravity flipped + if (players[i].mo->eflags & MFE_VERTICALFLIP) + ghostext[i].flags |= EZT_FLIP; + } + } +} + +void G_BeginMetal(void) +{ + mobj_t *mo = players[consoleplayer].mo; + +#if 0 + if (demo_p) + return; +#endif + + demo_p = demobuffer; + + // Write header. + M_Memcpy(demo_p, DEMOHEADER, 12); demo_p += 12; + WRITEUINT8(demo_p,VERSION); + WRITEUINT8(demo_p,SUBVERSION); + WRITEUINT16(demo_p,DEMOVERSION); + + // demo checksum + demo_p += 16; + + M_Memcpy(demo_p, "METL", 4); demo_p += 4; + + memset(&ghostext,0,sizeof(ghostext)); + ghostext[0].lastscale = ghostext[0].scale = FRACUNIT; + + // Set up our memory. + memset(&oldmetal,0,sizeof(oldmetal)); + oldmetal.x = mo->x; + oldmetal.y = mo->y; + oldmetal.z = mo->z; + oldmetal.angle = mo->angle>>24; +} + +void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT16 color, UINT32 val) +{ + char temp[16]; + + if (demoinfo_p && *(UINT32 *)demoinfo_p == 0) + { + WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker + *(UINT32 *)demoinfo_p = demo_p - demobuffer; + } + + WRITEUINT8(demo_p, DW_STANDING); + WRITEUINT8(demo_p, ranking); + + // Name + memset(temp, 0, 16); + strncpy(temp, name, 16); + M_Memcpy(demo_p,temp,16); + demo_p += 16; + + // Skin + WRITEUINT8(demo_p, skinnum); + + // Color + memset(temp, 0, 16); + strncpy(temp, skincolors[color].name, 16); + M_Memcpy(demo_p,temp,16); + demo_p += 16; + + // Score/time/whatever + WRITEUINT32(demo_p, val); +} + +void G_SetDemoTime(UINT32 ptime, UINT32 plap) +{ + if (!demo.recording || !demotime_p) + return; + if (demoflags & DF_TIMEATTACK) + { + WRITEUINT32(demotime_p, ptime); + WRITEUINT32(demotime_p, plap); + demotime_p = NULL; + } + else if (demoflags & DF_BREAKTHECAPSULES) + { + WRITEUINT32(demotime_p, ptime); + (void)plap; + demotime_p = NULL; + } +} + // Returns bitfield: // 1 == new demo has lower time // 2 == new demo has higher score @@ -2450,6 +2615,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p++; // numlaps G_SkipDemoExtraFiles(&p); + G_SkipDemoSkins(&p); + aflags = flags & (DF_TIMEATTACK|DF_BREAKTHECAPSULES); I_Assert(aflags); @@ -2514,6 +2681,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) return UINT8_MAX; } + G_SkipDemoSkins(&p); + oldtime = READUINT32(p); if (uselaps) oldlap = READUINT32(p); @@ -2545,7 +2714,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) void G_LoadDemoInfo(menudemo_t *pdemo) { UINT8 *infobuffer, *info_p, *extrainfo_p; - UINT8 version, subversion, pdemoflags; + UINT8 version, subversion, pdemoflags, worknumskins, skinid; + democharlist_t *skinlist = NULL; UINT16 pdemoversion, count; char mapname[MAXMAPLUMPNAME]; INT32 i; @@ -2616,6 +2786,13 @@ void G_LoadDemoInfo(menudemo_t *pdemo) pdemo->addonstatus = G_CheckDemoExtraFiles(&info_p, true); + skinlist = G_LoadDemoSkins(&info_p, &worknumskins, false); + if (!skinlist) + { + CONS_Alert(CONS_ERROR, M_GetText("%s has an invalid skin list.\n"), pdemo->filepath); + goto badreplay; + } + for (i = 0; i < PRNUMCLASS; i++) { info_p += 4; // RNG seed @@ -2662,15 +2839,10 @@ void G_LoadDemoInfo(menudemo_t *pdemo) extrainfo_p += 16; // Skin - M_Memcpy(temp,extrainfo_p,16); - extrainfo_p += 16; - pdemo->standings[count].skin = UINT8_MAX; - for (i = 0; i < numskins; i++) - if (stricmp(skins[i].name, temp) == 0) - { - pdemo->standings[count].skin = i; - break; - } + skinid = READUINT8(extrainfo_p); + if (skinid > worknumskins) + skinid = 0; + pdemo->standings[count].skin = skinlist[skinid].mapping; // Color M_Memcpy(temp,extrainfo_p,16); @@ -2692,12 +2864,14 @@ void G_LoadDemoInfo(menudemo_t *pdemo) } // I think that's everything we need? + Z_Free(skinlist); Z_Free(infobuffer); return; badreplay: pdemo->type = MD_INVALID; sprintf(pdemo->title, "INVALID REPLAY"); + Z_Free(skinlist); Z_Free(infobuffer); } @@ -2719,16 +2893,15 @@ void G_DeferedPlayDemo(const char *name) void G_DoPlayDemo(char *defdemoname) { - UINT8 i, p; + UINT8 i, p, numslots = 0; lumpnum_t l; - char skin[17],color[MAXCOLORNAME+1],follower[17],mapname[MAXMAPLUMPNAME],*n,*pdemoname; + char color[MAXCOLORNAME+1],follower[17],mapname[MAXMAPLUMPNAME],*n,*pdemoname; UINT8 version,subversion; UINT32 randseed[PRNUMCLASS]; char msg[1024]; - boolean spectator; - UINT8 slots[MAXPLAYERS], kartspeed[MAXPLAYERS], kartweight[MAXPLAYERS], lastfakeskin[MAXPLAYERS], numslots = 0; - UINT32 charflags[MAXPLAYERS]; + boolean spectator, bot; + UINT8 slots[MAXPLAYERS], lastfakeskin[MAXPLAYERS]; #if defined(SKIPERRORS) && !defined(DEVELOP) boolean skiperrors = false; @@ -2736,7 +2909,6 @@ void G_DoPlayDemo(char *defdemoname) G_InitDemoRewind(); - skin[16] = '\0'; follower[16] = '\0'; color[MAXCOLORNAME] = '\0'; @@ -2908,6 +3080,20 @@ void G_DoPlayDemo(char *defdemoname) } } + // character list + demo.skinlist = G_LoadDemoSkins(&demo_p, &demo.numskins, true); + if (!demo.skinlist) + { + snprintf(msg, 1024, M_GetText("%s has an invalid skin list and cannot be played.\n"), pdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(pdemoname); + Z_Free(demobuffer); + demo.playback = false; + demo.title = false; + return; + } + modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; multiplayer = !!(demoflags & DF_MULTIPLAYER); demo.netgame = (multiplayer && !(demoflags & DF_NONETMP)); @@ -2946,6 +3132,8 @@ void G_DoPlayDemo(char *defdemoname) snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(demo.skinlist); + demo.skinlist = NULL; Z_Free(pdemoname); Z_Free(demobuffer); demo.playback = false; @@ -2962,6 +3150,8 @@ void G_DoPlayDemo(char *defdemoname) snprintf(msg, 1024, M_GetText("%s contains no data to be played.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(demo.skinlist); + demo.skinlist = NULL; Z_Free(pdemoname); Z_Free(demobuffer); demo.playback = false; @@ -3006,14 +3196,17 @@ void G_DoPlayDemo(char *defdemoname) UINT8 flags = READUINT8(demo_p); spectator = !!(flags & DEMO_SPECTATOR); + bot = !!(flags & DEMO_BOT); - if (spectator == true) + if ((spectator || bot)) { if (modeattacking) { - snprintf(msg, 1024, M_GetText("%s is a Record Attack replay with spectators, and is thus invalid.\n"), pdemoname); + snprintf(msg, 1024, M_GetText("%s is a Record Attack replay with %s, and is thus invalid.\n"), pdemoname, (bot ? "bots" : "spectators")); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(demo.skinlist); + demo.skinlist = NULL; Z_Free(pdemoname); Z_Free(demobuffer); demo.playback = false; @@ -3030,6 +3223,8 @@ void G_DoPlayDemo(char *defdemoname) snprintf(msg, 1024, M_GetText("%s is a Record Attack replay with multiple players, and is thus invalid.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); + Z_Free(demo.skinlist); + demo.skinlist = NULL; Z_Free(pdemoname); Z_Free(demobuffer); demo.playback = false; @@ -3053,21 +3248,28 @@ void G_DoPlayDemo(char *defdemoname) else players[p].pflags &= ~PF_SHRINKME; + if ((players[p].bot = bot) == true) + { + players[p].botvars.difficulty = READUINT8(demo_p); + players[p].botvars.diffincrease = READUINT8(demo_p); // needed to avoid having to duplicate logic + players[p].botvars.rival = (boolean)READUINT8(demo_p); + } + K_UpdateShrinkCheat(&players[p]); // Name M_Memcpy(player_names[p],demo_p,16); demo_p += 16; - /*if (players[p].spectator) - { - CONS_Printf("player %s is spectator at start\n", player_names[p]); - }*/ - // Skin - M_Memcpy(skin,demo_p,16); - demo_p += 16; - SetPlayerSkin(p, skin); + + i = READUINT8(demo_p); + if (i >= demo.numskins) + i = 0; + SetPlayerSkinByNum(p, demo.skinlist[i].mapping); + demo.currentskinid[p] = ghostext[p].skinid = i; + + lastfakeskin[p] = READUINT8(demo_p); // Color M_Memcpy(color,demo_p,16); @@ -3102,15 +3304,6 @@ void G_DoPlayDemo(char *defdemoname) // Power Levels clientpowerlevels[p][gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE] = READUINT16(demo_p); - // Kart stats, temporarily - kartspeed[p] = READUINT8(demo_p); - kartweight[p] = READUINT8(demo_p); - lastfakeskin[p] = READUINT8(demo_p); - charflags[p] = READUINT32(demo_p); - - if (stricmp(skins[players[p].skin].name, skin) != 0) - FindClosestSkinForStats(p, kartspeed[p], kartweight[p]); - // Followitem players[p].followitem = READUINT32(demo_p); @@ -3149,23 +3342,24 @@ void G_DoPlayDemo(char *defdemoname) G_InitNew(demoflags & DF_ENCORE, gamemap, true, true, false); // Doesn't matter whether you reset or not here, given changes to resetplayer. - for (i = 0; i < MAXPLAYERS; i++) + for (i = 0; i < numslots; i++) { - if (players[i].mo) + p = slots[i]; + if (players[p].mo) { - players[i].mo->color = players[i].skincolor; - oldghost[i].x = players[i].mo->x; - oldghost[i].y = players[i].mo->y; - oldghost[i].z = players[i].mo->z; + players[p].mo->color = players[p].skincolor; + oldghost[p].x = players[p].mo->x; + oldghost[p].y = players[p].mo->y; + oldghost[p].z = players[p].mo->z; } // Set saved attribute values // No cheat checking here, because even if they ARE wrong... // it would only break the replay if we clipped them. - players[i].kartspeed = kartspeed[i]; - players[i].kartweight = kartweight[i]; - players[i].lastfakeskin = lastfakeskin[i]; - players[i].charflags = charflags[i]; + players[p].kartspeed = demo.skinlist[demo.currentskinid[p]].kartspeed; + players[p].kartweight = demo.skinlist[demo.currentskinid[p]].kartweight; + players[p].charflags = demo.skinlist[demo.currentskinid[p]].flags; + players[p].lastfakeskin = lastfakeskin[p]; } demo.deferstart = true; @@ -3175,17 +3369,17 @@ void G_AddGhost(char *defdemoname) { INT32 i; lumpnum_t l; - char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; + char name[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; demoghost *gh; UINT8 flags; UINT8 *buffer,*p; mapthing_t *mthing; UINT16 count, ghostversion; skin_t *ghskin = &skins[0]; - UINT8 kartspeed = UINT8_MAX, kartweight = UINT8_MAX; + UINT8 worknumskins; + democharlist_t *skinlist = NULL; name[16] = '\0'; - skin[16] = '\0'; color[16] = '\0'; n = defdemoname+strlen(defdemoname); @@ -3288,6 +3482,15 @@ void G_AddGhost(char *defdemoname) p++; // numlaps G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts. + skinlist = G_LoadDemoSkins(&p, &worknumskins, true); + if (!skinlist) + { + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data has invalid skin list, cannot continue.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 @@ -3321,6 +3524,7 @@ void G_AddGhost(char *defdemoname) if (*p == DEMOMARKER) { CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Replay is empty.\n"), pdemoname); + Z_Free(skinlist); Z_Free(pdemoname); Z_Free(buffer); return; @@ -3329,9 +3533,10 @@ void G_AddGhost(char *defdemoname) p++; // player number - doesn't really need to be checked, TODO maybe support adding multiple players' ghosts at once // any invalidating flags? - if ((READUINT8(p) & (DEMO_SPECTATOR)) != 0) + if ((READUINT8(p) & (DEMO_SPECTATOR|DEMO_BOT)) != 0) { CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname); + Z_Free(skinlist); Z_Free(pdemoname); Z_Free(buffer); return; @@ -3342,8 +3547,10 @@ void G_AddGhost(char *defdemoname) p += 16; // Skin - M_Memcpy(skin, p, 16); - p += 16; + i = READUINT8(p); + if (i < worknumskins) + ghskin = &skins[skinlist[i].mapping]; + p++; // lastfakeskin // Color M_Memcpy(color, p, 16); @@ -3355,36 +3562,17 @@ void G_AddGhost(char *defdemoname) p += 4; // score p += 2; // powerlevel - kartspeed = READUINT8(p); - kartweight = READUINT8(p); - p += 1; // lastfakeskin - p += 4; // charflags - p += 4; // followitem (maybe change later) if (READUINT8(p) != 0xFF) { CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname); + Z_Free(skinlist); Z_Free(pdemoname); Z_Free(buffer); return; } - for (i = 0; i < numskins; i++) - if (!stricmp(skins[i].name,skin)) - { - ghskin = &skins[i]; - break; - } - - if (i == numskins) - { - if (kartspeed != UINT8_MAX && kartweight != UINT8_MAX) - ghskin = &skins[GetSkinNumClosestToStats(kartspeed, kartweight)]; - - CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Invalid character. Falling back to %s.\n"), pdemoname, ghskin->name); - } - gh = Z_Calloc(sizeof(demoghost), PU_LEVEL, NULL); gh->next = ghosts; @@ -3392,6 +3580,9 @@ void G_AddGhost(char *defdemoname) M_Memcpy(gh->checksum, md5, 16); gh->p = p; + gh->numskins = worknumskins; + gh->skinlist = skinlist; + ghosts = gh; gh->version = ghostversion; @@ -3454,6 +3645,7 @@ void G_FreeGhosts(void) while (ghosts) { demoghost *next = ghosts->next; + Z_Free(ghosts->skinlist); Z_Free(ghosts); ghosts = next; } @@ -3513,6 +3705,8 @@ void G_UpdateStaffGhostName(lumpnum_t l) p++; // numlaps G_SkipDemoExtraFiles(&p); + G_SkipDemoSkins(&p); + switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 @@ -3780,6 +3974,9 @@ void G_StopDemo(void) democam.localaiming = 0; democam.keyboardlook = false; + Z_Free(demo.skinlist); + demo.skinlist = NULL; + if (gamestate == GS_INTERMISSION) Y_EndIntermission(); // cleanup diff --git a/src/g_demo.h b/src/g_demo.h index 2dc93eef2..a00756a74 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -28,6 +28,13 @@ extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality; extern tic_t demostarttime; +typedef struct democharlist_s { + UINT8 mapping; // No, this isn't about levels. It maps to loaded character ID. + UINT8 kartspeed; + UINT8 kartweight; + UINT32 flags; +} democharlist_t; + // Publicly-accessible demo vars struct demovars_s { char titlename[65]; @@ -54,6 +61,9 @@ struct demovars_s { boolean freecam; + UINT8 numskins; + democharlist_t *skinlist; + UINT8 currentskinid[MAXPLAYERS]; }; extern struct demovars_s demo; @@ -102,20 +112,18 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname); typedef enum { GHC_NORMAL = 0, - GHC_SUPER, - GHC_FIREFLOWER, GHC_INVINCIBLE, - GHC_RETURNSKIN // not actually a colour + GHC_SUPER } ghostcolor_t; extern UINT8 demo_extradata[MAXPLAYERS]; extern UINT8 demo_writerng; -#define DXD_RESPAWN 0x01 // "respawn" command in console -#define DXD_SKIN 0x02 // skin changed -#define DXD_NAME 0x04 // name changed -#define DXD_COLOR 0x08 // color changed -#define DXD_PLAYSTATE 0x10 // state changed between playing, spectating, or not in-game +#define DXD_PLAYSTATE 0x01 // state changed between playing, spectating, or not in-game +#define DXD_RESPAWN 0x02 // "respawn" command in console +#define DXD_SKIN 0x04 // skin changed +#define DXD_NAME 0x08 // name changed +#define DXD_COLOR 0x10 // color changed #define DXD_FOLLOWER 0x20 // follower was changed #define DXD_WEAPONPREF 0x40 // netsynced playsim settings were changed @@ -123,6 +131,8 @@ extern UINT8 demo_writerng; #define DXD_PST_SPECTATING 0x02 #define DXD_PST_LEFT 0x03 +#define DXD_PST_ISBOT 0x80 // extra flag + // Record/playback tics void G_ReadDemoExtraData(void); void G_WriteDemoExtraData(void); @@ -155,6 +165,8 @@ typedef struct demoghost { UINT8 *buffer, *p, color; UINT8 fadein; UINT16 version; + UINT8 numskins; + democharlist_t *skinlist; mobj_t oldmo, *mo; struct demoghost *next; } demoghost; diff --git a/src/k_hud.c b/src/k_hud.c index 29525a1c4..d9908c4c6 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1748,6 +1748,7 @@ static boolean K_drawKartPositionFaces(void) INT32 xoff, yoff, flipflag = 0; UINT8 workingskin; UINT8 *colormap; + UINT32 skinflags; ranklines = 0; memset(completed, 0, sizeof (completed)); @@ -1832,10 +1833,13 @@ static boolean K_drawKartPositionFaces(void) bumperx = FACE_X+19; emeraldx = FACE_X+16; + skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[rankplayer[i]]].flags + : skins[players[rankplayer[i]].skin].flags; + // Flip SF_IRONMAN portraits, but only if they're transformed - if (skins[players[rankplayer[i]].skin].flags & SF_IRONMAN - && !P_MobjWasRemoved(players[rankplayer[i]].mo) - && !(((skin_t*)players[rankplayer[i]].mo->skin)->flags & SF_IRONMAN) ) + if (skinflags & SF_IRONMAN + && !(players[rankplayer[i]].charflags & SF_IRONMAN) ) { flipflag = V_FLIP|V_VFLIP; // blonic flip xoff = yoff = 16; diff --git a/src/p_spec.c b/src/p_spec.c index 7a1e4072a..07ec1f102 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1927,9 +1927,16 @@ static void K_HandleLapIncrement(player_t *player) { P_DoPlayerExit(player); P_SetupSignExit(player); - } else if (skins[player->skin].flags & SF_IRONMAN) + } + else { - SetRandomFakePlayerSkin(player, true); + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[(player-players)]].flags + : skins[player->skin].flags; + if (skinflags & SF_IRONMAN) + { + SetRandomFakePlayerSkin(player, true); + } } diff --git a/src/p_user.c b/src/p_user.c index 0a95a143c..1f58384df 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4171,25 +4171,31 @@ void P_PlayerThink(player_t *player) } // Random skin / "ironman" - if ((!P_MobjWasRemoved(player->mo)) && (skins[player->skin].flags & SF_IRONMAN)) // we are Heavy Magician with a mobj { - if (((skin_t *)player->mo->skin)->flags & SF_IRONMAN) // no fakeskin yet + UINT32 skinflags = (demo.playback) + ? demo.skinlist[demo.currentskinid[playeri]].flags + : skins[player->skin].flags; + + if (skinflags & SF_IRONMAN) // we are Heavy Magician { - if (leveltime >= starttime && !player->exiting) + if (player->charflags & SF_IRONMAN) // no fakeskin yet { - if (player->fakeskin != MAXSKINS) + if (leveltime >= starttime && !player->exiting) { - SetFakePlayerSkin(player, player->fakeskin); - } - else if (!(gametyperules & GTR_CIRCUIT)) - { - SetRandomFakePlayerSkin(player, false); + if (player->fakeskin != MAXSKINS) + { + SetFakePlayerSkin(player, player->fakeskin); + } + else if (!(gametyperules & GTR_CIRCUIT)) + { + SetRandomFakePlayerSkin(player, false); + } } } - } - else if (player->exiting) // wearing a fakeskin, but need to display signpost postrace etc - { - ClearFakePlayerSkin(player); + else if (player->exiting) // wearing a fakeskin, but need to display signpost postrace etc + { + ClearFakePlayerSkin(player); + } } } diff --git a/src/r_skins.c b/src/r_skins.c index 9068a1021..db1e81345 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -337,23 +337,53 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) } // Set mo skin but not player_t skin, for ironman -void SetFakePlayerSkin(player_t* player, INT32 skinnum) +void SetFakePlayerSkin(player_t* player, INT32 skinid) { - player->mo->skin = &skins[skinnum]; - player->fakeskin = skinnum; - player->lastfakeskin = skinnum; - player->kartspeed = skins[skinnum].kartspeed; - player->kartweight = skins[skinnum].kartweight; - player->charflags = skins[skinnum].flags; + player->fakeskin = skinid; + + if (demo.playback) + { + player->kartspeed = demo.skinlist[skinid].kartspeed; + player->kartweight = demo.skinlist[skinid].kartweight; + player->charflags = demo.skinlist[skinid].flags; + skinid = demo.skinlist[skinid].mapping; + } + else + { + player->kartspeed = skins[skinid].kartspeed; + player->kartweight = skins[skinid].kartweight; + player->charflags = skins[skinid].flags; + } + + player->mo->skin = &skins[skinid]; } // Loudly rerandomize void SetRandomFakePlayerSkin(player_t* player, boolean fast) { INT32 i; - do { - i = P_RandomKey(PR_RANDOMSKIN, numskins); - } while (skins[i].flags & SF_IRONMAN || i == player->lastfakeskin); + UINT8 usableskins = 0, maxskinpick; + UINT8 grabskins[MAXSKINS]; + + maxskinpick = (demo.playback ? demo.numskins : numskins); + + for (i = 0; i < maxskinpick; i++) + { + if (i == player->lastfakeskin) + continue; + if (demo.playback) + { + if (demo.skinlist[i].flags & SF_IRONMAN) + continue; + } + else if (skins[i].flags & SF_IRONMAN) + continue; + /*if (K_SkinLocked(i)) + continue;*/ + grabskins[usableskins++] = i; + } + + i = grabskins[P_RandomKey(PR_RANDOMSKIN, usableskins)]; SetFakePlayerSkin(player, i); @@ -407,16 +437,28 @@ void SetRandomFakePlayerSkin(player_t* player, boolean fast) // Return to base skin from an SF_IRONMAN randomization void ClearFakePlayerSkin(player_t* player) { - if ((skins[player->skin].flags & SF_IRONMAN) && !P_MobjWasRemoved(player->mo)) + UINT8 skinid; + UINT32 flags; + + if (demo.playback) { - player->mo->skin = &skins[player->skin]; - player->fakeskin = MAXSKINS; - player->kartspeed = skins[player->skin].kartspeed; - player->kartweight = skins[player->skin].kartweight; - player->charflags = skins[player->skin].flags; + skinid = demo.currentskinid[(player-players)]; + flags = demo.skinlist[skinid].flags; + } + else + { + skinid = player->skin; + flags = skins[player->skin].flags; + } + + if ((flags & SF_IRONMAN) && !P_MobjWasRemoved(player->mo)) + { + SetFakePlayerSkin(player, skinid); S_StartSound(player->mo, sfx_s3k9f); K_SpawnMagicianParticles(player->mo, 5); } + + player->fakeskin = MAXSKINS; } // From 3ee8bbbfc487c6184a41522cd70fb285a596f87f Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Nov 2022 18:01:23 +0000 Subject: [PATCH 46/67] Adjust various EZT_s. - EZT_KART is now EZT_ITEMDATA. - Uses the new one-byte widths to reduce spurious filesize use for item type, item amount, and bumpers. - EZT_IRONMAN is now EZT_STATDATA. - Now includes kartspeed, kartweight, and charflags to be tolerant to restat. --- src/g_demo.c | 126 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 51 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 4f56dfd36..dc816856f 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -94,11 +94,13 @@ static struct { // EZT_SCALE fixed_t scale, lastscale; - // EZT_KART - INT32 kartitem, kartamount, kartbumpers; + // EZT_ITEMDATA + SINT8 itemtype; + UINT8 itemamount, bumpers; - // EZT_IRONMAN - UINT8 skinid; + // EZT_STATDATA + UINT8 skinid, kartspeed, kartweight; + UINT32 charflags; UINT8 desyncframes; // Don't try to resync unless we've been off for two frames, to monkeypatch a few trouble spots @@ -176,14 +178,14 @@ static ticcmd_t oldcmd[MAXPLAYERS]; #define GZT_EXTRA 0x40 #define GZT_FOLLOW 0x80 // Followmobj -// GZT_EXTRA flags -#define EZT_COLOR 0x001 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.) -#define EZT_FLIP 0x002 // Reversed gravity -#define EZT_SCALE 0x004 // Changed size -#define EZT_HIT 0x008 // Damaged a mobj -#define EZT_SPRITE 0x010 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) -#define EZT_KART 0x020 // Changed current held item/quantity and bumpers for battle -#define EZT_IRONMAN 0x040 // Changed object skin +// GZT_EXTRA flags (currently UINT8) +#define EZT_COLOR 0x01 // Changed color (Super transformation, Mario fireflowers/invulnerability, etc.) +#define EZT_FLIP 0x02 // Reversed gravity +#define EZT_SCALE 0x04 // Changed size +#define EZT_HIT 0x08 // Damaged a mobj +#define EZT_SPRITE 0x10 // Changed sprite set completely out of PLAY (NiGHTS, SOCs, whatever) +#define EZT_ITEMDATA 0x20 // Changed current held item/quantity and bumpers for battle +#define EZT_STATDATA 0x40 // Changed skin/stats // GZT_FOLLOW flags #define FZT_SPAWNED 0x01 // just been spawned @@ -352,9 +354,9 @@ void G_ReadDemoExtraData(void) SetPlayerSkinByNum(p, demo.skinlist[skinid].mapping); demo.currentskinid[p] = skinid; - players[p].kartspeed = demo.skinlist[skinid].kartspeed; - players[p].kartweight = demo.skinlist[skinid].kartweight; - players[p].charflags = demo.skinlist[skinid].flags; + players[p].kartspeed = ghostext[p].kartspeed = demo.skinlist[skinid].kartspeed; + players[p].kartweight = ghostext[p].kartweight = demo.skinlist[skinid].kartweight; + players[p].charflags = ghostext[p].charflags = demo.skinlist[skinid].flags; } if (extradata & DXD_COLOR) { @@ -835,23 +837,29 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) } if (ghost->player && ( - ghostext[playernum].kartitem != ghost->player->itemtype || - ghostext[playernum].kartamount != ghost->player->itemamount || - ghostext[playernum].kartbumpers != ghost->player->bumpers + ghostext[playernum].itemtype != ghost->player->itemtype || + ghostext[playernum].itemamount != ghost->player->itemamount || + ghostext[playernum].bumpers != ghost->player->bumpers )) { - ghostext[playernum].flags |= EZT_KART; - ghostext[playernum].kartitem = ghost->player->itemtype; - ghostext[playernum].kartamount = ghost->player->itemamount; - ghostext[playernum].kartbumpers = ghost->player->bumpers; + ghostext[playernum].flags |= EZT_ITEMDATA; + ghostext[playernum].itemtype = ghost->player->itemtype; + ghostext[playernum].itemamount = ghost->player->itemamount; + ghostext[playernum].bumpers = ghost->player->bumpers; } if (ghost->player && ( - ghostext[playernum].skinid != (UINT8)(((skin_t *)ghost->skin)-skins) + ghostext[playernum].skinid != (UINT8)(((skin_t *)ghost->skin)-skins) || + ghostext[playernum].kartspeed != ghost->player->kartspeed || + ghostext[playernum].kartweight != ghost->player->kartweight || + ghostext[playernum].charflags != ghost->player->charflags )) { - ghostext[playernum].flags |= EZT_IRONMAN; + ghostext[playernum].flags |= EZT_STATDATA; ghostext[playernum].skinid = (UINT8)(((skin_t *)ghost->skin)-skins); + ghostext[playernum].kartspeed = ghost->player->kartspeed; + ghostext[playernum].kartweight = ghost->player->kartweight; + ghostext[playernum].charflags = ghost->player->charflags; } if (ghostext[playernum].flags) @@ -895,14 +903,19 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) } if (ghostext[playernum].flags & EZT_SPRITE) WRITEUINT16(demo_p,oldghost[playernum].sprite); - if (ghostext[playernum].flags & EZT_KART) + if (ghostext[playernum].flags & EZT_ITEMDATA) { - WRITEINT32(demo_p, ghostext[playernum].kartitem); - WRITEINT32(demo_p, ghostext[playernum].kartamount); - WRITEINT32(demo_p, ghostext[playernum].kartbumpers); + WRITESINT8(demo_p, ghostext[playernum].itemtype); + WRITEUINT8(demo_p, ghostext[playernum].itemamount); + WRITEUINT8(demo_p, ghostext[playernum].bumpers); } - if (ghostext[playernum].flags & EZT_IRONMAN) + if (ghostext[playernum].flags & EZT_STATDATA) + { WRITEUINT8(demo_p,ghostext[playernum].skinid); + WRITEUINT8(demo_p,ghostext[playernum].kartspeed); + WRITEUINT8(demo_p,ghostext[playernum].kartweight); + WRITEUINT32(demo_p, ghostext[playernum].charflags); + } ghostext[playernum].flags = 0; } @@ -1073,17 +1086,20 @@ void G_ConsGhostTic(INT32 playernum) } if (xziptic & EZT_SPRITE) demo_p += sizeof(UINT16); - if (xziptic & EZT_KART) + if (xziptic & EZT_ITEMDATA) { - ghostext[playernum].kartitem = READINT32(demo_p); - ghostext[playernum].kartamount = READINT32(demo_p); - ghostext[playernum].kartbumpers = READINT32(demo_p); + ghostext[playernum].itemtype = READSINT8(demo_p); + ghostext[playernum].itemamount = READUINT8(demo_p); + ghostext[playernum].bumpers = READUINT8(demo_p); } - if (xziptic & EZT_IRONMAN) + if (xziptic & EZT_STATDATA) { ghostext[playernum].skinid = READUINT8(demo_p); if (ghostext[playernum].skinid >= demo.numskins) ghostext[playernum].skinid = 0; + ghostext[playernum].kartspeed = READUINT8(demo_p); + ghostext[playernum].kartweight = READUINT8(demo_p); + ghostext[playernum].charflags = READUINT32(demo_p); } } @@ -1142,29 +1158,33 @@ void G_ConsGhostTic(INT32 playernum) else ghostext[playernum].desyncframes = 0; - if (players[playernum].itemtype != ghostext[playernum].kartitem - || players[playernum].itemamount != ghostext[playernum].kartamount - || players[playernum].bumpers != ghostext[playernum].kartbumpers) + if (players[playernum].itemtype != ghostext[playernum].itemtype + || players[playernum].itemamount != ghostext[playernum].itemamount + || players[playernum].bumpers != ghostext[playernum].bumpers) { if (demosynced) CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (item/bumpers)!\n")); demosynced = false; - players[playernum].itemtype = ghostext[playernum].kartitem; - players[playernum].itemamount = ghostext[playernum].kartamount; - players[playernum].bumpers = ghostext[playernum].kartbumpers; + players[playernum].itemtype = ghostext[playernum].itemtype; + players[playernum].itemamount = ghostext[playernum].itemamount; + players[playernum].bumpers = ghostext[playernum].bumpers; } - if (demo.skinlist[ghostext[playernum].skinid].mapping != (UINT8)(((skin_t *)testmo->skin)-skins)) + if (players[playernum].kartspeed != ghostext[playernum].kartspeed + || players[playernum].kartweight != ghostext[playernum].kartweight + || players[playernum].charflags != ghostext[playernum].charflags || + demo.skinlist[ghostext[playernum].skinid].mapping != (UINT8)(((skin_t *)testmo->skin)-skins)) { if (demosynced) - CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (Character)!\n")); + CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced (Character/stats)!\n")); demosynced = false; testmo->skin = &skins[demo.skinlist[ghostext[playernum].skinid].mapping]; - players[playernum].kartspeed = demo.skinlist[ghostext[playernum].skinid].kartspeed; - players[playernum].kartweight = demo.skinlist[ghostext[playernum].skinid].kartweight; - players[playernum].charflags = demo.skinlist[ghostext[playernum].skinid].flags; + players[playernum].kartspeed = ghostext[playernum].kartspeed; + players[playernum].kartweight = ghostext[playernum].kartweight; + players[playernum].charflags = ghostext[playernum].charflags; + } } @@ -1332,14 +1352,15 @@ void G_GhostTicker(void) } if (xziptic & EZT_SPRITE) g->mo->sprite = READUINT16(g->p); - if (xziptic & EZT_KART) - g->p += 12; // kartitem, kartamount, kartbumpers - if (xziptic & EZT_IRONMAN) + if (xziptic & EZT_ITEMDATA) + g->p += 3; // itemtype, itemamount, bumpers + if (xziptic & EZT_STATDATA) { UINT8 skinid = READUINT8(g->p); if (skinid >= g->numskins) skinid = 0; g->mo->skin = &skins[g->skinlist[skinid].mapping]; + g->p += 6; // kartspeed, kartweight, charflags } } @@ -2475,6 +2496,9 @@ void G_BeginRecording(void) ghostext[i].lastcolor = ghostext[i].color = GHC_NORMAL; ghostext[i].lastscale = ghostext[i].scale = FRACUNIT; ghostext[i].skinid = players[i].skin; + ghostext[i].kartspeed = players[i].kartspeed; + ghostext[i].kartweight = players[i].kartweight; + ghostext[i].charflags = players[i].charflags; if (players[i].mo) { @@ -3356,9 +3380,9 @@ void G_DoPlayDemo(char *defdemoname) // Set saved attribute values // No cheat checking here, because even if they ARE wrong... // it would only break the replay if we clipped them. - players[p].kartspeed = demo.skinlist[demo.currentskinid[p]].kartspeed; - players[p].kartweight = demo.skinlist[demo.currentskinid[p]].kartweight; - players[p].charflags = demo.skinlist[demo.currentskinid[p]].flags; + players[p].kartspeed = ghostext[p].kartspeed = demo.skinlist[demo.currentskinid[p]].kartspeed; + players[p].kartweight = ghostext[p].kartweight = demo.skinlist[demo.currentskinid[p]].kartweight; + players[p].charflags = ghostext[p].charflags = demo.skinlist[demo.currentskinid[p]].flags; players[p].lastfakeskin = lastfakeskin[p]; } From c2183a626c63d12eb578d67ce4be649813d35bec Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Nov 2022 18:03:27 +0000 Subject: [PATCH 47/67] Actually track lastfakeskin! Tremendous whoopsie: turns out there's no code that actually saves it outside of netsync. This is now fixed. Also now allows you to roll Eggman as your first skin, and doesn't cause immediate characterswaps for midgame joiners. --- src/d_clisrv.c | 1 + src/g_demo.c | 8 ++++++++ src/r_skins.c | 7 ++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f826519a2..6ce85db27 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2551,6 +2551,7 @@ void CL_ClearPlayer(INT32 playernum) memset(&players[playernum], 0, sizeof (player_t)); players[playernum].followerskin = -1; // don't have a ghost follower + players[playernum].fakeskin = players[playernum].lastfakeskin = MAXSKINS; // don't avoid eggman RemoveAdminPlayer(playernum); // don't stay admin after you're gone } diff --git a/src/g_demo.c b/src/g_demo.c index dc816856f..8566a4c22 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1185,6 +1185,14 @@ void G_ConsGhostTic(INT32 playernum) players[playernum].kartweight = ghostext[playernum].kartweight; players[playernum].charflags = ghostext[playernum].charflags; + if (demo.skinlist[demo.currentskinid[playernum]].flags & SF_IRONMAN) + { + players[playernum].lastfakeskin = players[playernum].fakeskin; + players[playernum].fakeskin = + (ghostext[playernum].skinid == demo.currentskinid[playernum]) + ? MAXSKINS + : ghostext[playernum].skinid; + } } } diff --git a/src/r_skins.c b/src/r_skins.c index db1e81345..9779fdcfc 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -339,7 +339,12 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) // Set mo skin but not player_t skin, for ironman void SetFakePlayerSkin(player_t* player, INT32 skinid) { - player->fakeskin = skinid; + if (player->fakeskin != skinid) + { + if (player->fakeskin != MAXSKINS) + player->lastfakeskin = player->fakeskin; + player->fakeskin = skinid; + } if (demo.playback) { From 86813b96a3cceea936cd9a5f0016fa7ba1719de8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 23 Nov 2022 18:11:50 +0000 Subject: [PATCH 48/67] Adjust how properties are handled in G_PlayerReborn a little. For consistency, all conditionals are done when data is being preserved in local variables, not on write back to player struct. --- src/g_game.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 5e722fe4f..7dd33fec3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2286,12 +2286,22 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) skincolor = players[player].skincolor; skin = players[player].skin; - fakeskin = players[player].fakeskin; - lastfakeskin = players[player].lastfakeskin; - // SRB2kart - kartspeed = players[player].kartspeed; - kartweight = players[player].kartweight; + if (betweenmaps) + { + fakeskin = MAXSKINS; + kartspeed = skins[players[player].skin].kartspeed; + kartweight = skins[players[player].skin].kartweight; + charflags = skins[players[player].skin].flags; + } + else + { + fakeskin = players[player].fakeskin; + kartspeed = players[player].kartspeed; + kartweight = players[player].kartweight; + charflags = players[player].charflags; + } + lastfakeskin = players[player].lastfakeskin; followerready = players[player].followerready; followercolor = players[player].followercolor; @@ -2299,8 +2309,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) availabilities = players[player].availabilities; - charflags = players[player].charflags; - followitem = players[player].followitem; bot = players[player].bot; @@ -2417,10 +2425,13 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) // save player config truth reborn p->skincolor = skincolor; p->skin = skin; + + p->fakeskin = fakeskin; p->kartspeed = kartspeed; p->kartweight = kartweight; - // p->charflags = charflags; + p->lastfakeskin = lastfakeskin; + p->availabilities = availabilities; p->followitem = followitem; @@ -2441,19 +2452,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->botvars.rival = botrival; p->xtralife = xtralife; - if (betweenmaps) - { - p->fakeskin = MAXSKINS; - p->kartspeed = skins[p->skin].kartspeed; - p->kartweight = skins[p->skin].kartweight; - } - else - { - p->fakeskin = fakeskin; - } - - p->lastfakeskin = lastfakeskin; - // SRB2kart p->itemroulette = itemroulette; p->roulettetype = roulettetype; From db95e3144d1fe8e59b294d0319ec46e9783f96ef Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 25 Nov 2022 17:59:18 +0000 Subject: [PATCH 49/67] Re-add mid-game rankings - gc_rankings, bound to TAB by default - Now a toggle, rather than a hold behaviour - Rearrange HU_Drawer to have chat (and cecho/music credits) render over everything else (like, say, tab rankings) - Update PROFILEVER to 2 so we can add the new control to old profiles --- src/g_input.c | 27 +++++++------- src/g_input.h | 1 + src/hu_stuff.c | 92 +++++++++++++++++++++--------------------------- src/k_menudef.c | 3 ++ src/k_profiles.c | 16 +++++++-- src/k_profiles.h | 2 +- 6 files changed, 73 insertions(+), 68 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 9fbf89bf0..08d7ab2ed 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -525,19 +525,20 @@ void G_DefineDefaultControls(void) { // These defaults are bad & temporary. // Keyboard controls - gamecontroldefault[gc_up ][0] = KEY_UPARROW; - gamecontroldefault[gc_down ][0] = KEY_DOWNARROW; - gamecontroldefault[gc_left ][0] = KEY_LEFTARROW; - gamecontroldefault[gc_right][0] = KEY_RIGHTARROW; - gamecontroldefault[gc_a ][0] = 'z'; - gamecontroldefault[gc_b ][0] = 'x'; - gamecontroldefault[gc_c ][0] = 'c'; - gamecontroldefault[gc_x ][0] = 'a'; - gamecontroldefault[gc_y ][0] = 's'; - gamecontroldefault[gc_z ][0] = 'd'; - gamecontroldefault[gc_l ][0] = 'q'; - gamecontroldefault[gc_r ][0] = 'e'; - gamecontroldefault[gc_start][0] = KEY_ESCAPE; // * + gamecontroldefault[gc_up ][0] = KEY_UPARROW; + gamecontroldefault[gc_down ][0] = KEY_DOWNARROW; + gamecontroldefault[gc_left ][0] = KEY_LEFTARROW; + gamecontroldefault[gc_right ][0] = KEY_RIGHTARROW; + gamecontroldefault[gc_a ][0] = 'z'; + gamecontroldefault[gc_b ][0] = 'x'; + gamecontroldefault[gc_c ][0] = 'c'; + gamecontroldefault[gc_x ][0] = 'a'; + gamecontroldefault[gc_y ][0] = 's'; + gamecontroldefault[gc_z ][0] = 'd'; + gamecontroldefault[gc_l ][0] = 'q'; + gamecontroldefault[gc_r ][0] = 'e'; + gamecontroldefault[gc_start ][0] = KEY_ESCAPE; // * + gamecontroldefault[gc_rankings][0] = KEY_TAB; // Gamepad controls gamecontroldefault[gc_up ][1] = KEY_HAT1+0; // D-Pad Up diff --git a/src/g_input.h b/src/g_input.h index 14aa5aba3..17ecb9281 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -78,6 +78,7 @@ typedef enum gc_console, gc_talk, gc_teamtalk, + gc_rankings, gc_screenshot, gc_recordgif, diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 3fbcddd7f..dcfc8cf78 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -980,18 +980,27 @@ static void HU_TickSongCredits(void) void HU_Ticker(void) { + static boolean hu_holdscores = false; + if (dedicated) return; hu_tick++; hu_tick &= 7; // currently only to blink chat input cursor - /* - if (PlayerInputDown(1, gc_scores)) - hu_showscores = !chat_on; + // Rankings + if (G_PlayerInputDown(0, gc_rankings, 0)) + { + if (!hu_holdscores) + { + hu_showscores ^= true; + } + hu_holdscores = true; + } else - hu_showscores = false; - */ + { + hu_holdscores = false; + } hu_keystrokes = false; @@ -2066,35 +2075,8 @@ void HU_DrawSongCredits(void) // void HU_Drawer(void) { - if (cv_vhseffect.value && (paused || (demo.playback && cv_playbackspeed.value > 1))) - V_DrawVhsEffect(demo.rewinding); - - // draw chat string plus cursor - if (chat_on) - { - if (!OLDCHAT) - HU_DrawChat(); - else - HU_DrawChat_Old(); - } - else - { - typelines = 1; - chat_scrolltime = 0; - - if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) - HU_drawMiniChat(); // draw messages in a cool fashion. - } - - if (cechotimer) - HU_DrawCEcho(); - - if (!( Playing() || demo.playback ) - || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE - || gamestate == GS_CREDITS || gamestate == GS_EVALUATION - || gamestate == GS_ENDING || gamestate == GS_GAMEEND - || gamestate == GS_VOTING || gamestate == GS_WAITINGPLAYERS) // SRB2kart - return; + if (gamestate != GS_LEVEL) + goto drawchat; // draw multiplayer rankings if (hu_showscores) @@ -2117,12 +2099,8 @@ void HU_Drawer(void) } } - if (gamestate != GS_LEVEL) - return; - - // draw song credits - if (cv_songcredits.value && !( hu_showscores && (netgame || multiplayer) )) - HU_DrawSongCredits(); + if (cv_vhseffect.value && (paused || (demo.playback && cv_playbackspeed.value > 1))) + V_DrawVhsEffect(demo.rewinding); // draw desynch text if (hu_redownloadinggamestate) @@ -2138,20 +2116,30 @@ void HU_Drawer(void) V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text); } - if (modeattacking && pausedelay > 0 && !pausebreakkey) +drawchat: + // draw chat string plus cursor + if (chat_on) { - INT32 strength = ((pausedelay - 1 - NEWTICRATE/2)*10)/(NEWTICRATE/3); - INT32 x = BASEVIDWIDTH/2, y = BASEVIDHEIGHT/2; // obviously incorrect values while we scrap hudinfo - - V_DrawThinString(x, y, - ((leveltime & 4) ? V_SKYMAP : V_BLUEMAP), - "HOLD TO RETRY..."); - - if (strength > 9) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0); - else if (strength > 0) - V_DrawFadeScreen(0, strength); + if (!OLDCHAT) + HU_DrawChat(); + else + HU_DrawChat_Old(); } + else + { + typelines = 1; + chat_scrolltime = 0; + + if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) + HU_drawMiniChat(); // draw messages in a cool fashion. + } + + if (cechotimer) + HU_DrawCEcho(); + + // draw song credits + if (cv_songcredits.value && !( hu_showscores && (netgame || multiplayer) )) + HU_DrawSongCredits(); } //====================================================================== diff --git a/src/k_menudef.c b/src/k_menudef.c index 4fb6b2262..f080ff4e5 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -653,6 +653,9 @@ menuitem_t OPTIONS_ProfileControls[] = { {IT_CONTROL, "OPEN TEAM CHAT", "Do we even have team gamemodes?", NULL, {.routine = M_ProfileSetControl}, gc_teamtalk, 0}, + {IT_CONTROL, "SHOW RANKINGS", "Show mid-game rankings.", + NULL, {.routine = M_ProfileSetControl}, gc_rankings, 0}, + {IT_CONTROL, "OPEN CONSOLE", "Opens the developer options console.", NULL, {.routine = M_ProfileSetControl}, gc_console, 0}, diff --git a/src/k_profiles.c b/src/k_profiles.c index 05cd60155..8b3712ed0 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -327,8 +327,8 @@ void PR_LoadProfiles(void) { profilesList[i] = Z_Malloc(sizeof(profile_t), PU_STATIC, NULL); - // Version. - profilesList[i]->version = version; + // Version. (We always update this on successful forward step) + profilesList[i]->version = PROFILEVER; // Names. READSTRINGN(save_p, profilesList[i]->profilename, PROFILENAMELEN); @@ -382,6 +382,18 @@ void PR_LoadProfiles(void) // Controls. for (j = 0; j < num_gamecontrols; j++) { +#ifdef DEVELOP + // Profile update 1-->2: Add gc_rankings. + if (j == gc_rankings && version < 2) + { + for (k = 0; k < MAXINPUTMAPPING; k++) + { + profilesList[i]->controls[j][k] = gamecontroldefault[j][k]; + } + continue; + } +#endif + for (k = 0; k < MAXINPUTMAPPING; k++) { profilesList[i]->controls[j][k] = READINT32(save_p); diff --git a/src/k_profiles.h b/src/k_profiles.h index 0a254bef5..961ac807b 100644 --- a/src/k_profiles.h +++ b/src/k_profiles.h @@ -27,7 +27,7 @@ #define SKINNAMESIZE 16 #define PROFILENAMELEN 6 -#define PROFILEVER 1 +#define PROFILEVER 2 #define MAXPROFILES 16 #define PROFILESFILE "ringprofiles.prf" #define PROFILE_GUEST 0 From 5b10fd8d93a0742a0d06628213e40f129ef666b4 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 25 Nov 2022 18:21:19 +0000 Subject: [PATCH 50/67] Restartlevel respects cv_kartencore --- src/d_netcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a5abda657..56eb6470f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3164,7 +3164,7 @@ static void Command_RestartLevel(void) return; } - D_MapChange(gamemap, gametype, encoremode, false, 0, false, false); + D_MapChange(gamemap, gametype, (cv_kartencore.value == 1), false, 0, false, false); } static void Command_Pause(void) From 08a9f69ed692c340646ac6b36d4a476e83f9a084 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 25 Nov 2022 22:31:55 +0000 Subject: [PATCH 51/67] Multiple BonusGame support - Comma-separated (exactly the same as levellist) - Not REQUIRED, you can still make cups with one or zero BonusGame entries - Happens every (numlevels+1)/(numbonus+1) - 5 and 2 makes after rounds 2 and 4, for example --- src/deh_soc.c | 22 +++++++++++++++++++--- src/doomstat.h | 6 ++++-- src/g_game.c | 13 ++++++++++--- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 1455f0641..f23c71970 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3095,9 +3095,25 @@ void readcupheader(MYFILE *f, cupheader_t *cup) } else if (fastcmp(word, "BONUSGAME")) { - Z_Free(cup->levellist[CUPCACHE_BONUS]); - cup->levellist[CUPCACHE_BONUS] = Z_StrDup(word2); - cup->cachedlevels[CUPCACHE_BONUS] = NEXTMAP_INVALID; + while (cup->numbonus > 0) + { + cup->numbonus--; + Z_Free(cup->levellist[CUPCACHE_BONUS + cup->numbonus]); + cup->levellist[CUPCACHE_BONUS + cup->numbonus] = NULL; + } + + tmp = strtok(word2,","); + do { + if (cup->numbonus >= MAXBONUSLIST) + { + deh_warning("%s Cup: reached max bonus list (%d)\n", cup->name, MAXBONUSLIST); + break; + } + + cup->levellist[CUPCACHE_BONUS + cup->numbonus] = Z_StrDup(tmp); + cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus] = NEXTMAP_INVALID; + cup->numbonus++; + } while((tmp = strtok(NULL,",")) != NULL); } else if (fastcmp(word, "SPECIALSTAGE")) { diff --git a/src/doomstat.h b/src/doomstat.h index bf9e7b17e..3338e9b76 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -343,8 +343,9 @@ typedef struct // Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. #define MAXLEVELLIST 5 #define CUPCACHE_BONUS MAXLEVELLIST -#define CUPCACHE_SPECIAL MAXLEVELLIST+1 -#define CUPCACHE_MAX CUPCACHE_SPECIAL+1 +#define MAXBONUSLIST 2 +#define CUPCACHE_SPECIAL (CUPCACHE_BONUS+MAXBONUSLIST) +#define CUPCACHE_MAX (CUPCACHE_SPECIAL+1) typedef struct cupheader_s { @@ -354,6 +355,7 @@ typedef struct cupheader_s char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage UINT8 numlevels; ///< Number of levels defined in levellist + UINT8 numbonus; ///< Number of bonus stages defined UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald) SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required. struct cupheader_s *next; ///< Next cup in linked list diff --git a/src/g_game.c b/src/g_game.c index db838ab91..a57ee595d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3732,11 +3732,16 @@ static void G_GetNextMap(void) else { INT32 lastgametype = gametype; + // 5 levels, 2 bonus stages: after rounds 2 and 4 (but flexible enough to accomodate other solutions) + UINT8 bonusmodulo = (grandprixinfo.cup->numlevels+1)/(grandprixinfo.cup->numbonus+1); + UINT8 bonusindex = (grandprixinfo.roundnum / bonusmodulo) - 1; // If we're in a GP event, don't immediately follow it up with another. // I also suspect this will not work with online GP so I'm gonna prevent it right now. // The server might have to communicate eventmode (alongside other GP data) in XD_MAP later. - if (netgame || grandprixinfo.eventmode != GPEVENT_NONE) + if (netgame) + ; + else if (grandprixinfo.eventmode != GPEVENT_NONE) { grandprixinfo.eventmode = GPEVENT_NONE; @@ -3774,11 +3779,13 @@ static void G_GetNextMap(void) } } } - else if (grandprixinfo.roundnum == (grandprixinfo.cup->numlevels+1)/2) // 3 for a 5-map cup + else if ((grandprixinfo.cup->numbonus > 0) + && (grandprixinfo.roundnum % bonusmodulo) == 0 + && bonusindex < MAXBONUSLIST) { // todo any other condition? { - const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS]; + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS + bonusindex]; if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] && mapheaderinfo[cupLevelNum]->typeoflevel & (TOL_BOSS|TOL_BATTLE)) { From e2be36c3439a860e47e3d1aa565b0562ba2ffd55 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 25 Nov 2022 16:05:11 -0800 Subject: [PATCH 52/67] drawpickups command to hide collectible items --- src/r_main.c | 4 ++++ src/r_main.h | 1 + src/r_things.c | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/r_main.c b/src/r_main.c index 6c1ccf299..2c781509c 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -180,6 +180,8 @@ consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons consvar_t cv_renderstats = CVAR_INIT ("renderstats", "Off", 0, CV_OnOff, NULL); +consvar_t cv_drawpickups = CVAR_INIT ("drawpickups", "Yes", CV_CHEAT, CV_YesNo, NULL); + void SplitScreen_OnChange(void) { UINT8 i; @@ -1646,4 +1648,6 @@ void R_RegisterEngineStuff(void) // Frame interpolation/uncapped CV_RegisterVar(&cv_fpscap); + + CV_RegisterVar(&cv_drawpickups); } diff --git a/src/r_main.h b/src/r_main.h index e7f5b9d4c..c3e60a0ca 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -117,6 +117,7 @@ extern consvar_t cv_drawdist, cv_drawdist_precip; extern consvar_t cv_fov[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_skybox; extern consvar_t cv_tailspickup; +extern consvar_t cv_drawpickups; // Called by startup code. void R_Init(void); diff --git a/src/r_things.c b/src/r_things.c index 41dfc8585..43470152a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -3443,6 +3443,26 @@ boolean R_ThingVisible (mobj_t *thing) if (thing->sprite == SPR_NULL) return false; + if (!cv_drawpickups.value) + { + switch (thing->type) + { + case MT_RING: + case MT_FLINGRING: + case MT_BLUESPHERE: + case MT_RANDOMITEM: + case MT_SPHEREBOX: + case MT_ITEMCAPSULE: + case MT_ITEMCAPSULE_PART: + case MT_BATTLECAPSULE: + case MT_BATTLECAPSULE_PIECE: + return false; + + default: + break; + } + } + if (r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing))) return false; From 9abb5c0e6230af2d21126f1a513406f0802c8a75 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 25 Nov 2022 16:30:11 -0800 Subject: [PATCH 53/67] Fix instances of lump searching not being case insensitive --- src/w_wad.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index e81879114..fb828cf81 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1070,16 +1070,11 @@ UINT16 W_CheckNumForMapPwad(const char *name, UINT32 hash, UINT16 wad, UINT16 st UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { UINT16 i; - static char uname[8 + 1]; - UINT32 hash; + UINT32 hash = quickncasehash(name, 8); if (!TestValidLump(wad,0)) return INT16_MAX; - strlcpy(uname, name, sizeof uname); - strupr(uname); - hash = quickncasehash(uname, 8); - // // scan forward // start at 'startlump', useful parameter when there are multiple @@ -1092,7 +1087,7 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { if (lump_p->hash != hash) continue; - if (strncmp(lump_p->name, uname, sizeof(uname) - 1)) + if (strncasecmp(lump_p->name, name, 8)) continue; return i; } @@ -1111,16 +1106,11 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump) { UINT16 i; - static char uname[256 + 1]; - UINT32 hash; + UINT32 hash = quickncasehash(name, 8); // Not a mistake, legacy system for short lumpnames if (!TestValidLump(wad,0)) return INT16_MAX; - strlcpy(uname, name, sizeof uname); - strupr(uname); - hash = quickncasehash(uname, 8); // Not a mistake, legacy system for short lumpnames - // // scan forward // start at 'startlump', useful parameter when there are multiple @@ -1133,7 +1123,7 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump) { if (lump_p->hash != hash) continue; - if (strcmp(lump_p->longname, uname)) + if (strcasecmp(lump_p->longname, name)) continue; return i; } @@ -1227,7 +1217,7 @@ lumpnum_t W_CheckNumForName(const char *name) { if (!lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8] && lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumphash == hash - && strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) + && strncasecmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) { lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); return lumpnumcache[lumpnumcacheindex].lumpnum; @@ -1282,7 +1272,7 @@ lumpnum_t W_CheckNumForLongName(const char *name) for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) { if (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumphash == hash - && strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0) + && strcasecmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0) { lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); return lumpnumcache[lumpnumcacheindex].lumpnum; From b55c67c29dddb69c36d67dfe43153cf3b9754db2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 25 Nov 2022 20:53:02 -0500 Subject: [PATCH 54/67] Add currentwaypoint --- src/d_player.h | 1 + src/k_hud.c | 3 ++- src/k_kart.c | 3 ++- src/p_saveg.c | 9 +++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index d3b6975ed..193a9d887 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -413,6 +413,7 @@ typedef struct player_s UINT8 oldposition; // Used for taunting when you pass someone UINT8 positiondelay; // Used for position number, so it can grow when passing UINT32 distancetofinish; + waypoint_t *currentwaypoint; waypoint_t *nextwaypoint; respawnvars_t respawn; // Respawn info tic_t airtime; // Keep track of how long you've been in the air diff --git a/src/k_hud.c b/src/k_hud.c index 4a5644442..37d9a2074 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4634,7 +4634,8 @@ static void K_DrawWaypointDebugger(void) if (stplyr != &players[displayplayers[0]]) // only for p1 return; - V_DrawString(8, 166, 0, va("'Best' Waypoint ID: %d", K_GetWaypointID(stplyr->nextwaypoint))); + V_DrawString(8, 156, 0, va("Current Waypoint ID: %d", K_GetWaypointID(stplyr->currentwaypoint))); + V_DrawString(8, 166, 0, va("Next Waypoint ID: %d", K_GetWaypointID(stplyr->nextwaypoint))); V_DrawString(8, 176, 0, va("Finishline Distance: %d", stplyr->distancetofinish)); if (numstarposts > 0) diff --git a/src/k_kart.c b/src/k_kart.c index 6bb2be28e..dcd1fa60b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8855,7 +8855,8 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) waypoint_t *waypoint = K_GetBestWaypointForMobj(player->mo); boolean updaterespawn = false; - bestwaypoint = waypoint; + // Our current waypoint. + player->currentwaypoint = bestwaypoint = waypoint; // check the waypoint's location in relation to the player // If it's generally in front, it's fine, otherwise, use the best next/previous waypoint. diff --git a/src/p_saveg.c b/src/p_saveg.c index c9ede8b78..65b2d81a3 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4422,6 +4422,15 @@ static void P_RelinkPointers(void) if (!P_SetTarget(&mobj->player->follower, P_FindNewPosition(temp))) CONS_Debug(DBG_GAMELOGIC, "follower not found on %d\n", mobj->type); } + if (mobj->player->currentwaypoint) + { + temp = (UINT32)(size_t)mobj->player->currentwaypoint; + mobj->player->currentwaypoint = K_GetWaypointFromIndex(temp); + if (mobj->player->currentwaypoint == NULL) + { + CONS_Debug(DBG_GAMELOGIC, "currentwaypoint not found on %d\n", mobj->type); + } + } if (mobj->player->nextwaypoint) { temp = (UINT32)(size_t)mobj->player->nextwaypoint; From d5b62886d2e22cc5d4b777ecb6cdd9b8f8ebe987 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 00:04:09 -0500 Subject: [PATCH 55/67] Change distance to finish calculation It now calculates it from a position clamped inbetween lines formed by the waypoints. --- src/k_kart.c | 153 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 18 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index dcd1fa60b..8ca23b483 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8900,20 +8900,17 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) // We're using a lot of angle calculations here, because only using facing angle or only using momentum angle both have downsides. // nextwaypoints will be picked if you're facing OR moving forward. // prevwaypoints will be picked if you're facing AND moving backward. - if ((angledelta > ANGLE_45 || momdelta > ANGLE_45) - && (finishlinehack == false)) + if ( +#if 0 + (angledelta > ANGLE_45 || momdelta > ANGLE_45) && +#endif + (finishlinehack == false) + ) { - angle_t nextbestdelta = angledelta; - angle_t nextbestmomdelta = momdelta; + angle_t nextbestdelta = ANGLE_MAX; + angle_t nextbestmomdelta = ANGLE_MAX; size_t i = 0U; - if (K_PlayerUsesBotMovement(player)) - { - // Try to force bots to use a next waypoint - nextbestdelta = ANGLE_MAX; - nextbestmomdelta = ANGLE_MAX; - } - if ((waypoint->nextwaypoints != NULL) && (waypoint->numnextwaypoints > 0U)) { for (i = 0U; i < waypoint->numnextwaypoints; i++) @@ -9151,7 +9148,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) // Player has finished, we don't need to calculate this player->distancetofinish = 0U; } - else if ((player->nextwaypoint != NULL) && (finishline != NULL)) + else if ((player->currentwaypoint != NULL) && (player->nextwaypoint != NULL) && (finishline != NULL)) { const boolean useshortcuts = false; const boolean huntbackwards = false; @@ -9165,17 +9162,137 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) // Using shortcuts won't find a path, so distance won't be updated until the player gets back on track if (pathfindsuccess == true) { - // Add euclidean distance to the next waypoint to the distancetofinish - UINT32 adddist; - fixed_t disttowaypoint = + const boolean pathBackwardsReverse = ((player->pflags & PF_WRONGWAY) == 0); + boolean pathBackwardsSuccess = false; + path_t pathBackwards = {0}; + + fixed_t disttonext = 0; + UINT32 traveldist = 0; + UINT32 adddist = 0; + + disttonext = P_AproxDistance( (player->mo->x >> FRACBITS) - (player->nextwaypoint->mobj->x >> FRACBITS), (player->mo->y >> FRACBITS) - (player->nextwaypoint->mobj->y >> FRACBITS)); - disttowaypoint = P_AproxDistance(disttowaypoint, (player->mo->z >> FRACBITS) - (player->nextwaypoint->mobj->z >> FRACBITS)); + disttonext = P_AproxDistance(disttonext, (player->mo->z >> FRACBITS) - (player->nextwaypoint->mobj->z >> FRACBITS)); - adddist = (UINT32)disttowaypoint; + traveldist = ((UINT32)disttonext) * 2; + pathBackwardsSuccess = + K_PathfindThruCircuit(player->nextwaypoint, traveldist, &pathBackwards, false, pathBackwardsReverse); - player->distancetofinish = pathtofinish.totaldist + adddist; + if (pathBackwardsSuccess == true) + { + if (pathBackwards.numnodes > 1) + { + // Find the closest segment, and add the distance to reach it. + vector3_t point; + size_t i; + + vector3_t best; + fixed_t bestPoint = INT32_MAX; + fixed_t bestDist = INT32_MAX; + UINT32 bestGScore = UINT32_MAX; + + point.x = player->mo->x; + point.y = player->mo->y; + point.z = player->mo->z; + + best.x = point.x; + best.y = point.y; + best.z = point.z; + + for (i = 1; i < pathBackwards.numnodes; i++) + { + vector3_t line[2]; + vector3_t result; + + waypoint_t *pwp = (waypoint_t *)pathBackwards.array[i - 1].nodedata; + waypoint_t *wp = (waypoint_t *)pathBackwards.array[i].nodedata; + + fixed_t pDist = 0; + UINT32 g = pathBackwards.array[i - 1].gscore; + + line[0].x = pwp->mobj->x; + line[0].y = pwp->mobj->y; + line[0].z = pwp->mobj->z; + + line[1].x = wp->mobj->x; + line[1].y = wp->mobj->y; + line[1].z = wp->mobj->z; + + P_ClosestPointOnLine3D(&point, line, &result); + + pDist = P_AproxDistance(point.x - result.x, point.y - result.y); + pDist = P_AproxDistance(pDist, point.z - result.z); + + if (pDist < bestPoint) + { + FV3_Copy(&best, &result); + + bestPoint = pDist; + + bestDist = + P_AproxDistance( + (result.x >> FRACBITS) - (line[0].x >> FRACBITS), + (result.y >> FRACBITS) - (line[0].y >> FRACBITS)); + bestDist = P_AproxDistance(bestDist, (result.z >> FRACBITS) - (line[0].z >> FRACBITS)); + + bestGScore = g + ((UINT32)bestDist); + } + } + + if (cv_kartdebugwaypoints.value) + { + mobj_t *debugmobj = P_SpawnMobj(best.x, best.y, best.z, MT_SPARK); + P_SetMobjState(debugmobj, S_WAYPOINTORB); + + debugmobj->frame &= ~FF_TRANSMASK; + debugmobj->frame |= FF_FULLBRIGHT; //FF_TRANS20 + + debugmobj->tics = 2; + debugmobj->color = SKINCOLOR_BANANA; + } + + adddist = bestGScore; + } + /* + else + { + // Only one point to work with, so just add your euclidean distance to that. + waypoint_t *wp = (waypoint_t *)pathBackwards.array[0].nodedata; + fixed_t disttowaypoint = + P_AproxDistance( + (player->mo->x >> FRACBITS) - (wp->mobj->x >> FRACBITS), + (player->mo->y >> FRACBITS) - (wp->mobj->y >> FRACBITS)); + disttowaypoint = P_AproxDistance(disttowaypoint, (player->mo->z >> FRACBITS) - (wp->mobj->z >> FRACBITS)); + + adddist = (UINT32)disttowaypoint; + } + */ + } + /* + else + { + // Fallback to adding euclidean distance to the next waypoint to the distancetofinish + adddist = (UINT32)disttonext; + } + */ + + if (pathBackwardsReverse == false) + { + if (pathtofinish.totaldist > adddist) + { + player->distancetofinish = pathtofinish.totaldist - adddist; + } + else + { + player->distancetofinish = 0; + } + } + else + { + player->distancetofinish = pathtofinish.totaldist + adddist; + } Z_Free(pathtofinish.array); // distancetofinish is currently a flat distance to the finish line, but in order to be fully From cb580031caf26e851d1b9a7bc155c348aa3b7092 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 01:26:46 -0500 Subject: [PATCH 56/67] Condense all of the P_CheckSight copy-paste For something for my next commit --- src/p_sight.c | 700 ++++++++++++++++++++++---------------------------- 1 file changed, 306 insertions(+), 394 deletions(-) diff --git a/src/p_sight.c b/src/p_sight.c index 64bba3969..50b22243d 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -27,13 +27,26 @@ // killough 4/19/98: // Convert LOS info to struct for reentrancy and efficiency of data locality -typedef struct { - fixed_t sightzstart, t2x, t2y; // eye z of looker - divline_t strace; // from t1 to t2 - fixed_t topslope, bottomslope; // slopes to top and bottom of target +typedef struct +{ + fixed_t sightzstart, t2x, t2y; // eye z of looker + divline_t strace; // from t1 to t2 + fixed_t topslope, bottomslope; // slopes to top and bottom of target fixed_t bbox[4]; + + mobj_t *compareThing; // Original thing + boolean alreadyHates; // For bot traversal, for if the bot is already in a sector it doesn't want to be } los_t; +typedef boolean (*los_valid_t)(seg_t *, divline_t *, register los_t *); +typedef boolean (*los_valid_poly_t)(polyobj_t *, divline_t *, register los_t *); + +typedef struct +{ + los_valid_t validate; // Validation function. If true, continue iterating for possible success. If false, end early with failure. + los_valid_poly_t validatePolyobj; // If not NULL, then we will also check polyobject lines using this func. +} los_funcs_t; + static INT32 sightcounts[2]; // @@ -103,23 +116,58 @@ static fixed_t P_InterceptVector2(divline_t *v2, divline_t *v1) return frac; } -static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los) +static boolean P_IsVisiblePolyObj(polyobj_t *po, divline_t *divl, register los_t *los) { - size_t i; - sector_t *polysec; + sector_t *polysec = po->lines[0]->backsector; + fixed_t frac; + fixed_t topslope, bottomslope; if (!(po->flags & POF_RENDERALL)) + { return true; // the polyobject isn't visible, so we can ignore it + } - polysec = po->lines[0]->backsector; + // stop because it is not two sided + /* + if (!(po->flags & POF_TESTHEIGHT)) + { + return false; + } + */ + + frac = P_InterceptVector2(&los->strace, divl); + + // get slopes of top and bottom of this polyobject line + topslope = FixedDiv(polysec->ceilingheight - los->sightzstart , frac); + bottomslope = FixedDiv(polysec->floorheight - los->sightzstart , frac); + + if (topslope >= los->topslope && bottomslope <= los->bottomslope) + { + // view completely blocked + return false; + } + + // TODO: figure out if it's worth considering partially blocked cases or not? + // maybe to adjust los's top/bottom slopes if needed + /* + if (los->topslope <= los->bottomslope) + { + return false; + } + */ + + return true; +} + +static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los, register los_funcs_t *funcs) +{ + size_t i; for (i = 0; i < po->numLines; ++i) { line_t *line = po->lines[i]; divline_t divl; const vertex_t *v1,*v2; - fixed_t frac; - fixed_t topslope, bottomslope; // already checked other side? if (line->validcount == validcount) @@ -150,23 +198,195 @@ static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los) P_DivlineSide(los->t2x, los->t2y, &divl)) continue; - // stop because it is not two sided - //if (!(po->flags & POF_TESTHEIGHT)) - //return false; + if (funcs->validatePolyobj(po, &divl, los) == false) + { + return false; + } + } - frac = P_InterceptVector2(&los->strace, &divl); + return true; +} - // get slopes of top and bottom of this polyobject line - topslope = FixedDiv(polysec->ceilingheight - los->sightzstart , frac); - bottomslope = FixedDiv(polysec->floorheight - los->sightzstart , frac); +static boolean P_IsVisible(seg_t *seg, divline_t *divl, register los_t *los) +{ + line_t *line = seg->linedef; + fixed_t popentop, popenbottom; + const sector_t *front, *back; + fixed_t frac; + fixed_t fracx, fracy; + fixed_t frontf, backf, frontc, backc; - if (topslope >= los->topslope && bottomslope <= los->bottomslope) - return false; // view completely blocked + // stop because it is not two sided anyway + if (!(line->flags & ML_TWOSIDED)) + { + return false; + } + // calculate fractional intercept (how far along we are divided by how far we are from t2) + frac = P_InterceptVector2(&los->strace, divl); + + front = seg->frontsector; + back = seg->backsector; + // calculate position at intercept + fracx = los->strace.x + FixedMul(los->strace.dx, frac); + fracy = los->strace.y + FixedMul(los->strace.dy, frac); + // calculate sector heights + frontf = P_GetSectorFloorZAt (front, fracx, fracy); + frontc = P_GetSectorCeilingZAt(front, fracx, fracy); + backf = P_GetSectorFloorZAt (back , fracx, fracy); + backc = P_GetSectorCeilingZAt(back , fracx, fracy); + // crosses a two sided line + // no wall to block sight with? + if (frontf == backf && frontc == backc + && !front->ffloors & !back->ffloors) // (and no FOFs) + { + return true; + } + + // possible occluder + // because of ceiling height differences + popentop = min(frontc, backc); + + // because of floor height differences + popenbottom = max(frontf, backf); + + // quick test for totally closed doors + if (popenbottom >= popentop) + { + return false; + } + + if (frontf != backf) + { + fixed_t slope = FixedDiv(popenbottom - los->sightzstart , frac); + if (slope > los->bottomslope) + los->bottomslope = slope; + } + + if (frontc != backc) + { + fixed_t slope = FixedDiv(popentop - los->sightzstart , frac); + if (slope < los->topslope) + los->topslope = slope; + } + + if (los->topslope <= los->bottomslope) + { + return false; + } + + // Monster Iestyn: check FOFs! + if (front->ffloors || back->ffloors) + { + ffloor_t *rover; + fixed_t topslope, bottomslope; + fixed_t topz, bottomz; + // check front sector's FOFs first + for (rover = front->ffloors; rover; rover = rover->next) + { + if (!(rover->fofflags & FOF_EXISTS) + || !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG))) + { + continue; + } + + topz = P_GetFFloorTopZAt (rover, fracx, fracy); + bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy); + topslope = FixedDiv( topz - los->sightzstart, frac); + bottomslope = FixedDiv(bottomz - los->sightzstart, frac); + + if (topslope >= los->topslope && bottomslope <= los->bottomslope) + { + return false; // view completely blocked + } + } + // check back sector's FOFs as well + for (rover = back->ffloors; rover; rover = rover->next) + { + if (!(rover->fofflags & FOF_EXISTS) + || !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG))) + { + continue; + } + + topz = P_GetFFloorTopZAt (rover, fracx, fracy); + bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy); + topslope = FixedDiv( topz - los->sightzstart, frac); + bottomslope = FixedDiv(bottomz - los->sightzstart, frac); + + if (topslope >= los->topslope && bottomslope <= los->bottomslope) + { + return false; // view completely blocked + } + } // TODO: figure out if it's worth considering partially blocked cases or not? // maybe to adjust los's top/bottom slopes if needed - //if (los->topslope <= los->bottomslope) - //return false; + } + + return true; +} + +static boolean P_CanTraceBlockingLine(seg_t *seg, divline_t *divl, register los_t *los) +{ + line_t *line = seg->linedef; + + (void)divl; + + if (P_IsLineBlocking(line, los->compareThing) == true) + { + // This line will always block us + return false; + } + + if (los->compareThing->player != NULL) + { + if (P_IsLineTripWire(line) == true && K_TripwirePass(los->compareThing->player) == false) + { + // Can't go through trip wire. + return false; + } + } + + return true; +} + +static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los) +{ + line_t *line = seg->linedef; + fixed_t maxstep = 0; + + if (P_CanTraceBlockingLine(seg, divl, los) == false) + { + // Blocked, so obviously can't traverse either. + return false; + } + + // set openrange, opentop, openbottom + tm.x = los->compareThing->x; + tm.y = los->compareThing->y; + P_LineOpening(line, los->compareThing); + maxstep = P_GetThingStepUp(los->compareThing, tm.x, tm.y); + + if ((openrange < los->compareThing->height) // doesn't fit + || (opentop - los->compareThing->z < los->compareThing->height) // mobj is too high + || (openbottom - los->compareThing->z > maxstep)) // too big a step up + { + // This line situationally blocks us + return false; + } + + if (los->compareThing->player != NULL && los->alreadyHates == false) + { + // Treat damage sectors like walls, if you're not already in a bad sector. + vertex_t pos; + P_ClosestPointOnLine(los->compareThing->x, los->compareThing->y, line, &pos); + + if (K_BotHatesThisSector(los->compareThing->player, line->frontsector, pos.x, pos.y) + || K_BotHatesThisSector(los->compareThing->player, line->backsector, pos.x, pos.y)) + { + // This line does not block us, but we don't want to be in it. + return false; + } } return true; @@ -177,11 +397,10 @@ static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los) // // Returns true if strace crosses the given subsector successfully. // -static boolean P_CrossSubsector(size_t num, register los_t *los) +static boolean P_CrossSubsector(size_t num, register los_t *los, register los_funcs_t *funcs) { seg_t *seg; INT32 count; - polyobj_t *po; // haleyjd 02/23/06 #ifdef RANGECHECK if (num >= numsubsectors) @@ -192,30 +411,30 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) seg = segs + subsectors[num].firstline; // haleyjd 02/23/06: check polyobject lines - if ((po = subsectors[num].polyList)) + if (funcs->validatePolyobj != NULL) { - while (po) + polyobj_t *po; + + if ((po = subsectors[num].polyList)) { - if (po->validcount != validcount) + while (po) { - po->validcount = validcount; - if (!P_CrossSubsecPolyObj(po, los)) - return false; + if (po->validcount != validcount) + { + po->validcount = validcount; + if (!P_CrossSubsecPolyObj(po, los, funcs)) + return false; + } + po = (polyobj_t *)(po->link.next); } - po = (polyobj_t *)(po->link.next); } } for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines { line_t *line = seg->linedef; + const vertex_t *v1, *v2; divline_t divl; - fixed_t popentop, popenbottom; - const sector_t *front, *back; - const vertex_t *v1,*v2; - fixed_t frac; - fixed_t frontf, backf, frontc, backc; - fixed_t fracx, fracy; if (seg->glseg) continue; @@ -249,99 +468,9 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) P_DivlineSide(los->t2x, los->t2y, &divl)) continue; - // stop because it is not two sided anyway - if (!(line->flags & ML_TWOSIDED)) - return false; - - // calculate fractional intercept (how far along we are divided by how far we are from t2) - frac = P_InterceptVector2(&los->strace, &divl); - - front = seg->frontsector; - back = seg->backsector; - // calculate position at intercept - fracx = los->strace.x + FixedMul(los->strace.dx, frac); - fracy = los->strace.y + FixedMul(los->strace.dy, frac); - // calculate sector heights - frontf = P_GetSectorFloorZAt (front, fracx, fracy); - frontc = P_GetSectorCeilingZAt(front, fracx, fracy); - backf = P_GetSectorFloorZAt (back , fracx, fracy); - backc = P_GetSectorCeilingZAt(back , fracx, fracy); - // crosses a two sided line - // no wall to block sight with? - if (frontf == backf && frontc == backc - && !front->ffloors & !back->ffloors) // (and no FOFs) - continue; - - // possible occluder - // because of ceiling height differences - popentop = min(frontc, backc); - - // because of floor height differences - popenbottom = max(frontf, backf); - - // quick test for totally closed doors - if (popenbottom >= popentop) - return false; - - if (frontf != backf) + if (funcs->validate(seg, &divl, los) == false) { - fixed_t slope = FixedDiv(popenbottom - los->sightzstart , frac); - if (slope > los->bottomslope) - los->bottomslope = slope; - } - - if (frontc != backc) - { - fixed_t slope = FixedDiv(popentop - los->sightzstart , frac); - if (slope < los->topslope) - los->topslope = slope; - } - - if (los->topslope <= los->bottomslope) return false; - - // Monster Iestyn: check FOFs! - if (front->ffloors || back->ffloors) - { - ffloor_t *rover; - fixed_t topslope, bottomslope; - fixed_t topz, bottomz; - // check front sector's FOFs first - for (rover = front->ffloors; rover; rover = rover->next) - { - if (!(rover->fofflags & FOF_EXISTS) - || !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG))) - { - continue; - } - - topz = P_GetFFloorTopZAt (rover, fracx, fracy); - bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy); - topslope = FixedDiv( topz - los->sightzstart, frac); - bottomslope = FixedDiv(bottomz - los->sightzstart, frac); - - if (topslope >= los->topslope && bottomslope <= los->bottomslope) - return false; // view completely blocked - } - // check back sector's FOFs as well - for (rover = back->ffloors; rover; rover = rover->next) - { - if (!(rover->fofflags & FOF_EXISTS) - || !(rover->fofflags & FOF_RENDERSIDES) || (rover->fofflags & (FOF_TRANSLUCENT|FOF_FOG))) - { - continue; - } - - topz = P_GetFFloorTopZAt (rover, fracx, fracy); - bottomz = P_GetFFloorBottomZAt(rover, fracx, fracy); - topslope = FixedDiv( topz - los->sightzstart, frac); - bottomslope = FixedDiv(bottomz - los->sightzstart, frac); - - if (topslope >= los->topslope && bottomslope <= los->bottomslope) - return false; // view completely blocked - } - // TODO: figure out if it's worth considering partially blocked cases or not? - // maybe to adjust los's top/bottom slopes if needed } } @@ -356,24 +485,32 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) // // killough 4/20/98: rewritten to remove tail recursion, clean up, and optimize -static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los) +static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los, register los_funcs_t *funcs) { + if (funcs->validate == NULL) + { + return false; + } + while (!(bspnum & NF_SUBSECTOR)) { register node_t *bsp = nodes + bspnum; - INT32 side = P_DivlineSide(los->strace.x,los->strace.y,(divline_t *)bsp)&1; + INT32 side = P_DivlineSide(los->strace.x, los->strace.y, (divline_t *)bsp) & 1; + if (side == P_DivlineSide(los->t2x, los->t2y, (divline_t *) bsp)) + { bspnum = bsp->children[side]; // doesn't touch the other side + } else // the partition plane is crossed here { - if (!P_CrossBSPNode(bsp->children[side], los)) - return 0; // cross the starting side + if (!P_CrossBSPNode(bsp->children[side], los, funcs)) + return false; // cross the starting side else - bspnum = bsp->children[side^1]; // cross the ending side + bspnum = bsp->children[side ^ 1]; // cross the ending side } } - return - P_CrossSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), los); + + return P_CrossSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), los, funcs); } // @@ -387,6 +524,7 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) const sector_t *s1, *s2; size_t pnum; los_t los; + los_funcs_t funcs; // First check for trivial rejection. if (!t1 || !t2) @@ -423,6 +561,9 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) validcount++; + los.compareThing = t1; + los.alreadyHates = false; + los.topslope = (los.bottomslope = t2->z - (los.sightzstart = t1->z + t1->height - @@ -498,127 +639,19 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) } } + funcs.validate = &P_IsVisible; + funcs.validatePolyobj = &P_IsVisiblePolyObj; + // the head node is the last node output - return P_CrossBSPNode((INT32)numnodes - 1, &los); -} - -// -// P_TraceBlockingLines -// -// Returns true if a straight line between t1 and t2 is unobstructed. -// Unlike P_CheckSight, simplifed down to only check for explicit blocking lines on the 2D plane. -// Intended for Kart waypoints. -// Might be better in it's own file? -// - -typedef struct { - fixed_t t2x, t2y; - divline_t strace; // from t1 to t2 - fixed_t bbox[4]; - mobj_t *compareThing; - boolean alreadyHates; -} traceblocking_t; - -static boolean P_CrossBlockingSubsector(size_t num, register traceblocking_t *tb) -{ - seg_t *seg; - INT32 count; - -#ifdef RANGECHECK - if (num >= numsubsectors) - I_Error("P_CrossBlockingSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); -#endif - - // haleyjd 02/23/06: this assignment should be after the above check - seg = segs + subsectors[num].firstline; - - for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines - { - line_t *line = seg->linedef; - divline_t divl; - const vertex_t *v1,*v2; - - if (seg->glseg) - continue; - - // already checked other side? - if (line->validcount == validcount) - continue; - - line->validcount = validcount; - - // OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test - if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] || - line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] || - line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] || - line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM]) - continue; - - v1 = line->v1; - v2 = line->v2; - - // line isn't crossed? - if (P_DivlineSide(v1->x, v1->y, &tb->strace) == - P_DivlineSide(v2->x, v2->y, &tb->strace)) - continue; - - // stop because it is not two sided anyway - if (!(line->flags & ML_TWOSIDED)) - return false; - - divl.dx = v2->x - (divl.x = v1->x); - divl.dy = v2->y - (divl.y = v1->y); - - // line isn't crossed? - if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) == - P_DivlineSide(tb->t2x, tb->t2y, &divl)) - continue; - - if (P_IsLineBlocking(line, tb->compareThing) == true) - { - // This line will always block us - return false; - } - - if (tb->compareThing->player != NULL) - { - if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false) - { - // Can't go through trip wire. - return false; - } - } - } - - // passed the subsector ok - return true; -} - -static boolean P_CrossBSPNodeBlocking(INT32 bspnum, register traceblocking_t *tb) -{ - while (!(bspnum & NF_SUBSECTOR)) - { - register node_t *bsp = nodes + bspnum; - INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1; - if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp)) - bspnum = bsp->children[side]; // doesn't touch the other side - else // the partition plane is crossed here - { - if (!P_CrossBSPNodeBlocking(bsp->children[side], tb)) - return false; // cross the starting side - else - bspnum = bsp->children[side^1]; // cross the ending side - } - } - - return P_CrossBlockingSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb); + return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); } boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2) { const sector_t *s1, *s2; size_t pnum; - traceblocking_t tb; + los_t los; + los_funcs_t funcs; // First check for trivial rejection. if (!t1 || !t2) @@ -651,161 +684,38 @@ boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2) validcount++; - tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x); - tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y); + los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); + los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); if (t1->x > t2->x) - tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x; + los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; else - tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x; + los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; if (t1->y > t2->y) - tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y; + los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; else - tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y; + los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; - tb.compareThing = t1; - tb.alreadyHates = false; + los.compareThing = t1; + los.alreadyHates = false; + + funcs.validate = &P_CanTraceBlockingLine; // the head node is the last node output - return P_CrossBSPNodeBlocking((INT32)numnodes - 1, &tb); + return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); } // // ANOTHER version, this time for bot traversal. -// (TODO: since we have so many versions of this function, the differences -// should maybe just be a function var that gets called?) // -static boolean P_CrossBotTraversalSubsector(size_t num, register traceblocking_t *tb) -{ - seg_t *seg; - INT32 count; - -#ifdef RANGECHECK - if (num >= numsubsectors) - I_Error("P_CrossBotTraversalSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); -#endif - - // haleyjd 02/23/06: this assignment should be after the above check - seg = segs + subsectors[num].firstline; - - for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines - { - line_t *line = seg->linedef; - divline_t divl; - const vertex_t *v1,*v2; - fixed_t maxstep = INT32_MAX; - - if (seg->glseg) - continue; - - // already checked other side? - if (line->validcount == validcount) - continue; - - line->validcount = validcount; - - // OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test - if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] || - line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] || - line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] || - line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM]) - continue; - - v1 = line->v1; - v2 = line->v2; - - // line isn't crossed? - if (P_DivlineSide(v1->x, v1->y, &tb->strace) == - P_DivlineSide(v2->x, v2->y, &tb->strace)) - continue; - - // stop because it is not two sided anyway - if (!(line->flags & ML_TWOSIDED)) - return false; - - divl.dx = v2->x - (divl.x = v1->x); - divl.dy = v2->y - (divl.y = v1->y); - - // line isn't crossed? - if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) == - P_DivlineSide(tb->t2x, tb->t2y, &divl)) - continue; - - if (P_IsLineBlocking(line, tb->compareThing) == true) - { - // This line will always block us - return false; - } - - if (tb->compareThing->player != NULL) - { - if (P_IsLineTripWire(line) == true && K_TripwirePass(tb->compareThing->player) == false) - { - // Can't go through trip wire. - return false; - } - } - - // set openrange, opentop, openbottom - tm.x = tb->compareThing->x; - tm.y = tb->compareThing->y; - P_LineOpening(line, tb->compareThing); - maxstep = P_GetThingStepUp(tb->compareThing, tm.x, tm.y); - - if ((openrange < tb->compareThing->height) // doesn't fit - || (opentop - tb->compareThing->z < tb->compareThing->height) // mobj is too high - || (openbottom - tb->compareThing->z > maxstep)) // too big a step up - { - // This line situationally blocks us - return false; - } - - if (tb->compareThing->player != NULL && tb->alreadyHates == false) - { - // Treat damage sectors like walls, if you're not already in a bad sector. - vertex_t pos; - P_ClosestPointOnLine(tb->compareThing->x, tb->compareThing->y, line, &pos); - - if (K_BotHatesThisSector(tb->compareThing->player, line->frontsector, pos.x, pos.y) - || K_BotHatesThisSector(tb->compareThing->player, line->backsector, pos.x, pos.y)) - { - // This line does not block us, but we don't want to be in it. - return false; - } - } - } - - // passed the subsector ok - return true; -} - -static boolean P_CrossBSPNodeBotTraversal(INT32 bspnum, register traceblocking_t *tb) -{ - while (!(bspnum & NF_SUBSECTOR)) - { - register node_t *bsp = nodes + bspnum; - INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1; - if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp)) - bspnum = bsp->children[side]; // doesn't touch the other side - else // the partition plane is crossed here - { - if (!P_CrossBSPNodeBotTraversal(bsp->children[side], tb)) - return false; // cross the starting side - else - bspnum = bsp->children[side^1]; // cross the ending side - } - } - - return P_CrossBotTraversalSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb); -} - boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2) { const sector_t *s1, *s2; size_t pnum; - traceblocking_t tb; + los_t los; + los_funcs_t funcs; // First check for trivial rejection. if (!t1 || !t2) @@ -838,33 +748,35 @@ boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2) validcount++; - tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x); - tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y); + los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); + los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); if (t1->x > t2->x) - tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x; + los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; else - tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x; + los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; if (t1->y > t2->y) - tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y; + los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; else - tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y; + los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; - tb.compareThing = t1; + los.compareThing = t1; if (t1->player != NULL) { - tb.alreadyHates = K_BotHatesThisSector( + los.alreadyHates = K_BotHatesThisSector( t1->player, t1->subsector->sector, t1->x, t1->y ); } else { - tb.alreadyHates = false; + los.alreadyHates = false; } + funcs.validate = &P_CanBotTraverse; + // the head node is the last node output - return P_CrossBSPNodeBotTraversal((INT32)numnodes - 1, &tb); + return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); } From 0053cda35c9f1b79d3352e5d2e4b02603a9e677c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 02:31:11 -0500 Subject: [PATCH 57/67] Don't allow nextwaypoint to be past finish linedef --- src/k_kart.c | 121 +++++++---------------------------------------- src/k_waypoint.c | 4 +- src/p_local.h | 1 + src/p_sight.c | 79 +++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 107 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 8ca23b483..3fd42d6bf 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8848,6 +8848,7 @@ void K_KartPlayerAfterThink(player_t *player) --------------------------------------------------*/ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) { + waypoint_t *finishline = K_GetFinishLineWaypoint(); waypoint_t *bestwaypoint = NULL; if ((player != NULL) && (player->mo != NULL) && (P_MobjWasRemoved(player->mo) == false)) @@ -8864,13 +8865,15 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) // Otherwise it breaks the distance calculations. if (waypoint != NULL) { - boolean finishlinehack = false; angle_t playerangle = player->mo->angle; angle_t momangle = K_MomentumAngle(player->mo); angle_t angletowaypoint = R_PointToAngle2(player->mo->x, player->mo->y, waypoint->mobj->x, waypoint->mobj->y); - angle_t angledelta = ANGLE_MAX; - angle_t momdelta = ANGLE_MAX; + angle_t angledelta = ANGLE_180; + angle_t momdelta = ANGLE_180; + + // Remove WRONG WAY flag. + player->pflags &= ~PF_WRONGWAY; angledelta = playerangle - angletowaypoint; if (angledelta > ANGLE_180) @@ -8884,31 +8887,15 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) momdelta = InvAngle(momdelta); } - if (bestwaypoint == K_GetFinishLineWaypoint()) - { - waypoint_t *nextwaypoint = waypoint->nextwaypoints[0]; - angle_t angletonextwaypoint = - R_PointToAngle2(waypoint->mobj->x, waypoint->mobj->y, nextwaypoint->mobj->x, nextwaypoint->mobj->y); - - // facing towards the finishline - if (AngleDelta(angletonextwaypoint, angletowaypoint) <= ANGLE_90) - { - finishlinehack = true; - } - } - // We're using a lot of angle calculations here, because only using facing angle or only using momentum angle both have downsides. // nextwaypoints will be picked if you're facing OR moving forward. // prevwaypoints will be picked if you're facing AND moving backward. - if ( #if 0 - (angledelta > ANGLE_45 || momdelta > ANGLE_45) && + if (angledelta > ANGLE_45 || momdelta > ANGLE_45) #endif - (finishlinehack == false) - ) { - angle_t nextbestdelta = ANGLE_MAX; - angle_t nextbestmomdelta = ANGLE_MAX; + angle_t nextbestdelta = ANGLE_90; + angle_t nextbestmomdelta = ANGLE_90; size_t i = 0U; if ((waypoint->nextwaypoints != NULL) && (waypoint->numnextwaypoints > 0U)) @@ -8952,10 +8939,13 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) if (angledelta < nextbestdelta || momdelta < nextbestmomdelta) { - if (P_TraceBlockingLines(player->mo, waypoint->nextwaypoints[i]->mobj) == false) + if (waypoint->nextwaypoints[i] != finishline) // Allow finish line. { - // Save sight checks when all of the other checks pass, so we only do it if we have to - continue; + if (P_TraceWaypointTraversal(player->mo, waypoint->nextwaypoints[i]->mobj) == false) + { + // Save sight checks when all of the other checks pass, so we only do it if we have to + continue; + } } bestwaypoint = waypoint->nextwaypoints[i]; @@ -8969,8 +8959,6 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) nextbestmomdelta = momdelta; } - // Remove wrong way flag if we're using nextwaypoints - player->pflags &= ~PF_WRONGWAY; updaterespawn = true; } } @@ -9004,7 +8992,7 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) if (angledelta < nextbestdelta && momdelta < nextbestmomdelta) { - if (P_TraceBlockingLines(player->mo, waypoint->prevwaypoints[i]->mobj) == false) + if (P_TraceWaypointTraversal(player->mo, waypoint->prevwaypoints[i]->mobj) == false) { // Save sight checks when all of the other checks pass, so we only do it if we have to continue; @@ -9044,69 +9032,6 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) return bestwaypoint; } -#if 0 -static boolean K_PlayerCloserToNextWaypoints(waypoint_t *const waypoint, player_t *const player) -{ - boolean nextiscloser = true; - - if ((waypoint != NULL) && (player != NULL) && (player->mo != NULL)) - { - size_t i = 0U; - waypoint_t *currentwpcheck = NULL; - angle_t angletoplayer = ANGLE_MAX; - angle_t currentanglecheck = ANGLE_MAX; - angle_t bestangle = ANGLE_MAX; - - angletoplayer = R_PointToAngle2(waypoint->mobj->x, waypoint->mobj->y, - player->mo->x, player->mo->y); - - for (i = 0U; i < waypoint->numnextwaypoints; i++) - { - currentwpcheck = waypoint->nextwaypoints[i]; - currentanglecheck = R_PointToAngle2( - waypoint->mobj->x, waypoint->mobj->y, currentwpcheck->mobj->x, currentwpcheck->mobj->y); - - // Get delta angle - currentanglecheck = currentanglecheck - angletoplayer; - - if (currentanglecheck > ANGLE_180) - { - currentanglecheck = InvAngle(currentanglecheck); - } - - if (currentanglecheck < bestangle) - { - bestangle = currentanglecheck; - } - } - - for (i = 0U; i < waypoint->numprevwaypoints; i++) - { - currentwpcheck = waypoint->prevwaypoints[i]; - currentanglecheck = R_PointToAngle2( - waypoint->mobj->x, waypoint->mobj->y, currentwpcheck->mobj->x, currentwpcheck->mobj->y); - - // Get delta angle - currentanglecheck = currentanglecheck - angletoplayer; - - if (currentanglecheck > ANGLE_180) - { - currentanglecheck = InvAngle(currentanglecheck); - } - - if (currentanglecheck < bestangle) - { - bestangle = currentanglecheck; - nextiscloser = false; - break; - } - } - } - - return nextiscloser; -} -#endif - /*-------------------------------------------------- void K_UpdateDistanceFromFinishLine(player_t *const player) @@ -9302,21 +9227,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) == 0U) { const UINT8 numfulllapsleft = ((UINT8)numlaps - player->laps); - player->distancetofinish += numfulllapsleft * K_GetCircuitLength(); - -#if 0 - // An additional HACK, to fix looking backwards towards the finish line - // If the player's next waypoint is the finishline and the angle distance from player to - // connectin waypoints implies they're closer to a next waypoint, add a full track distance - if (player->nextwaypoint == finishline) - { - if (K_PlayerCloserToNextWaypoints(player->nextwaypoint, player) == true) - { - player->distancetofinish += K_GetCircuitLength(); - } - } -#endif } } } diff --git a/src/k_waypoint.c b/src/k_waypoint.c index 28ff00d04..837f77102 100644 --- a/src/k_waypoint.c +++ b/src/k_waypoint.c @@ -361,7 +361,7 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj) // remember: huge radius if (closestdist <= rad && checkdist <= rad && finishline != NULL) { - if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj)) + if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj)) // Intentionally not P_TraceWaypointTraversal { // Save sight checks when all of the other checks pass, so we only do it if we have to continue; @@ -379,7 +379,7 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj) } else if (checkdist < closestdist && bestfindist == INT32_MAX) { - if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj)) + if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj)) // Intentionally not P_TraceWaypointTraversal { // Save sight checks when all of the other checks pass, so we only do it if we have to continue; diff --git a/src/p_local.h b/src/p_local.h index 1042f1193..9bc92cb64 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -456,6 +456,7 @@ void P_BounceMove(mobj_t *mo, TryMoveResult_t *result); boolean P_CheckSight(mobj_t *t1, mobj_t *t2); boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2); boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2); +boolean P_TraceWaypointTraversal(mobj_t *t1, mobj_t *t2); void P_CheckHoopPosition(mobj_t *hoopthing, fixed_t x, fixed_t y, fixed_t z, fixed_t radius); boolean P_CheckSector(sector_t *sector, boolean crunch); diff --git a/src/p_sight.c b/src/p_sight.c index 50b22243d..b582931f6 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -392,6 +392,26 @@ static boolean P_CanBotTraverse(seg_t *seg, divline_t *divl, register los_t *los return true; } +static boolean P_CanWaypointTraverse(seg_t *seg, divline_t *divl, register los_t *los) +{ + line_t *line = seg->linedef; + + if (P_CanTraceBlockingLine(seg, divl, los) == false) + { + // Blocked, so obviously can't traverse either. + return false; + } + + if (line->special == 2001) + { + // Don't allow through the finish linedef. + // Causes some janky behavior. + return false; + } + + return true; +} + // // P_CrossSubsector // @@ -780,3 +800,62 @@ boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2) return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); } +boolean P_TraceWaypointTraversal(mobj_t *t1, mobj_t *t2) +{ + const sector_t *s1, *s2; + size_t pnum; + los_t los; + los_funcs_t funcs; + + // First check for trivial rejection. + if (!t1 || !t2) + return false; + + I_Assert(!P_MobjWasRemoved(t1)); + I_Assert(!P_MobjWasRemoved(t2)); + + if (!t1->subsector || !t2->subsector + || !t1->subsector->sector || !t2->subsector->sector) + return false; + + s1 = t1->subsector->sector; + s2 = t2->subsector->sector; + pnum = (s1-sectors)*numsectors + (s2-sectors); + + if (rejectmatrix != NULL) + { + // Check in REJECT table. + if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected + return false; + } + + // killough 11/98: shortcut for melee situations + // same subsector? obviously visible + // haleyjd 02/23/06: can't do this if there are polyobjects in the subsec + if (!t1->subsector->polyList && + t1->subsector == t2->subsector) + return true; + + validcount++; + + los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); + los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); + + if (t1->x > t2->x) + los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; + else + los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; + + if (t1->y > t2->y) + los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; + else + los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; + + los.compareThing = t1; + los.alreadyHates = false; + + funcs.validate = &P_CanWaypointTraverse; + + // the head node is the last node output + return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); +} From fdd016eafc21c8701cd2e8ba781f4289d1888cd1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 02:39:49 -0500 Subject: [PATCH 58/67] Smarter WRONG WAY again --- src/k_kart.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 3fd42d6bf..deff7b3ee 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8872,9 +8872,6 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) angle_t angledelta = ANGLE_180; angle_t momdelta = ANGLE_180; - // Remove WRONG WAY flag. - player->pflags &= ~PF_WRONGWAY; - angledelta = playerangle - angletowaypoint; if (angledelta > ANGLE_180) { @@ -8939,6 +8936,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) if (angledelta < nextbestdelta || momdelta < nextbestmomdelta) { + // Wanted to use a next waypoint, so remove WRONG WAY flag. + // Done here instead of when set, because of finish line + // hacks meaning we might not actually use this one, but + // we still want to acknowledge we're facing the right way. + player->pflags &= ~PF_WRONGWAY; + if (waypoint->nextwaypoints[i] != finishline) // Allow finish line. { if (P_TraceWaypointTraversal(player->mo, waypoint->nextwaypoints[i]->mobj) == false) @@ -9166,6 +9169,7 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) } } +#if 0 if (cv_kartdebugwaypoints.value) { mobj_t *debugmobj = P_SpawnMobj(best.x, best.y, best.z, MT_SPARK); @@ -9174,9 +9178,10 @@ void K_UpdateDistanceFromFinishLine(player_t *const player) debugmobj->frame &= ~FF_TRANSMASK; debugmobj->frame |= FF_FULLBRIGHT; //FF_TRANS20 - debugmobj->tics = 2; + debugmobj->tics = 1; debugmobj->color = SKINCOLOR_BANANA; } +#endif adddist = bestGScore; } From eef87c4676bb16f1c109069b7b5a41f34388a262 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 03:15:03 -0500 Subject: [PATCH 59/67] Remove even more code dupe from p_sight.c --- src/p_sight.c | 294 ++++++++++++++++---------------------------------- 1 file changed, 90 insertions(+), 204 deletions(-) diff --git a/src/p_sight.c b/src/p_sight.c index b582931f6..e96bf9db8 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -38,11 +38,13 @@ typedef struct boolean alreadyHates; // For bot traversal, for if the bot is already in a sector it doesn't want to be } los_t; +typedef boolean (*los_init_t)(mobj_t *, mobj_t *, register los_t *); typedef boolean (*los_valid_t)(seg_t *, divline_t *, register los_t *); typedef boolean (*los_valid_poly_t)(polyobj_t *, divline_t *, register los_t *); typedef struct { + los_init_t init; // Initialization function. If true, we'll continue with checking across linedefs. If false, end early with failure. los_valid_t validate; // Validation function. If true, continue iterating for possible success. If false, end early with failure. los_valid_poly_t validatePolyobj; // If not NULL, then we will also check polyobject lines using this func. } los_funcs_t; @@ -507,11 +509,6 @@ static boolean P_CrossSubsector(size_t num, register los_t *los, register los_fu static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los, register los_funcs_t *funcs) { - if (funcs->validate == NULL) - { - return false; - } - while (!(bspnum & NF_SUBSECTOR)) { register node_t *bsp = nodes + bspnum; @@ -533,79 +530,22 @@ static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los, register los_fu return P_CrossSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), los, funcs); } -// -// P_CheckSight -// -// Returns true if a straight line between t1 and t2 is unobstructed. -// Uses REJECT. -// -boolean P_CheckSight(mobj_t *t1, mobj_t *t2) +static boolean P_InitCheckSight(mobj_t *t1, mobj_t *t2, register los_t *los) { const sector_t *s1, *s2; - size_t pnum; - los_t los; - los_funcs_t funcs; - - // First check for trivial rejection. - if (!t1 || !t2) - return false; - - I_Assert(!P_MobjWasRemoved(t1)); - I_Assert(!P_MobjWasRemoved(t2)); - - if (!t1->subsector || !t2->subsector - || !t1->subsector->sector || !t2->subsector->sector) - return false; - - s1 = t1->subsector->sector; - s2 = t2->subsector->sector; - pnum = (s1-sectors)*numsectors + (s2-sectors); - - if (rejectmatrix != NULL) - { - // Check in REJECT table. - if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected - return false; - } - - // killough 11/98: shortcut for melee situations - // same subsector? obviously visible - // haleyjd 02/23/06: can't do this if there are polyobjects in the subsec - if (!t1->subsector->polyList && - t1->subsector == t2->subsector) - return true; // An unobstructed LOS is possible. // Now look from eyes of t1 to any part of t2. sightcounts[1]++; - validcount++; - - los.compareThing = t1; - los.alreadyHates = false; - - los.topslope = - (los.bottomslope = t2->z - (los.sightzstart = - t1->z + t1->height - - (t1->height>>2))) + t2->height; - los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); - los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); - - if (t1->x > t2->x) - los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; - else - los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; - - if (t1->y > t2->y) - los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; - else - los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; - // Prevent SOME cases of looking through 3dfloors // // This WILL NOT work for things like 3d stairs with monsters behind // them - they will still see you! TODO: Fix. // + s1 = t1->subsector->sector; + s2 = t2->subsector->sector; + if (s1 == s2) // Both sectors are the same. { ffloor_t *rover; @@ -629,8 +569,8 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) bottomz2 = P_GetFFloorBottomZAt(rover, t2->x, t2->y); // Check for blocking floors here. - if ((los.sightzstart < bottomz1 && t2->z >= topz2) - || (los.sightzstart >= topz1 && t2->z + t2->height < bottomz2)) + if ((los->sightzstart < bottomz1 && t2->z >= topz2) + || (los->sightzstart >= topz1 && t2->z + t2->height < bottomz2)) { // no way to see through that return false; @@ -641,182 +581,66 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) if (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES)) { - if (los.sightzstart >= topz1 && t2->z + t2->height < topz2) + if (los->sightzstart >= topz1 && t2->z + t2->height < topz2) return false; // blocked by upper outside plane - if (los.sightzstart < bottomz1 && t2->z >= bottomz2) + if (los->sightzstart < bottomz1 && t2->z >= bottomz2) return false; // blocked by lower outside plane } if (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES) { - if (los.sightzstart < topz1 && t2->z >= topz2) + if (los->sightzstart < topz1 && t2->z >= topz2) return false; // blocked by upper inside plane - if (los.sightzstart >= bottomz1 && t2->z + t2->height < bottomz2) + if (los->sightzstart >= bottomz1 && t2->z + t2->height < bottomz2) return false; // blocked by lower inside plane } } } - funcs.validate = &P_IsVisible; - funcs.validatePolyobj = &P_IsVisiblePolyObj; - - // the head node is the last node output - return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); + return true; } -boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2) +static boolean P_InitTraceBotTraversal(mobj_t *t1, mobj_t *t2, register los_t *los) { - const sector_t *s1, *s2; - size_t pnum; - los_t los; - los_funcs_t funcs; + (void)t2; - // First check for trivial rejection. - if (!t1 || !t2) - return false; - - I_Assert(!P_MobjWasRemoved(t1)); - I_Assert(!P_MobjWasRemoved(t2)); - - if (!t1->subsector || !t2->subsector - || !t1->subsector->sector || !t2->subsector->sector) - return false; - - s1 = t1->subsector->sector; - s2 = t2->subsector->sector; - pnum = (s1-sectors)*numsectors + (s2-sectors); - - if (rejectmatrix != NULL) - { - // Check in REJECT table. - if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected - return false; - } - - // killough 11/98: shortcut for melee situations - // same subsector? obviously visible - // haleyjd 02/23/06: can't do this if there are polyobjects in the subsec - if (!t1->subsector->polyList && - t1->subsector == t2->subsector) - return true; - - validcount++; - - los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); - los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); - - if (t1->x > t2->x) - los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; - else - los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; - - if (t1->y > t2->y) - los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; - else - los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; - - los.compareThing = t1; - los.alreadyHates = false; - - funcs.validate = &P_CanTraceBlockingLine; - - // the head node is the last node output - return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); -} - -// -// ANOTHER version, this time for bot traversal. -// - -boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2) -{ - const sector_t *s1, *s2; - size_t pnum; - los_t los; - los_funcs_t funcs; - - // First check for trivial rejection. - if (!t1 || !t2) - return false; - - I_Assert(!P_MobjWasRemoved(t1)); - I_Assert(!P_MobjWasRemoved(t2)); - - if (!t1->subsector || !t2->subsector - || !t1->subsector->sector || !t2->subsector->sector) - return false; - - s1 = t1->subsector->sector; - s2 = t2->subsector->sector; - pnum = (s1-sectors)*numsectors + (s2-sectors); - - if (rejectmatrix != NULL) - { - // Check in REJECT table. - if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected - return false; - } - - // killough 11/98: shortcut for melee situations - // same subsector? obviously visible - // haleyjd 02/23/06: can't do this if there are polyobjects in the subsec - if (!t1->subsector->polyList && - t1->subsector == t2->subsector) - return true; - - validcount++; - - los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); - los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); - - if (t1->x > t2->x) - los.bbox[BOXRIGHT] = t1->x, los.bbox[BOXLEFT] = t2->x; - else - los.bbox[BOXRIGHT] = t2->x, los.bbox[BOXLEFT] = t1->x; - - if (t1->y > t2->y) - los.bbox[BOXTOP] = t1->y, los.bbox[BOXBOTTOM] = t2->y; - else - los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; - - los.compareThing = t1; if (t1->player != NULL) { - los.alreadyHates = K_BotHatesThisSector( + los->alreadyHates = K_BotHatesThisSector( t1->player, t1->subsector->sector, t1->x, t1->y ); } else { - los.alreadyHates = false; + los->alreadyHates = false; } - funcs.validate = &P_CanBotTraverse; - - // the head node is the last node output - return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); + return true; } -boolean P_TraceWaypointTraversal(mobj_t *t1, mobj_t *t2) +static boolean P_CompareMobjsAcrossLines(mobj_t *t1, mobj_t *t2, register los_funcs_t *funcs) { + los_t los; const sector_t *s1, *s2; size_t pnum; - los_t los; - los_funcs_t funcs; // First check for trivial rejection. if (!t1 || !t2) + { return false; + } I_Assert(!P_MobjWasRemoved(t1)); I_Assert(!P_MobjWasRemoved(t2)); if (!t1->subsector || !t2->subsector || !t1->subsector->sector || !t2->subsector->sector) + { return false; + } s1 = t1->subsector->sector; s2 = t2->subsector->sector; @@ -826,7 +650,9 @@ boolean P_TraceWaypointTraversal(mobj_t *t1, mobj_t *t2) { // Check in REJECT table. if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected + { return false; + } } // killough 11/98: shortcut for melee situations @@ -834,10 +660,19 @@ boolean P_TraceWaypointTraversal(mobj_t *t1, mobj_t *t2) // haleyjd 02/23/06: can't do this if there are polyobjects in the subsec if (!t1->subsector->polyList && t1->subsector == t2->subsector) + { return true; + } validcount++; + los.compareThing = t1; + los.alreadyHates = false; + + los.topslope = + (los.bottomslope = t2->z - (los.sightzstart = + t1->z + t1->height - + (t1->height>>2))) + t2->height; los.strace.dx = (los.t2x = t2->x) - (los.strace.x = t1->x); los.strace.dy = (los.t2y = t2->y) - (los.strace.y = t1->y); @@ -851,11 +686,62 @@ boolean P_TraceWaypointTraversal(mobj_t *t1, mobj_t *t2) else los.bbox[BOXTOP] = t2->y, los.bbox[BOXBOTTOM] = t1->y; - los.compareThing = t1; - los.alreadyHates = false; + if (funcs->init != NULL) + { + if (funcs->init(t1, t2, &los) == false) + { + return false; + } + } + + // The only required function. + I_Assert(funcs->validate != NULL); + + // the head node is the last node output + return P_CrossBSPNode((INT32)numnodes - 1, &los, funcs); +} + +// +// P_CheckSight +// +// Returns true if a straight line between t1 and t2 is unobstructed. +// Uses REJECT. +// +boolean P_CheckSight(mobj_t *t1, mobj_t *t2) +{ + los_funcs_t funcs = {0}; + + funcs.init = &P_InitCheckSight; + funcs.validate = &P_IsVisible; + funcs.validatePolyobj = &P_IsVisiblePolyObj; + + return P_CompareMobjsAcrossLines(t1, t2, &funcs); +} + +boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2) +{ + los_funcs_t funcs = {0}; + + funcs.validate = &P_CanTraceBlockingLine; + + return P_CompareMobjsAcrossLines(t1, t2, &funcs); +} + +boolean P_TraceBotTraversal(mobj_t *t1, mobj_t *t2) +{ + los_funcs_t funcs = {0}; + + funcs.init = &P_InitTraceBotTraversal; + funcs.validate = &P_CanBotTraverse; + + return P_CompareMobjsAcrossLines(t1, t2, &funcs); +} + +boolean P_TraceWaypointTraversal(mobj_t *t1, mobj_t *t2) +{ + los_funcs_t funcs = {0}; funcs.validate = &P_CanWaypointTraverse; - // the head node is the last node output - return P_CrossBSPNode((INT32)numnodes - 1, &los, &funcs); + return P_CompareMobjsAcrossLines(t1, t2, &funcs); } From 15a51e370afd0b7ef27a75d525fee240e8f11113 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 26 Nov 2022 16:40:19 +0000 Subject: [PATCH 60/67] Restartmap respects `encore Auto` too Per jart's suggestion --- src/d_netcmd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 56eb6470f..d7c45e518 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3152,6 +3152,8 @@ static void Command_RandomMap(void) static void Command_RestartLevel(void) { + boolean newencore = false; + if (client && !IsPlayerAdmin(consoleplayer)) { CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); @@ -3164,7 +3166,12 @@ static void Command_RestartLevel(void) return; } - D_MapChange(gamemap, gametype, (cv_kartencore.value == 1), false, 0, false, false); + if (cv_kartencore.value != 0) + { + newencore = (cv_kartencore.value == 1) || encoremode; + } + + D_MapChange(gamemap, gametype, newencore, false, 0, false, false); } static void Command_Pause(void) From 400a7b597427aaa04127bb98c9ec460badad701b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 26 Nov 2022 16:49:57 +0000 Subject: [PATCH 61/67] Move closed chat to behind rankings HUD --- src/hu_stuff.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index dcfc8cf78..e30a725e9 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2075,8 +2075,18 @@ void HU_DrawSongCredits(void) // void HU_Drawer(void) { + // Closed chat + if (!chat_on) + { + typelines = 1; + chat_scrolltime = 0; + + if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) + HU_drawMiniChat(); // draw messages in a cool fashion. + } + if (gamestate != GS_LEVEL) - goto drawchat; + goto drawontop; // draw multiplayer rankings if (hu_showscores) @@ -2116,8 +2126,8 @@ void HU_Drawer(void) V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text); } -drawchat: - // draw chat string plus cursor +drawontop: + // Opened chat if (chat_on) { if (!OLDCHAT) @@ -2125,14 +2135,6 @@ drawchat: else HU_DrawChat_Old(); } - else - { - typelines = 1; - chat_scrolltime = 0; - - if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) - HU_drawMiniChat(); // draw messages in a cool fashion. - } if (cechotimer) HU_DrawCEcho(); From 0e654aa2f9d2fb476715e6b53160220efc67fb96 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 15:27:51 -0500 Subject: [PATCH 62/67] Fix missing currentwaypoint in saveg --- src/p_saveg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_saveg.c b/src/p_saveg.c index 65b2d81a3..3d379879e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -249,6 +249,7 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].oldposition); WRITEUINT8(save_p, players[i].positiondelay); WRITEUINT32(save_p, players[i].distancetofinish); + WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].currentwaypoint)); WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint)); WRITEUINT32(save_p, players[i].airtime); WRITEUINT8(save_p, players[i].startboost); @@ -548,6 +549,7 @@ static void P_NetUnArchivePlayers(void) players[i].oldposition = READUINT8(save_p); players[i].positiondelay = READUINT8(save_p); players[i].distancetofinish = READUINT32(save_p); + players[i].currentwaypoint = (waypoint_t *)(size_t)READUINT32(save_p); players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save_p); players[i].airtime = READUINT32(save_p); players[i].startboost = READUINT8(save_p); From 1999cf05099595e23186163e3ab8364e22feb756 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 26 Nov 2022 22:25:15 +0000 Subject: [PATCH 63/67] Rank num SFX tweak - Add new sounds at various pitches depending on position - Don't play sound if a pass has just happened --- src/k_kart.c | 11 +++++++++-- src/sounds.c | 18 ++++++++++++++++++ src/sounds.h | 18 ++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 033f4e3ed..84bcc72be 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9916,10 +9916,17 @@ void K_KartUpdatePosition(player_t *player) if (position != oldposition) // Changed places? { - if (position < oldposition && P_IsDisplayPlayer(player) == true) + if (player->positiondelay <= 0 && position < oldposition && P_IsDisplayPlayer(player) == true) { // Play sound when getting closer to 1st. - S_StartSound(player->mo, sfx_mbs41); + UINT32 soundpos = (max(0, position - 1) * MAXPLAYERS)/realplayers; // always 1-15 despite there being 16 players at max... +#if MAXPLAYERS > 16 + if (soundpos < 15) + { + soundpos = 15; + } +#endif + S_StartSound(player->mo, sfx_pass02 + soundpos); // ...which is why we can start at index 2 for a lower general pitch } player->positiondelay = POS_DELAY_TIME + 4; // Position number growth diff --git a/src/sounds.c b/src/sounds.c index e10adc82c..f50e94942 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1130,6 +1130,24 @@ sfxinfo_t S_sfx[NUMSFX] = {"gate04", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"gate05", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // Passing sounds + {"pass01", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass02", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass03", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass04", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass05", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass06", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass07", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass08", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass09", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass10", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass11", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass12", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass13", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass14", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass15", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"pass16", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + // SRB2Kart - Engine sounds // Engine class A {"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""}, diff --git a/src/sounds.h b/src/sounds.h index 5194d1114..fe4427048 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -1195,6 +1195,24 @@ typedef enum sfx_gate04, sfx_gate05, + // Passing sounds + sfx_pass01, + sfx_pass02, + sfx_pass03, + sfx_pass04, + sfx_pass05, + sfx_pass06, + sfx_pass07, + sfx_pass08, + sfx_pass09, + sfx_pass10, + sfx_pass11, + sfx_pass12, + sfx_pass13, + sfx_pass14, + sfx_pass15, + sfx_pass16, + // Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy... // Engine class A - Low Speed, Low Weight sfx_krta00, From b1adc3d27c5ff8fdb4dfc06fc413d06ab1c36d16 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 26 Nov 2022 22:39:27 +0000 Subject: [PATCH 64/67] Fix chunky gap between Kart position numbers There's still a big gap but that's a graphics lump size issue, code wouldn't solve it --- src/k_hud.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index d9908c4c6..40f98323e 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1574,8 +1574,8 @@ static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 *color, fixed_t x, fi overlayFlags[1] = V_SUBTRACT; } - w = kp_positionnum[num][0][splitIndex]->width * scale; - h = kp_positionnum[num][0][splitIndex]->height * scale; + w = SHORT(kp_positionnum[num][0][splitIndex]->width) * scale; + h = SHORT(kp_positionnum[num][0][splitIndex]->height) * scale; if (flags & V_SNAPTORIGHT) { @@ -1597,7 +1597,12 @@ static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 *color, fixed_t x, fi ); } - return (x - w); + if (!(flags & V_SNAPTORIGHT)) + { + x -= w; + } + + return x; } static void K_DrawKartPositionNum(INT32 num) From 3f1ba402461341abb84a6c2dbc15a550d93089ca Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 26 Nov 2022 23:24:02 +0000 Subject: [PATCH 65/67] Missing gamecontrolname --- src/g_input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_input.c b/src/g_input.c index 08d7ab2ed..119eaa834 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -392,6 +392,7 @@ static const char *gamecontrolname[num_gamecontrols] = "console", "talk", "teamtalk", + "rankings", "screenshot", "recordgif", }; From e331910fe319bc5e8ba0a0a1aed63a171f041608 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 20:12:00 -0500 Subject: [PATCH 66/67] Reduce VFX toggle Can be used to disable VFX, so it can only appear if its owner is a display player. If no owner is provided, then it will be removed entirely. Applied to most things that Ivo asked for --- src/d_netcmd.c | 2 ++ src/d_netcmd.h | 2 +- src/k_kart.c | 53 ++++++++++++++++++++++++++++++++++++++++--------- src/k_kart.h | 3 +++ src/k_terrain.c | 5 +++-- src/p_enemy.c | 3 ++- src/p_map.c | 6 ++++-- src/p_mobj.c | 5 +++++ src/p_user.c | 2 ++ src/s_sound.c | 21 ++++++++++++++++++++ src/s_sound.h | 4 ++++ 11 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a5abda657..90c4b292f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -450,6 +450,8 @@ consvar_t cv_kartdebugdirector = CVAR_INIT ("debugdirector", "Off", CV_CHEAT, CV consvar_t cv_spbtest = CVAR_INIT ("spbtest", "Off", CV_CHEAT|CV_NETVAR, CV_OnOff, NULL); consvar_t cv_gptest = CVAR_INIT ("gptest", "Off", CV_CHEAT|CV_NETVAR, CV_OnOff, NULL); +consvar_t cv_reducevfx = CVAR_INIT ("reducevfx", "No", CV_SAVE, CV_YesNo, NULL); + static CV_PossibleValue_t votetime_cons_t[] = {{10, "MIN"}, {3600, "MAX"}, {0, NULL}}; consvar_t cv_votetime = CVAR_INIT ("votetime", "20", CV_NETVAR, votetime_cons_t, NULL); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index f3ace5cd9..1583ec5d8 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -120,7 +120,7 @@ extern consvar_t cv_votetime; extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugdistribution, cv_kartdebughuddrop; extern consvar_t cv_kartdebugnodes, cv_kartdebugcolorize, cv_kartdebugdirector; -extern consvar_t cv_spbtest, cv_gptest; +extern consvar_t cv_spbtest, cv_gptest, cv_reducevfx; extern consvar_t cv_kartdebugwaypoints, cv_kartdebugbotpredict; extern consvar_t cv_itemfinder; diff --git a/src/k_kart.c b/src/k_kart.c index 033f4e3ed..7a9b34bd3 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -195,6 +195,22 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player) return flag; } +void K_ReduceVFX(mobj_t *mo, player_t *owner) +{ + if (cv_reducevfx.value == 0) + { + // Leave the visuals alone. + return; + } + + mo->renderflags |= RF_DONTDRAW; + + if (owner != NULL) + { + mo->renderflags &= ~K_GetPlayerDontDrawFlag(owner); + } +} + player_t *K_GetItemBoxPlayer(mobj_t *mobj) { fixed_t closest = INT32_MAX; @@ -334,6 +350,8 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartdebugdirector); CV_RegisterVar(&cv_spbtest); CV_RegisterVar(&cv_gptest); + + CV_RegisterVar(&cv_reducevfx); } //} @@ -2432,6 +2450,8 @@ spawn_brake_dust P_SetScale(spark, (spark->destscale = FixedMul(scale, spark->scale))); + + K_ReduceVFX(spark, master->player); } static void K_SpawnBrakeVisuals(player_t *player) @@ -2474,7 +2494,7 @@ static void K_SpawnBrakeVisuals(player_t *player) } if (leveltime % 4 == 0) - S_StartSound(player->mo, sfx_s3k67); + S_ReducedVFXSound(player->mo, sfx_s3k67, player); /* vertical shaking, scales with speed */ player->mo->spriteyoffset = P_RandomFlip(2 * scale); @@ -2507,6 +2527,8 @@ void K_SpawnDriftBoostClip(player_t *player) P_InstaThrust(clip, player->mo->angle + P_RandomFlip(P_RandomRange(PR_DECORATION, FRACUNIT/2, FRACUNIT)), FixedMul(scale, player->speed)); + + K_ReduceVFX(clip, player); } void K_SpawnDriftBoostClipSpark(mobj_t *clip) @@ -2557,6 +2579,7 @@ static void K_SpawnGenericSpeedLines(player_t *player, boolean top) } K_MatchGenericExtraFlags(fast, player->mo); + K_ReduceVFX(fast, player); if (top) { @@ -2619,6 +2642,7 @@ void K_SpawnInvincibilitySpeedLines(mobj_t *mo) fast->momz = 3*P_GetMobjZMovement(mo)/4; K_MatchGenericExtraFlags(fast, mo); + K_ReduceVFX(fast, mo->player); fast->color = mo->color; fast->colorized = true; @@ -3667,6 +3691,7 @@ void K_SpawnWaterRunParticles(mobj_t *mobj) water->momz = mobj->momz; P_SetScale(water, trailScale); P_SetMobjState(water, curUnderlayFrame); + K_ReduceVFX(water, mobj->player); // overlay water = P_SpawnMobj(x1, y1, @@ -3678,6 +3703,7 @@ void K_SpawnWaterRunParticles(mobj_t *mobj) water->momz = mobj->momz; P_SetScale(water, trailScale); P_SetMobjState(water, curOverlayFrame); + K_ReduceVFX(water, mobj->player); // Right // Underlay @@ -3690,6 +3716,7 @@ void K_SpawnWaterRunParticles(mobj_t *mobj) water->momz = mobj->momz; P_SetScale(water, trailScale); P_SetMobjState(water, curUnderlayFrame); + K_ReduceVFX(water, mobj->player); // Overlay water = P_SpawnMobj(x2, y2, @@ -3701,11 +3728,12 @@ void K_SpawnWaterRunParticles(mobj_t *mobj) water->momz = mobj->momz; P_SetScale(water, trailScale); P_SetMobjState(water, curOverlayFrame); + K_ReduceVFX(water, mobj->player); if (!S_SoundPlaying(mobj, sfx_s3kdbs)) { const INT32 volume = (min(trailScale, FRACUNIT) * 255) / FRACUNIT; - S_StartSoundAtVolume(mobj, sfx_s3kdbs, volume); + S_ReducedVFXSoundAtVolume(mobj, sfx_s3kdbs, volume, mobj->player); } } @@ -3714,7 +3742,7 @@ void K_SpawnWaterRunParticles(mobj_t *mobj) { if (P_RandomChance(PR_BUBBLE, FRACUNIT/2) && leveltime % TICRATE == 0) { - S_StartSound(mobj, sfx_floush); + S_ReducedVFXSound(mobj, sfx_floush, mobj->player); } } } @@ -5453,6 +5481,7 @@ static void K_SpawnDriftElectricity(player_t *player) spark->momz = mo->momz; spark->color = color; K_GenericExtraFlagsNoZAdjust(spark, mo); + K_ReduceVFX(spark, player); spark->spritexscale += scalefactor/3; spark->spriteyscale += scalefactor/8; @@ -5502,10 +5531,11 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave) spark->frame |= FF_ADD; sparkangle += ANGLE_90; + K_ReduceVFX(spark, player); } } } - S_StartSound(mo, sfx_s3k45); + S_ReducedVFXSound(mo, sfx_s3k45, player); } static void K_SpawnDriftSparks(player_t *player) @@ -5652,6 +5682,7 @@ static void K_SpawnDriftSparks(player_t *player) spark->tics += trail; K_MatchGenericExtraFlags(spark, player->mo); + K_ReduceVFX(spark, player); } if (player->driftcharge >= dsthree) @@ -9919,7 +9950,7 @@ void K_KartUpdatePosition(player_t *player) if (position < oldposition && P_IsDisplayPlayer(player) == true) { // Play sound when getting closer to 1st. - S_StartSound(player->mo, sfx_mbs41); + S_ReducedVFXSound(player->mo, sfx_mbs41, NULL); } player->positiondelay = POS_DELAY_TIME + 4; // Position number growth @@ -10215,6 +10246,8 @@ static void K_KartSpindashDust(mobj_t *parent) dust->momx = FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT)); dust->momy = FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT)); dust->momz = vmomentum * flip; + + //K_ReduceVFX(dust, parent->player); } } @@ -10239,6 +10272,7 @@ static void K_KartSpindashWind(mobj_t *parent) wind->momz = 3 * P_GetMobjZMovement(parent) / 4; K_MatchGenericExtraFlags(wind, parent); + K_ReduceVFX(wind, parent->player); } // Time after which you get a thrust for releasing spindash @@ -10284,13 +10318,14 @@ static void K_KartSpindash(player_t *player) P_SetTarget(&grease->target, player->mo); grease->angle = K_MomentumAngle(player->mo); grease->extravalue1 = i; + K_ReduceVFX(grease, player); } } player->tiregrease = 2*TICRATE; player->spindash = 0; - S_StartSound(player->mo, sfx_s23c); + S_ReducedVFXSound(player->mo, sfx_s23c, player); } @@ -10327,7 +10362,7 @@ static void K_KartSpindash(player_t *player) if (player->speed == 0 && player->steering != 0 && leveltime % 8 == 0) { // Rubber burn turn sfx - S_StartSound(player->mo, sfx_ruburn); + S_ReducedVFXSound(player->mo, sfx_ruburn, player); } if (player->speed < 6*player->mo->scale) @@ -10369,7 +10404,7 @@ static void K_KartSpindash(player_t *player) { if (spawnOldEffect == true) K_SpawnDashDustRelease(player); - S_StartSound(player->mo, sfx_s3kab); + S_ReducedVFXSound(player->mo, sfx_s3kab, player); } } else if (chargetime < -TICRATE) @@ -10381,7 +10416,7 @@ static void K_KartSpindash(player_t *player) else { if (leveltime % 4 == 0) - S_StartSound(player->mo, sfx_kc2b); + S_ReducedVFXSound(player->mo, sfx_kc2b, player); } } diff --git a/src/k_kart.h b/src/k_kart.h index db280afc0..cddf3d503 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -43,7 +43,10 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt); void K_TimerReset(void); void K_TimerInit(void); + UINT32 K_GetPlayerDontDrawFlag(player_t *player); +void K_ReduceVFX(mobj_t *mo, player_t *owner); + boolean K_IsPlayerLosing(player_t *player); fixed_t K_GetKartGameSpeedScalar(SINT8 value); diff --git a/src/k_terrain.c b/src/k_terrain.c index de1124bcf..1b1df12f1 100644 --- a/src/k_terrain.c +++ b/src/k_terrain.c @@ -559,8 +559,8 @@ void K_ProcessTerrainEffect(mobj_t *mo) { /* use a shorter sound if not two tics have passed * since the last step */ - S_StartSound(mo, player->stairjank - >= 16 ? sfx_s23b : sfx_s268); + S_ReducedVFXSound(mo, player->stairjank + >= 16 ? sfx_s23b : sfx_s268, NULL); if (player->stairjank == 0) { @@ -569,6 +569,7 @@ void K_ProcessTerrainEffect(mobj_t *mo) spark->fuse = 9; spark->cusval = K_StairJankFlip(ANGLE_90); P_SetTarget(&spark->target, mo); + K_ReduceVFX(spark, player); } player->stairjank = 17; diff --git a/src/p_enemy.c b/src/p_enemy.c index 3b8ebb9ce..0db891f81 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3829,12 +3829,13 @@ void A_AttractChase(mobj_t *actor) // Base add is 3 tics for 9,9, adds 1 tic for each point closer to the 1,1 end actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true) + 3; - S_StartSound(actor->target, sfx_s1b5); + S_ReducedVFXSound(actor->target, sfx_s1b5, NULL); sparkle = P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, MT_RINGSPARKS); P_SetTarget(&sparkle->target, actor->target); sparkle->angle = (actor->target->angle + (offset>>1)) + (offset * actor->target->player->sparkleanim); actor->target->player->sparkleanim = (actor->target->player->sparkleanim+1) % 20; + K_ReduceVFX(sparkle, actor->target->player); P_KillMobj(actor, actor->target, actor->target, DMG_NORMAL); return; diff --git a/src/p_map.c b/src/p_map.c index 97ea69da7..cb5d030a2 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -420,6 +420,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) P_SetTarget(&grease->target, object); grease->angle = K_MomentumAngle(object); grease->extravalue1 = i; + K_ReduceVFX(grease, object->player); } } @@ -2873,8 +2874,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try { /* use a shorter sound if not two tics have passed * since the last step */ - S_StartSound(thing, thing->player->stairjank - >= 16 ? sfx_s23b : sfx_s268); + S_ReducedVFXSound(thing, thing->player->stairjank + >= 16 ? sfx_s23b : sfx_s268, NULL); if (!thing->player->stairjank) { @@ -2883,6 +2884,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try spark->fuse = 9; spark->cusval = K_StairJankFlip(ANGLE_90); P_SetTarget(&spark->target, thing); + K_ReduceVFX(spark, thing->player); } thing->player->stairjank = 17; diff --git a/src/p_mobj.c b/src/p_mobj.c index ac0312dec..814aa6b57 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7408,6 +7408,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } } } + + K_ReduceVFX(mobj, mobj->target->player); break; } case MT_BOOSTFLAME: @@ -7496,6 +7498,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) S_StartSound(mobj, sfx_cdfm17); K_MatchGenericExtraFlags(mobj, mobj->target); + K_ReduceVFX(mobj, mobj->target->player); if (leveltime & 1) mobj->renderflags |= RF_DONTDRAW; } @@ -7698,6 +7701,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) else mobj->renderflags = (mobj->renderflags & ~RF_TRANSMASK)|(trans << RF_TRANSSHIFT); } + + K_ReduceVFX(mobj, mobj->target->player); break; case MT_MAGICIANBOX: { diff --git a/src/p_user.c b/src/p_user.c index 1f58384df..7d21578dd 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1237,6 +1237,8 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->old_pitch = mobj->old_pitch2; ghost->old_roll = mobj->old_roll2; + K_ReduceVFX(ghost, mobj->player); + return ghost; } diff --git a/src/s_sound.c b/src/s_sound.c index e8a3a30dd..a36b14bf6 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -732,6 +732,27 @@ void S_StartSound(const void *origin, sfxenum_t sfx_id) S_StartSoundAtVolume(origin, sfx_id, 255); } +void S_ReducedVFXSoundAtVolume(const void *origin, sfxenum_t sfx_id, INT32 volume, void *owner) +{ + if (S_SoundDisabled()) + return; + + if (cv_reducevfx.value == 1) + { + if (owner == NULL) + { + return; + } + + if (P_IsDisplayPlayer((player_t *)owner) == false) + { + return; + } + } + + S_StartSoundAtVolume(origin, sfx_id, volume); +} + void S_StopSound(void *origin) { INT32 cnum; diff --git a/src/s_sound.h b/src/s_sound.h index 461f376af..e67868266 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -139,6 +139,10 @@ void S_StartSound(const void *origin, sfxenum_t sound_id); // Will start a sound at a given volume. void S_StartSoundAtVolume(const void *origin, sfxenum_t sound_id, INT32 volume); +// Will start a sound, but only if VFX reduce is off or the owner isn't a display player. +void S_ReducedVFXSoundAtVolume(const void *origin, sfxenum_t sfx_id, INT32 volume, void *owner); +#define S_ReducedVFXSound(a, b, c) S_ReducedVFXSoundAtVolume(a, b, 255, c) + // Stop sound for thing at void S_StopSound(void *origin); From 678e674d6564937a2f21b2a538452f46e0b23602 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Nov 2022 20:55:06 -0500 Subject: [PATCH 67/67] Disable e-brake vfx --- src/k_kart.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 7a9b34bd3..c95d92d9d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10108,11 +10108,12 @@ void K_KartEbrakeVisuals(player_t *p) wave->momy = p->mo->momy; wave->momz = p->mo->momz; wave->standingslope = p->mo->standingslope; + K_ReduceVFX(wave, p); } // sound if (!S_SoundPlaying(p->mo, sfx_s3kd9s)) - S_StartSound(p->mo, sfx_s3kd9s); + S_ReducedVFXSound(p->mo, sfx_s3kd9s, p); // HOLD! bubble. if (!p->ebrakefor) @@ -10134,6 +10135,7 @@ void K_KartEbrakeVisuals(player_t *p) p->mo->hprev->angle = p->mo->angle; p->mo->hprev->fuse = TICRATE/2; // When we leave spindash for any reason, make sure this bubble goes away soon after. K_FlipFromObject(p->mo->hprev, p->mo); + K_ReduceVFX(p->mo->hprev, p); p->mo->hprev->sprzoff = p->mo->sprzoff; } @@ -10147,6 +10149,7 @@ void K_KartEbrakeVisuals(player_t *p) spdl->colorized = true; spdl->color = SKINCOLOR_WHITE; K_MatchGenericExtraFlags(spdl, p->mo); + K_ReduceVFX(spdl, p); P_SetScale(spdl, p->mo->scale); // squish the player a little bit.