diff --git a/src/d_main.cpp b/src/d_main.cpp index f3a5b60bc..302f1bbc2 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -346,11 +346,6 @@ boolean D_RenderLevel(void) { viewssnum = i; -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_RenderPlayerView(); - else -#endif if (rendermode != render_none) { if (i > 0) // Splitscreen-specific @@ -380,7 +375,15 @@ boolean D_RenderLevel(void) break; } } + } +#ifdef HWRENDER + if (rendermode == render_opengl) + HWR_RenderPlayerView(); + else +#endif + if (rendermode != render_none) + { R_RenderPlayerView(); } } diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 381f13a57..cd02ad652 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -122,17 +122,23 @@ typedef struct FLOAT scalex,scaley,scalez; FLOAT fovxangle, fovyangle; UINT8 splitscreen; - boolean flip; // screenflip boolean shearing; // 14042019 float viewaiming; // 17052019 boolean roll; FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ FLOAT centerx, centery; FLOAT rollx, rollz; - boolean mirror; // SRB2Kart: Encore Mode - boolean mirrorflip; // Encore Mode with Flipcam + UINT8 fliptype; } FTransform; +enum +{ + TRANSFORM_NONE = 0, + TRANSFORM_FLIP = 1 << 0, // screenflip + TRANSFORM_MIRROR = 1 << 1, // SRB2Kart: Encore Mode + TRANSFORM_MIRRORFLIP = TRANSFORM_FLIP|TRANSFORM_MIRROR // SRB2Kart: Encore Mode with Flipcam +}; + // Transformed vector, as passed to HWR API typedef struct { diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 71560d3a9..fbb44a145 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -61,22 +61,6 @@ // GLOBALS // ========================================================================== -// base values set at SetViewSize -static float gl_basecentery; -static float gl_basecenterx; - -float gl_baseviewwindowy, gl_basewindowcentery; -float gl_baseviewwindowx, gl_basewindowcenterx; -float gl_viewwidth, gl_viewheight; // viewport clipping boundaries (screen coords) -float gl_viewwindowx; - -static float gl_centerx, gl_centery; -static float gl_viewwindowy; // top left corner of view window -static float gl_windowcenterx; // center of view window, for projection -static float gl_windowcentery; - -static float gl_pspritexscale, gl_pspriteyscale; - seg_t *gl_curline; side_t *gl_sidedef; line_t *gl_linedef; @@ -604,61 +588,9 @@ boolean HWR_BlendMidtextureSurface(FSurfaceInfo *pSurf) // -----------------+ void HWR_SetViewSize(void) { - // setup view size - gl_viewwidth = (float)vid.width; - gl_viewheight = (float)vid.height; - - if (r_splitscreen > 0) - { - gl_viewheight /= 2; - - if (r_splitscreen > 1) - { - gl_viewwidth /= 2; - } - } - - gl_basecenterx = gl_viewwidth / 2; - gl_basecentery = gl_viewheight / 2; - - gl_baseviewwindowx = 0; - gl_basewindowcenterx = gl_viewwidth / 2; - - gl_baseviewwindowy = 0; - gl_basewindowcentery = gl_viewheight / 2; - - gl_pspritexscale = gl_viewwidth / BASEVIDWIDTH; - gl_pspriteyscale = ((vid.height*gl_pspritexscale*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width; - GL_FlushScreenTextures(); } -// -------------------+ -// HWR_ShiftViewPort : offset viewport according to current split -// -------------------+ -static void HWR_ShiftViewPort(void) -{ - gl_centerx = gl_basecenterx; - gl_viewwindowx = gl_baseviewwindowx; - gl_windowcenterx = gl_basewindowcenterx; - - gl_centery = gl_basecentery; - gl_viewwindowy = gl_baseviewwindowy; - gl_windowcentery = gl_basewindowcentery; - - if (viewssnum > ( r_splitscreen > 1 )) - { - gl_viewwindowy += gl_viewheight; - gl_windowcentery += gl_viewheight; - } - - if (r_splitscreen > 1 && viewssnum & 1) - { - gl_viewwindowx += gl_viewwidth; - gl_windowcenterx += gl_viewwidth; - } -} - // Set view aiming, for the sky dome, the skybox, // and the normal view, all with a single function. void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox, boolean side_effect) @@ -669,7 +601,9 @@ void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox, if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))) { fixed_t fixedaiming = AIMINGTODY(aimingangle); - trans->viewaiming = FIXED_TO_FLOAT(fixedaiming); + trans->viewaiming = FixedToFloat(fixedaiming) * ((float)vid.width / (float)vid.height) / ((float)BASEVIDWIDTH / (float)BASEVIDHEIGHT); + if (splitscreen == 1) // only for 2 player splitscreen + trans->viewaiming *= 2.125f; // splitscreen adjusts fov with 0.8, so compensate (but only halfway, since splitscreen means only half the screen is used) trans->shearing = true; temp_aimingangle = 0; } @@ -730,17 +664,17 @@ static void HWR_PrepareTransform(player_t *player, boolean is_skybox) gl_viewludsin = FIXED_TO_FLOAT(FINECOSINE(gl_aimingangle>>ANGLETOFINESHIFT)); gl_viewludcos = FIXED_TO_FLOAT(-FINESINE(gl_aimingangle>>ANGLETOFINESHIFT)); - atransform.flip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && !(thiscam->postimgflags & POSTIMG_MIRROR)) - atransform.flip = true; - - atransform.mirror = false; - if ((thiscam->postimgflags & POSTIMG_MIRROR) && !(thiscam->postimgflags & POSTIMG_FLIP)) - atransform.mirror = true; - - atransform.mirrorflip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && (thiscam->postimgflags & POSTIMG_MIRROR)) - atransform.mirrorflip = true; + if (thiscam->postimgflags & POSTIMG_FLIP) + { + if (thiscam->postimgflags & POSTIMG_MIRROR) + atransform.fliptype = TRANSFORM_MIRRORFLIP; + else + atransform.fliptype = TRANSFORM_FLIP; + } + else if (thiscam->postimgflags & POSTIMG_MIRROR) + { + atransform.fliptype = TRANSFORM_MIRROR; + } atransform.x = gl_viewx; // FIXED_TO_FLOAT(viewx) atransform.y = gl_viewy; // FIXED_TO_FLOAT(viewy) @@ -987,7 +921,6 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea if (timing) { - ps_hw_spritesorttime = I_GetPreciseTime(); } @@ -1057,6 +990,20 @@ void HWR_RollTransform(FTransform *tr, angle_t roll) } } +// -----------------+ +// HWR_ClearView : clear the viewwindow, with maximum z value. also clears stencil buffer. +// -----------------+ +static inline void HWR_ClearView(void) +{ + GL_GClipRect(viewwindowx, + viewwindowy, + (viewwindowx + viewwidth), + (viewwindowy + viewheight), + ZCLIP_PLANE); + + GL_ClearBuffer(false, true, true, NULL); +} + void HWR_RenderPlayerView(void) { player_t * player = &players[displayplayers[viewssnum]]; @@ -1070,7 +1017,19 @@ void HWR_RenderPlayerView(void) ClearColor.blue = 0.0f; ClearColor.alpha = 1.0f; - GL_ClearBuffer(true, true, true, &ClearColor); + if (cv_glshaders.value) + GL_SetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime. + + if (viewssnum == 0) // Only do it if it's the first screen being rendered + GL_ClearBuffer(true, true, true, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. + + ps_hw_skyboxtime = I_GetPreciseTime(); + if (skybox) // If there's a skybox and we should be drawing the sky, draw the skybox + { + HWR_ClearView(); + HWR_RenderSkyboxView(player); // This is drawn before everything else so it is placed behind + } + ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; if (!HWR_ShouldUsePaletteRendering()) { @@ -1084,29 +1043,9 @@ void HWR_RenderPlayerView(void) #endif } - // set window position - HWR_ShiftViewPort(); - - GL_GClipRect((INT32)gl_viewwindowx, - (INT32)gl_viewwindowy, - (INT32)(gl_viewwindowx + gl_viewwidth), - (INT32)(gl_viewwindowy + gl_viewheight), - ZCLIP_PLANE); - // Reset the shader state. HWR_SetShaderState(); - if (cv_glshaders.value) - GL_SetShaderInfo(HWD_SHADERINFO_LEVELTIME, (INT32)leveltime); // The water surface shader needs the leveltime. - - if (viewssnum == 0) // Only do it if it's the first screen being rendered - GL_ClearBuffer(true, false, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. - - ps_hw_skyboxtime = I_GetPreciseTime(); - if (skybox) // If there's a skybox and we should be drawing the sky, draw the skybox - HWR_RenderSkyboxView(player); // This is drawn before everything else so it is placed behind - ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; - // note: sets viewangle, viewx, viewy, viewz R_SetupFrame(viewssnum, skybox); framecount++; // timedemo @@ -1114,6 +1053,8 @@ void HWR_RenderPlayerView(void) // Check for new console commands. NetUpdate(); + HWR_ClearView(); + HWR_RenderViewpoint(player, !skybox, // Don't draw the regular sky if there's a skybox false, diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 879f3c40b..cce9daf45 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -124,10 +124,6 @@ extern consvar_t cv_gldebugportal; extern consvar_t cv_glskydebug; -extern float gl_viewwidth, gl_viewheight, gl_baseviewwindowy; - -extern float gl_viewwindowx, gl_basewindowcentery; - extern seg_t *gl_curline; extern side_t *gl_sidedef; extern line_t *gl_linedef; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 0431b8875..b3ab2bdb1 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1717,8 +1717,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.anglez = FIXED_TO_FLOAT(AngleFixed(R_InterpolateAngle(spr->mobj->old_pitch, spr->mobj->pitch))); p.anglex = FIXED_TO_FLOAT(AngleFixed(R_InterpolateAngle(spr->mobj->old_roll, spr->mobj->roll))); - p.flip = atransform.flip; - p.mirror = atransform.mirror; + p.fliptype = atransform.fliptype; if (HWR_UseShader()) GL_SetShader(HWR_GetShaderFromTarget(SHADER_MODEL)); diff --git a/src/hardware/hw_sky.c b/src/hardware/hw_sky.c index fbd040a6e..47b8c9692 100644 --- a/src/hardware/hw_sky.c +++ b/src/hardware/hw_sky.c @@ -164,12 +164,13 @@ void HWR_BuildSkyDome(void) void HWR_DrawSkyBackground(player_t *player) { - UINT8 viewnum = R_GetViewNumber(); - camera_t *thiscam = &camera[viewnum]; GL_SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); if (cv_glskydome.value) { + UINT8 viewnum = R_GetViewNumber(); + camera_t *thiscam = &camera[viewnum]; + FTransform dometransform; const float fpov = FIXED_TO_FLOAT(cv_fov[viewssnum].value+player->fovadd); @@ -178,17 +179,17 @@ void HWR_DrawSkyBackground(player_t *player) HWR_SetTransformAiming(&dometransform, player, false, true); dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); - dometransform.flip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && !(thiscam->postimgflags & POSTIMG_MIRROR)) - dometransform.flip = true; - - dometransform.mirror = false; - if ((thiscam->postimgflags & POSTIMG_MIRROR) && !(thiscam->postimgflags & POSTIMG_FLIP)) - dometransform.mirror = true; - - dometransform.mirrorflip = false; - if ((thiscam->postimgflags & POSTIMG_FLIP) && (thiscam->postimgflags & POSTIMG_MIRROR)) - dometransform.mirrorflip = true; + if (thiscam->postimgflags & POSTIMG_FLIP) + { + if (thiscam->postimgflags & POSTIMG_MIRROR) + dometransform.fliptype = TRANSFORM_MIRRORFLIP; + else + dometransform.fliptype = TRANSFORM_FLIP; + } + else if (thiscam->postimgflags & POSTIMG_MIRROR) + { + dometransform.fliptype = TRANSFORM_MIRROR; + } dometransform.scalex = 1; dometransform.scaley = (float)vid.width/vid.height; @@ -265,7 +266,8 @@ void HWR_DrawSkyBackground(player_t *player) // Middle of the sky should always be at angle 0 // need to keep correct aspect ratio with X - if (atransform.flip) + if (atransform.fliptype == TRANSFORM_FLIP || + atransform.fliptype == TRANSFORM_MIRRORFLIP) { // During vertical flip the sky should be flipped and it's y movement should also be flipped obviously v[3].t = v[2].t = -(0.5f-(0.5f/dimensionmultiply)); // top diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 1b1ae2b1a..6da624800 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -923,7 +923,7 @@ static void SetNoTexture(GLenum texture) } } -static void GLPerspective(GLfloat fovy, GLfloat aspect) +static void GL_Perspective(GLfloat fovy, GLfloat aspect) { GLfloat m[4][4] = { @@ -1033,7 +1033,7 @@ void SetModelView(GLint w, GLint h) pglMatrixMode(GL_MODELVIEW); pglLoadIdentity(); - GLPerspective(fov, ASPECT_RATIO); + GL_Perspective(fov, ASPECT_RATIO); //pglScalef(1.0f, 320.0f/200.0f, 1.0f); // gl_scalefrustum (ORIGINAL_ASPECT) // added for new coronas' code (without depth buffer) @@ -1339,7 +1339,7 @@ void GL_GClipRect(INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip //pglScissor(minx, screen_height-maxy, maxx-minx, maxy-miny); pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); - GLPerspective(fov, ASPECT_RATIO); + GL_Perspective(fov, ASPECT_RATIO); pglMatrixMode(GL_MODELVIEW); // added for new coronas' code (without depth buffer) @@ -1368,6 +1368,7 @@ void GL_ClearBuffer(FBOOLEAN ColorMask, ClearColor->alpha); ClearMask |= GL_COLOR_BUFFER_BIT; } + if (DepthMask) { pglClearDepth(1.0f); //Hurdler: all that are permanen states @@ -1375,6 +1376,7 @@ void GL_ClearBuffer(FBOOLEAN ColorMask, pglDepthFunc(GL_LEQUAL); ClearMask |= GL_DEPTH_BUFFER_BIT; } + if (StencilMask) ClearMask |= GL_STENCIL_BUFFER_BIT; @@ -2740,7 +2742,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float // pos->mirror is if the screen is flipped horizontally // XOR all the flips together to figure out what culling to use! { - boolean reversecull = (flipped ^ hflipped ^ pos->flip ^ pos->mirror); + boolean reversecull = (flipped ^ hflipped ^ !!(pos->fliptype & TRANSFORM_FLIP) ^ !!(pos->fliptype & TRANSFORM_MIRROR)); if (reversecull) pglCullFace(GL_FRONT); else @@ -2926,7 +2928,7 @@ void GL_DrawModel(model_t *model, INT32 frameIndex, float duration, float tics, // -----------------+ void GL_SetTransform(FTransform *stransform) { - static boolean special_splitscreen; + boolean special_splitscreen = false; boolean shearing = false; float used_fov; @@ -2935,14 +2937,21 @@ void GL_SetTransform(FTransform *stransform) if (stransform) { used_fov = stransform->fovxangle; - if (stransform->mirror) - pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); - else if (stransform->mirrorflip) - pglScalef(-stransform->scalex, -stransform->scaley, -stransform->scalez); - else if (stransform->flip) - pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); - else - pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez); + switch (stransform->fliptype) + { + case TRANSFORM_MIRROR: + pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); + break; + case TRANSFORM_MIRRORFLIP: + pglScalef(-stransform->scalex, -stransform->scaley, -stransform->scalez); + break; + case TRANSFORM_FLIP: + pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); + break; + default: // TRANSFORM_NONE + pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez); + break; + } if (stransform->roll) pglRotatef(stransform->rollangle, 0.0f, 0.0f, 1.0f); @@ -2962,23 +2971,29 @@ void GL_SetTransform(FTransform *stransform) pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); + // jimita 14042019 // Simulate Software's y-shearing // https://zdoom.org/wiki/Y-shearing if (shearing) { - float fdy = stransform->viewaiming * 2 * ((float)vid.width / vid.height) / ((float)BASEVIDWIDTH / BASEVIDHEIGHT); //screen_width/BASEVIDWIDTH; - if (stransform->flip) - fdy *= -1.0f; - pglTranslatef(0.0f, -fdy/BASEVIDHEIGHT, 0.0f); + float dy = stransform->viewaiming * 2; + + if (stransform->fliptype == TRANSFORM_FLIP || + stransform->fliptype == TRANSFORM_MIRRORFLIP) + dy *= -1.0f; + + pglTranslatef(0.0f, -dy/BASEVIDHEIGHT, 0.0f); } if (special_splitscreen) { - used_fov = atan(tan(used_fov*M_PI/360)*0.8)*360/M_PI; - GLPerspective(used_fov, 2*ASPECT_RATIO); + used_fov = (atanf(tanf(used_fov * (float)M_PI / 360.0f) * 0.8f) * 360.0f / (float)M_PI); + GL_Perspective(used_fov, 2*ASPECT_RATIO); } else - GLPerspective(used_fov, ASPECT_RATIO); + { + GL_Perspective(used_fov, ASPECT_RATIO); + } pglGetFloatv(GL_PROJECTION_MATRIX, projMatrix); // added for new coronas' code (without depth buffer) pglMatrixMode(GL_MODELVIEW); @@ -2987,7 +3002,7 @@ void GL_SetTransform(FTransform *stransform) } -INT32 GL_GetTextureUsed(void) +INT32 GL_GetTextureUsed(void) { FTextureInfo *tmp = TexCacheHead; INT32 res = 0; diff --git a/src/k_items.c b/src/k_items.c index 843e007ad..12ddfd127 100644 --- a/src/k_items.c +++ b/src/k_items.c @@ -1127,7 +1127,7 @@ UINT32 K_GetCongaLineDistance(const player_t *player, UINT8 startPos) memset(sortedPlayers, -1, sizeof(sortedPlayers)); - if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false) + if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false && player->position > 0) { // Sort all of the players ahead of you. // Then tally up their distances in a conga line. diff --git a/src/k_kart.c b/src/k_kart.c index 55bb53246..0add2b200 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1803,7 +1803,7 @@ static void K_RespawnChecker(player_t *player) */ void K_KartMoveAnimation(player_t *player) { - const fixed_t fastspeed = (K_GetKartSpeed(player, false, true) * 17) / 20; // 85% + const fixed_t fastspeed = (K_GetKartSpeed(player, player->forcedtopspeed > 0, true) * 17) / 20; // 85% const fixed_t speedthreshold = player->mo->scale / 8; const boolean onground = P_IsObjectOnGround(player->mo); @@ -4428,7 +4428,7 @@ static void K_SpawnDraftDust(mobj_t *mo) } } -void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) +mobj_t *K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) { mobj_t *dust; angle_t aoff; @@ -4469,6 +4469,8 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent) if (translucent) dust->renderflags |= RF_GHOSTLY; + + return dust; } // K_DriftDustHandling @@ -6793,6 +6795,9 @@ static void K_TireGreaseEffect(player_t *player) if (leveltime % 6 == 0) S_StartSound(player->mo, sfx_screec); + + if (!S_SoundPlaying(player->mo, sfx_ruburn)) + S_StartSound(player->mo, sfx_ruburn); } boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound) @@ -9828,9 +9833,19 @@ static void K_KartSlipdash(player_t *player, boolean onground) } } +static boolean K_CanPanicRecoverySpin(const player_t *player) +{ + return player->flashing > 0 && ( +#if 0 // skip the last flashtics? maybe not... + player->spinouttimer > 0 ? player->spinouttimer <= TICRATE/4 : +#endif + !K_IsPlayerDamaged(player) + ); +} + static boolean K_PlayerWantsRecoverySpin(player_t *player) { - return ((player->cmd.buttons & BT_ACCELERATE) && (player->cmd.buttons & BT_BRAKE) && (!(player->cmd.buttons & BT_DRIFT))); + return (K_GetKartButtons(player) & (BT_ACCELERATE|BT_BRAKE|BT_DRIFT)) == (BT_ACCELERATE|BT_BRAKE); } static boolean K_PlayerCanStartRecoverySpin(player_t *player) @@ -9842,159 +9857,161 @@ static boolean K_PlayerCanStartRecoverySpin(player_t *player) static boolean K_PlayerCanRecoverySpin(player_t *player) { return (K_RecoveryDashActive() && leveltime > starttime && (player->carry == CR_NONE) && - !(player->sneakertimer || K_IsPlayerDamaged(player) || player->squishedtimer || - player->exiting || (player->pflags & PF_STASIS) || player->dashpadcooldown || + !(player->sneakertimer || (K_IsPlayerDamaged(player) && !K_CanPanicRecoverySpin(player)) || + player->squishedtimer || player->exiting || (player->pflags & PF_STASIS) || player->dashpadcooldown || player->walltransferboost || player->loop.radius )); } static void K_RecoveryDash(player_t *player) { - if (K_PlayerWantsRecoverySpin(player) && (player->spinouttimer > 0 || player->flipovertimer > 0) && (!player->wipeoutslow)) + if (K_PlayerWantsRecoverySpin(player) && K_IsPlayerDamaged(player) && player->wipeoutslow == 0) { player->wipeoutslow = max(wipeoutslowtime + 1, player->spinouttimer + 4); } - if ((player->pflags & PF_RECOVERYSPIN) && player->forcedtopspeed == 0 && player->speed >= 10*player->mo->scale) + if (!K_PlayerCanRecoverySpin(player) + || ((player->pflags & PF_RECOVERYSPIN) && player->forcedtopspeed == 0 && player->speed >= 10*player->mo->scale)) { player->pflags &= ~PF_RECOVERYSPIN; player->forcedtopspeed = 0; player->recoverydashcharge = 0; + return; } - if (K_PlayerCanRecoverySpin(player)) + if (K_PlayerWantsRecoverySpin(player) && K_PlayerCanStartRecoverySpin(player)) { - if (K_PlayerWantsRecoverySpin(player) && K_PlayerCanStartRecoverySpin(player)) + player->pflags |= PF_RECOVERYSPIN; + player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; + S_StartSound(player->mo, sfx_cdfm20); + + player->mo->momx = min(10*player->mo->scale, abs(player->mo->momx/2)) * intsign(player->mo->momx); + player->mo->momy = min(10*player->mo->scale, abs(player->mo->momy/2)) * intsign(player->mo->momy); + + player->driftboost = 0; + player->sneakertimer = 0; + player->ringboost = 0; + player->startboost = 0; + } + + if (player->pflags & PF_RECOVERYSPIN) + { + if ((K_GetKartButtons(player) & (BT_ACCELERATE|BT_BRAKE)) != (BT_ACCELERATE|BT_BRAKE)) { - player->pflags |= PF_RECOVERYSPIN; - player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; - S_StartSound(player->mo, sfx_cdfm20); - - player->mo->momx = min(10*player->mo->scale, abs(player->mo->momx/2)) * intsign(player->mo->momx); - player->mo->momy = min(10*player->mo->scale, abs(player->mo->momy/2)) * intsign(player->mo->momy); - - player->driftboost = 0; - player->sneakertimer = 0; - player->ringboost = 0; - player->startboost = 0; + player->pflags &= ~PF_RECOVERYSPIN; + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME && (K_GetKartButtons(player) & BT_ACCELERATE)) + { + K_SetTireGrease(player, 2*TICRATE); + player->outrun = TICRATE/4; + player->recoverydash = TICRATE; + player->flashing = 0; + S_StartSound(player->mo, sfx_s23c); + K_SpawnDashDustRelease(player, true); + } + player->recoverydashcharge = 0; + player->forcedtopspeed = 0; + return; } - if (player->pflags & PF_RECOVERYSPIN) + player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; + if (P_IsObjectOnGround(player->mo)) { - if (!((player->cmd.buttons & BT_ACCELERATE) && (player->cmd.buttons & BT_BRAKE))) + tic_t oldcharge = player->recoverydashcharge; + player->recoverydashcharge += K_CanPanicRecoverySpin(player) ? (leveltime & 1) + 1 : 1; + if (oldcharge < RECOVERYDASHCHARGETIME && player->recoverydashcharge >= RECOVERYDASHCHARGETIME) + S_StartSound(player->mo, sfx_s3ka2); + + mobj_t *dust = K_SpawnWipeoutTrail(player->mo, !K_CanPanicRecoverySpin(player) + && player->recoverydashcharge < RECOVERYDASHWIPETIME); + + if (K_CanPanicRecoverySpin(player)) { - player->pflags &= ~PF_RECOVERYSPIN; - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME && (player->cmd.buttons & BT_ACCELERATE)) - { - K_SetTireGrease(player, 2*TICRATE); - player->outrun = TICRATE/4; - player->recoverydash = TICRATE; - player->flashing = 0; - S_StartSound(player->mo, sfx_s23c); - K_SpawnDashDustRelease(player, true); - } - player->recoverydashcharge = 0; - player->forcedtopspeed = 0; - return; + dust->colorized = true; + dust->color = SKINCOLOR_KETCHUP; + if (!S_SoundPlaying(player->mo, sfx_s248)) + S_StartSound(player->mo, sfx_s248); } - player->forcedtopspeed = cv_kartrecoverydash_spinspeed.value + 8; - if (P_IsObjectOnGround(player->mo)) + if (player->recoverydashcharge < RECOVERYDASHCHARGETIME) { - player->recoverydashcharge += player->flashing ? ((leveltime & 1) + 1) : 1; - - K_SpawnWipeoutTrail(player->mo, (player->recoverydashcharge < RECOVERYDASHWIPETIME)); - if (leveltime % 6 == 0) { - if (player->recoverydashcharge < RECOVERYDASHCHARGETIME) - { - S_StartSound(player->mo, sfx_s225); - } - } - if (leveltime % 4 == 0) - { - fixed_t newx; - fixed_t newy; - mobj_t *skid; - angle_t travelangle; - travelangle = player->mo->angle; - for (INT32 i = 0; i < 2; i++) - { - newx = P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); - newy = P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); - skid = P_SpawnMobjFromMobj(player->mo, newx, newy, (10*player->mo->scale), MT_OVERLAY); - P_SetTarget(&skid->target, player->mo); - skid->sprxoff = newx; - skid->spryoff = newy; - skid->sprzoff = (10*player->mo->scale); - - P_SetScale(skid, player->mo->scale); - skid->destscale = player->mo->destscale; - skid->scalespeed = player->mo->scalespeed; - skid->movefactor = FRACUNIT; - skid->angle = travelangle; - - - P_SetMobjState(skid, S_RECSPIN_SKID); - K_MatchGenericExtraFlags(skid, player->mo); - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) - { - skid->renderflags |= RF_TRANS20; - } - else - { - skid->renderflags |= RF_TRANS40; - } - if (i) skid->renderflags |= RF_HORIZONTALFLIP; - } + S_StartSound(player->mo, sfx_s225); } } - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) + if (leveltime % 4 == 0) { - if (player->recoverydashcharge == RECOVERYDASHCHARGETIME && P_IsObjectOnGround(player->mo)) - S_StartSound(player->mo, sfx_s3ka2); - - if (leveltime & 1) + fixed_t newx; + fixed_t newy; + mobj_t *skid; + angle_t travelangle; + travelangle = player->mo->angle; + for (INT32 i = 0; i < 2; i++) { - fixed_t newx; - fixed_t newy; - mobj_t *spark; - angle_t travelangle, sparkangle; - travelangle = player->mo->angle; - sparkangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - for (INT32 i = 0; i < 2; i++) + newx = P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); + newy = P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(28*FRACUNIT, player->mo->scale)); + skid = P_SpawnMobjFromMobj(player->mo, newx, newy, (10*player->mo->scale), MT_OVERLAY); + P_SetTarget(&skid->target, player->mo); + skid->sprxoff = newx; + skid->spryoff = newy; + skid->sprzoff = (10*player->mo->scale); + + P_SetScale(skid, player->mo->scale); + skid->destscale = player->mo->destscale; + skid->scalespeed = player->mo->scalespeed; + skid->movefactor = FRACUNIT; + skid->angle = travelangle; + + P_SetMobjState(skid, S_RECSPIN_SKID); + K_MatchGenericExtraFlags(skid, player->mo); + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) { - newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); - newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); - spark = P_SpawnMobj(newx, newy, player->mo->z, MT_DRIFTSPARK); - spark->momx = player->mo->momx/2; - spark->momy = player->mo->momy/2; - - P_SetTarget(&spark->target, player->mo); - spark->angle = sparkangle; - spark->color = SKINCOLOR_WHITE; - - if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME + TICRATE/4) - { - P_SetMobjState(spark, S_DRIFTSPARK_B1); - } - else - { - P_SetMobjState(spark, S_DRIFTSPARK_A1); - } - K_MatchGenericExtraFlags(spark, player->mo); + skid->renderflags |= RF_TRANS20; } + else + { + skid->renderflags |= RF_TRANS40; + } + if (i) skid->renderflags |= RF_HORIZONTALFLIP; + } + } + } + + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME) + { + if (leveltime & 1) + { + fixed_t newx; + fixed_t newy; + mobj_t *spark; + angle_t travelangle, sparkangle; + travelangle = player->mo->angle; + sparkangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + for (INT32 i = 0; i < 2; i++) + { + newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); + newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale)); + spark = P_SpawnMobj(newx, newy, player->mo->z, MT_DRIFTSPARK); + spark->momx = player->mo->momx/2; + spark->momy = player->mo->momy/2; + + P_SetTarget(&spark->target, player->mo); + spark->angle = sparkangle; + spark->color = SKINCOLOR_WHITE; + + if (player->recoverydashcharge >= RECOVERYDASHCHARGETIME + TICRATE/4) + { + P_SetMobjState(spark, S_DRIFTSPARK_B1); + } + else + { + P_SetMobjState(spark, S_DRIFTSPARK_A1); + } + K_MatchGenericExtraFlags(spark, player->mo); } } } - } - else - { - player->pflags &= ~PF_RECOVERYSPIN; - player->forcedtopspeed = 0; - player->recoverydashcharge = 0; } } diff --git a/src/k_kart.h b/src/k_kart.h index 4cd6d4305..07426d099 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -253,7 +253,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color); UINT16 K_DriftSparkColor(player_t *player, INT32 charge); void K_SpawnBoostTrail(player_t *player); void K_SpawnSparkleTrail(mobj_t *mo); -void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); +mobj_t *K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); void K_DriftDustHandling(mobj_t *spawner); mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow); void K_PuntMine(mobj_t *mine, mobj_t *punter);