diff --git a/src/dehacked.c b/src/dehacked.c index f735b22e9..48f561a32 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7102,6 +7102,23 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGOORB", + "S_WATERTRAIL1", + "S_WATERTRAIL2", + "S_WATERTRAIL3", + "S_WATERTRAIL4", + "S_WATERTRAIL5", + "S_WATERTRAIL6", + "S_WATERTRAIL7", + "S_WATERTRAIL8", + "S_WATERTRAILUNDERLAY1", + "S_WATERTRAILUNDERLAY2", + "S_WATERTRAILUNDERLAY3", + "S_WATERTRAILUNDERLAY4", + "S_WATERTRAILUNDERLAY5", + "S_WATERTRAILUNDERLAY6", + "S_WATERTRAILUNDERLAY7", + "S_WATERTRAILUNDERLAY8", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -7914,6 +7931,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BATTLECAPSULE", "MT_BATTLECAPSULE_PIECE", + "MT_WATERTRAIL", + "MT_WATERTRAILUNDERLAY", + #ifdef SEENAMES "MT_NAMECHECK", #endif diff --git a/src/info.c b/src/info.c index fcdeffcd6..795885f92 100644 --- a/src/info.c +++ b/src/info.c @@ -69,8 +69,8 @@ char sprnames[NUMSPRITES + 1][5] = "ICEB","CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS", "ZTCH","MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH", "BFRT","OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN", - "FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","EGOO","XMS4","XMS5", - "VIEW" + "FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","EGOO","WTRL","XMS4", + "XMS5","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -3500,6 +3500,24 @@ state_t states[NUMSTATES] = {SPR_EGOO, 0, 1, {NULL}, 0, 0, S_NULL}, // S_EGOORB + // Water Trail + {SPR_WTRL, FF_PAPERSPRITE , 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL1 + {SPR_WTRL, FF_PAPERSPRITE|1, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL2 + {SPR_WTRL, FF_PAPERSPRITE|2, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL3 + {SPR_WTRL, FF_PAPERSPRITE|3, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL4 + {SPR_WTRL, FF_PAPERSPRITE|4, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL5 + {SPR_WTRL, FF_PAPERSPRITE|5, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL6 + {SPR_WTRL, FF_PAPERSPRITE|6, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL7 + {SPR_WTRL, FF_PAPERSPRITE|7, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL8 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|8, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY1 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|9, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY2 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|10, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY3 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|11, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY4 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|12, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY5 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|13, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY6 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|14, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY7 + {SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|15, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY8 + #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK #endif @@ -20778,6 +20796,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_WATERTRAIL + -1, // doomednum + S_WATERTRAIL1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 32*FRACUNIT, // height + 1, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_WATERTRAILUNDERLAY + -1, // doomednum + S_WATERTRAILUNDERLAY1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 48*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + // ============================================================================================================================// #ifdef SEENAMES diff --git a/src/info.h b/src/info.h index a1db87946..183d1f941 100644 --- a/src/info.h +++ b/src/info.h @@ -798,6 +798,8 @@ typedef enum sprite SPR_EGOO, + SPR_WTRL, // Water Trail + // Xmas-specific sprites that don't fit aboxe SPR_XMS4, SPR_XMS5, @@ -4188,6 +4190,23 @@ typedef enum state S_EGOORB, + S_WATERTRAIL1, + S_WATERTRAIL2, + S_WATERTRAIL3, + S_WATERTRAIL4, + S_WATERTRAIL5, + S_WATERTRAIL6, + S_WATERTRAIL7, + S_WATERTRAIL8, + S_WATERTRAILUNDERLAY1, + S_WATERTRAILUNDERLAY2, + S_WATERTRAILUNDERLAY3, + S_WATERTRAILUNDERLAY4, + S_WATERTRAILUNDERLAY5, + S_WATERTRAILUNDERLAY6, + S_WATERTRAILUNDERLAY7, + S_WATERTRAILUNDERLAY8, + #ifdef SEENAMES S_NAMECHECK, #endif @@ -5017,6 +5036,9 @@ typedef enum mobj_type MT_BATTLECAPSULE, MT_BATTLECAPSULE_PIECE, + MT_WATERTRAIL, + MT_WATERTRAILUNDERLAY, + #ifdef SEENAMES MT_NAMECHECK, #endif diff --git a/src/p_user.c b/src/p_user.c index 28273ca82..0fdfd7120 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -6045,6 +6045,7 @@ static void P_MovePlayer(player_t *player) */ // If you're running fast enough, you can create splashes as you run in shallow water. +#if 0 if (!player->climbing && ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height >= player->mo->watertop && player->mo->z <= player->mo->watertop) || (player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height >= player->mo->waterbottom && player->mo->z <= player->mo->waterbottom)) @@ -6065,6 +6066,83 @@ static void P_MovePlayer(player_t *player) water->destscale = player->mo->scale; P_SetScale(water, player->mo->scale); } +#endif + + if (!player->climbing + && ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height >= player->mo->watertop && player->mo->z <= player->mo->watertop) + || (player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height >= player->mo->waterbottom && player->mo->z <= player->mo->waterbottom)) + && (player->speed > runspd || (player->pflags & PF_STARTDASH)) + && player->mo->momz == 0 && !(player->pflags & PF_SLIDING) && !player->spectator) + { + fixed_t trailScale = FixedMul(FixedDiv(player->speed - runspd, K_GetKartSpeed(player, false) - runspd), mapobjectscale); + fixed_t playerTopSpeed = K_GetKartSpeed(player, false); + + if (playerTopSpeed > runspd) + trailScale = FixedMul(FixedDiv(player->speed - runspd, playerTopSpeed - runspd), mapobjectscale); + else + trailScale = mapobjectscale; // Scaling is based off difference between runspeed and top speed + + if (trailScale > 0) + { + const angle_t forwardangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + const fixed_t playerVisualRadius = player->mo->radius + 8*FRACUNIT; + const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1; + const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames); + const statenum_t curUnderlayFrame = S_WATERTRAILUNDERLAY1 + (leveltime % numFrames); + fixed_t x1, x2, y1, y2; + mobj_t *water; + + x1 = player->mo->x + player->mo->momx + P_ReturnThrustX(player->mo, forwardangle + ANGLE_90, playerVisualRadius); + y1 = player->mo->y + player->mo->momy + P_ReturnThrustY(player->mo, forwardangle + ANGLE_90, playerVisualRadius); + x1 = x1 + P_ReturnThrustX(player->mo, forwardangle, playerVisualRadius); + y1 = y1 + P_ReturnThrustY(player->mo, forwardangle, playerVisualRadius); + + x2 = player->mo->x + player->mo->momx + P_ReturnThrustX(player->mo, forwardangle - ANGLE_90, playerVisualRadius); + y2 = player->mo->y + player->mo->momy + P_ReturnThrustY(player->mo, forwardangle - ANGLE_90, playerVisualRadius); + x2 = x2 + P_ReturnThrustX(player->mo, forwardangle, playerVisualRadius); + y2 = y2 + P_ReturnThrustY(player->mo, forwardangle, playerVisualRadius); + + // Left + // underlay + water = P_SpawnMobj(x1, y1, + ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAILUNDERLAY); + water->angle = forwardangle - ANGLE_180 - ANGLE_22h; + water->destscale = trailScale; + P_SetScale(water, trailScale); + P_SetMobjState(water, curUnderlayFrame); + + // overlay + water = P_SpawnMobj(x1, y1, + ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAIL); + water->angle = forwardangle - ANGLE_180 - ANGLE_22h; + water->destscale = trailScale; + P_SetScale(water, trailScale); + P_SetMobjState(water, curOverlayFrame); + + // Right + // Underlay + water = P_SpawnMobj(x2, y2, + ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAILUNDERLAY].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAILUNDERLAY); + water->angle = forwardangle - ANGLE_180 + ANGLE_22h; + water->destscale = trailScale; + P_SetScale(water, trailScale); + P_SetMobjState(water, curUnderlayFrame); + + // Overlay + water = P_SpawnMobj(x2, y2, + ((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_WATERTRAIL].height, player->mo->scale) : player->mo->watertop), MT_WATERTRAIL); + water->angle = forwardangle - ANGLE_180 + ANGLE_22h; + water->destscale = trailScale; + P_SetScale(water, trailScale); + P_SetMobjState(water, curOverlayFrame); + + if (!S_SoundPlaying(player->mo, sfx_s3kdbs)) + { + const INT32 volume = (min(trailScale, FRACUNIT) * 255) / FRACUNIT; + S_StartSoundAtVolume(player->mo, sfx_s3kdbs, volume); + } + } + } // Little water sound while touching water - just a nicety. if ((player->mo->eflags & MFE_TOUCHWATER) && !(player->mo->eflags & MFE_UNDERWATER) && !player->spectator)