diff --git a/org.srb2.SRB2Kart-Saturn.desktop b/org.srb2.SRB2Kart-Saturn.desktop new file mode 100644 index 000000000..e0282b90f --- /dev/null +++ b/org.srb2.SRB2Kart-Saturn.desktop @@ -0,0 +1,20 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=Sonic Robo Blast 2 Kart Saturn +Comment=A kart racing mod based on the 3D Sonic the Hedgehog fangame Sonic Robo Blast 2 +TryExec=srb2kart.sh +Exec=srb2kart.sh +Icon=org.srb2.SRB2Kart-Saturn +Terminal=false +Categories=Game;SportsGame; +Keywords=kart;sonic;racer;multiplayer;doom; +Actions=OpenGL;Software; + +[Desktop Action OpenGL] +Name=OpenGL renderer +Exec=srb2kart.sh -opengl + +[Desktop Action Software] +Name=Software renderer +Exec=srb2kart.sh -software diff --git a/org.srb2.SRB2Kart-Saturn.metainfo.xml b/org.srb2.SRB2Kart-Saturn.metainfo.xml new file mode 100644 index 000000000..54c1de8b2 --- /dev/null +++ b/org.srb2.SRB2Kart-Saturn.metainfo.xml @@ -0,0 +1,80 @@ + + + + org.srb2.SRB2Kart-Saturn + FSFAP + GPL-2.0+ + Sonic Robo Blast 2 Kart Saturn + Modded SRB2Kart adding many custom features + +

+ A modded net-compatible version of SRB2Kart v1.6 that offers multiple code optimizations, palette rendering, player sprite rotation, base Kart HUD customization, and many more. +

+
+ org.srb2.SRB2Kart-Saturn.desktop + + + https://wiki.srb2.org/w/images/a/ac/Srb2kart_title.png + Title screen + + + https://user-images.githubusercontent.com/15758649/227740700-26e0962b-5572-486c-b633-7d4990d86f89.png + Game modes + + + https://user-images.githubusercontent.com/1964655/82821921-3d180c00-9ea5-11ea-937b-e1f53fe6c686.png + Game play as Sonic + + + https://user-images.githubusercontent.com/1964655/82821933-41442980-9ea5-11ea-9146-38998161edae.png + Game play as Tails + + + https://user-images.githubusercontent.com/1964655/82821966-502adc00-9ea5-11ea-9cbd-274d7adb479e.png + Game play as Eggman + + + https://user-images.githubusercontent.com/1964655/82821980-5620bd00-9ea5-11ea-9eec-2835ebb2a262.png + Game play as Metal Sonic + + + https://github.com/Indev450/SRB2Kart-Saturn + https://github.com/Indev450/SRB2Kart-Saturn/issues + Indev450 + + srb2kart + + + + +

The complete changelog can be found on the build's GitHub repository.

+
+ https://github.com/Indev450/SRB2Kart-Saturn/releases/tag/v5.1 +
+ + +

The complete changelog can be found on the build's GitHub repository.

+
+ https://github.com/Indev450/SRB2Kart-Saturn/releases/tag/v5 +
+
+ + Game + SportsGame + + + keyboard + gamepad + + + moderate + mild + intense + mild + + + doom + multiplayer + racing + +
diff --git a/src/g_game.c b/src/g_game.c index 55438cc83..b8aa208db 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -517,6 +517,8 @@ static CV_PossibleValue_t sloperolldist_cons_t[] = { {8192, "8192"}, {0, "Infinite"}, {0, NULL}}; consvar_t cv_sloperolldist = {"sloperolldist", "Infinite", CV_SAVE, sloperolldist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_sparkroll = {"sparkroll", "Off", CV_SAVE|CV_CALL, CV_OnOff, PDistort_menu_Onchange, 0, NULL, NULL, 0, 0, NULL}; + consvar_t cv_cechotoggle = {"show_cecho", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; #if MAXPLAYERS > 16 diff --git a/src/g_game.h b/src/g_game.h index 2f69070af..bc6d5f3b9 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -159,6 +159,7 @@ extern consvar_t cv_sloperoll; extern consvar_t cv_sliptideroll; extern consvar_t cv_slamsound; extern consvar_t cv_sloperolldist; +extern consvar_t cv_sparkroll; extern consvar_t cv_cechotoggle; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 4c682b2eb..5d63795ed 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -129,8 +129,10 @@ typedef struct FLOAT x,y,z; // position #ifdef USE_FTRANSFORM_ANGLEZ FLOAT anglex,angley,anglez; // aimingangle / viewangle + FLOAT anglex2,anglez2; // secondaries #else FLOAT anglex,angley; // aimingangle / viewangle + FLOAT anglex2; // secondaries #endif FLOAT scalex,scaley,scalez; FLOAT spritexscale,spriteyscale; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f0fab7fe5..3dfc2eb3c 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5515,7 +5515,7 @@ void HWR_ProjectSprite(mobj_t *thing) boolean mirrored = thing->mirrored; boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); - angle_t ang; + angle_t ang, camang; const boolean papersprite = (thing->frame & FF_PAPERSPRITE); INT32 heightsec, phs; vector3_t pos; @@ -5616,6 +5616,8 @@ void HWR_ProjectSprite(mobj_t *thing) #endif ang = R_PointToAngle (interp.x, interp.y) - interp.angle; + camang = R_PointToAngle (interp.x, interp.y); + if (mirrored) ang = InvAngle(ang); @@ -5666,15 +5668,22 @@ void HWR_ProjectSprite(mobj_t *thing) spr_topoffset = spritecachedinfo[lumpoff].topoffset; #ifdef ROTSPRITE - if ((thing->rollangle)||(thing->sloperoll)||(thing->player && thing->player->sliproll)) + + rollangle = FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), interp.roll) + + FixedMul(FINESINE((ang) >> ANGLETOFINESHIFT), interp.pitch) + + FixedMul(FINECOSINE((camang) >> ANGLETOFINESHIFT), interp.sloperoll) + + FixedMul(FINESINE((camang) >> ANGLETOFINESHIFT), interp.slopepitch) + + thing->rollangle; + + if ((rollangle)||(thing->player && thing->player->sliproll)) { if (thing->player) { sliptiderollangle = cv_sliptideroll.value ? thing->player->sliproll*(thing->player->sliptidemem) : 0; - rollsum = (thing->rollangle)+(thing->sloperoll)+FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), sliptiderollangle); + rollsum = rollangle+FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), sliptiderollangle); } else - rollsum = (thing->rollangle)+(thing->sloperoll); + rollsum = rollangle; rollangle = R_GetRollAngle(rollsum); rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 9cd077588..9a50b8a4f 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1401,18 +1401,55 @@ void HWR_DrawMD2(gr_vissprite_t *spr) p.anglex = 0.0f; + p.anglex2 = 0.0f; #ifdef USE_FTRANSFORM_ANGLEZ // Slope rotation from Kart p.anglez = 0.0f; + p.anglez2 = 0.0f; + + // use secondary angles for the slope rotation if (spr->mobj->standingslope) { fixed_t tempz = spr->mobj->standingslope->normal.z; fixed_t tempy = spr->mobj->standingslope->normal.y; fixed_t tempx = spr->mobj->standingslope->normal.x; fixed_t tempangle = AngleFixed(R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx)); - p.anglez = FIXED_TO_FLOAT(tempangle); + p.anglez2 = FIXED_TO_FLOAT(tempangle); tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy)); - p.anglex = FIXED_TO_FLOAT(tempangle); + p.anglex2 = FIXED_TO_FLOAT(tempangle); + } + else if ((spr->mobj->sloperoll || spr->mobj->slopepitch) && (!P_IsObjectOnGround(spr->mobj)) && (!paused)) + { + SINT8 flipfactor = flip ? -1 : 1; + + angle_t camang = R_PointToAngle(interp.x, interp.y); + angle_t mobjang; + + if (spr->mobj->flags & (MF_NOTHINK|MF_SCENERY)) + mobjang = spr->mobj->angle; + else + mobjang = interp.angle; + + angle_t fmoang; + fmoang = camang - mobjang; + + // slopepitch + p.anglex += flipfactor*FIXED_TO_FLOAT( AngleFixed(FixedMul(FINESINE((camang-fmoang) >> ANGLETOFINESHIFT), interp.slopepitch)) ); + p.anglez -= flipfactor*FIXED_TO_FLOAT( AngleFixed(FixedMul(FINECOSINE((camang-fmoang) >> ANGLETOFINESHIFT), interp.slopepitch)) ); + + // sloperoll + p.anglex += flipfactor*FIXED_TO_FLOAT( AngleFixed(FixedMul(FINECOSINE((camang-fmoang) >> ANGLETOFINESHIFT), interp.sloperoll)) ); + p.anglez += flipfactor*FIXED_TO_FLOAT( AngleFixed(FixedMul(FINESINE((camang-fmoang) >> ANGLETOFINESHIFT), interp.sloperoll)) ); + p.roll = true; + } + + // pitch and roll + if (interp.roll || interp.pitch) + { + SINT8 flipfactor = flip ? -1 : 1; + p.anglex += flipfactor*FIXED_TO_FLOAT(AngleFixed(interp.roll)); + p.anglez -= flipfactor*FIXED_TO_FLOAT(AngleFixed(interp.pitch)); + p.roll = true; } #endif diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index cf10c059f..8022f0091 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -3742,21 +3742,29 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float if (hflipped) scalez = -scalez; #ifdef USE_FTRANSFORM_ANGLEZ - pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart + pglRotatef(pos->anglez2, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart #endif - pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f); + pglRotatef(pos->anglex2, -1.0f, 0.0f, 0.0f); pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); if (pos->roll) { float roll = (1.0f * pos->rollflip); pglTranslatef(pos->centerx, pos->centery, 0); + + // rotate model for pitch and roll + pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f); +#ifdef USE_FTRANSFORM_ANGLEZ + pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); +#endif + if (pos->rotaxis == 2) // Z pglRotatef(pos->rollangle, 0.0f, 0.0f, roll); else if (pos->rotaxis == 1) // Y pglRotatef(pos->rollangle, 0.0f, roll, 0.0f); else // X pglRotatef(pos->rollangle, roll, 0.0f, 0.0f); + pglTranslatef(-pos->centerx, -pos->centery, 0); } diff --git a/src/k_kart.c b/src/k_kart.c index c44c0398d..8791da368 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3005,6 +3005,13 @@ static void K_SpawnDriftSparks(player_t *player) spark->momy = player->mo->momy/2; //spark->momz = player->mo->momz/2; + // rotate the sparks based on pitch and roll; it just looks neat + if (cv_sparkroll.value == 1) + { + spark->slopepitch = player->mo->slopepitch; + spark->sloperoll = player->mo->sloperoll; + } + if (player->kartstuff[k_driftcharge] >= K_GetKartDriftSparkValue(player)*4) { spark->color = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))); @@ -3214,7 +3221,7 @@ static void K_QuiteSaltyHop(player_t *p) } } -static INT32 K_FindPlayerNum(player_t *plyr) +/*static INT32 K_FindPlayerNum(player_t *plyr) { INT32 i; @@ -3224,95 +3231,61 @@ static INT32 K_FindPlayerNum(player_t *plyr) return i; } return 0; // technically defaulting to player 1 but fuck it -} +}*/ -static angle_t K_GetSlopeRollAngle(player_t *p, boolean dontflip, boolean useReserves) +#define SLOPEROLL_DIV 3 + +void K_RollMobjBySlopes(mobj_t* mo, boolean usedistance) { - angle_t lookAngle = 0; - angle_t zangle = 0; - angle_t xydirection = 0; - angle_t an; - angle_t final_slope; - INT32 pNum = K_FindPlayerNum(p); + I_Assert(mo->subsector != NULL); + I_Assert(mo->subsector->sector != NULL); - I_Assert(p != NULL); - I_Assert(p->mo != NULL); - I_Assert(!P_MobjWasRemoved(p->mo)); + angle_t an; + fixed_t m_dist = R_PointToDist(mo->x, mo->y); + fixed_t rolldist = cv_sloperolldist.value * mapobjectscale; - if (useReserves) - { - I_Assert(p->mo->reservezangle != NULL); - I_Assert(p->mo->reservexydir != NULL); - } + // lifted from hw_md2 + if (mo->standingslope) + { + fixed_t tempz = mo->standingslope->normal.z; + fixed_t tempy = mo->standingslope->normal.y; + fixed_t tempx = mo->standingslope->normal.x; + fixed_t tempangle = -(R_PointToAngle2( + 0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx)); - lookAngle = R_PointToAngle2(camera[pNum].x, camera[pNum].y, p->mo->x, p->mo->y); + // admittedly this is a very hacky way to do the pitch and roll easing - if (!R_PointToDist(p->mo->x, p->mo->y)) - lookAngle = p->mo->angle; + // pitch + if ((!usedistance) || (m_dist <= (rolldist))) + { + an = (INT32)((angle_t)tempangle - mo->pitch_sprite) / SLOPEROLL_DIV; - if (!useReserves) - { - zangle = p->mo->standingslope->zangle; - xydirection = p->mo->standingslope->xydirection; + mo->pitch_sprite = an ? mo->pitch_sprite + an : (angle_t)tempangle; + } + else + mo->pitch_sprite = FixedAngle(0); - p->mo->reservezangle = zangle; - p->mo->reservexydir = xydirection; - } - else if (p->mo->reservezangle) - { - zangle = p->mo->reservezangle; - xydirection = p->mo->reservexydir; - } + mo->slopepitch = mo->pitch_sprite; - if ((p->mo->eflags & MFE_VERTICALFLIP) && (!dontflip)) - zangle = InvAngle(zangle); + // roll + tempangle = (R_PointToAngle2(0, 0, tempz, tempy)); - an = (lookAngle - xydirection); - final_slope = -(FixedMul(FINESINE(an>>ANGLETOFINESHIFT), zangle)); - - an = (INT32)(final_slope - p->tilt_sprite) / (camspin[pNum] ? 1 : 3); - - p->tilt_sprite = an ? p->tilt_sprite + an : final_slope; - return -p->tilt_sprite; -} + if ((!usedistance) || (m_dist <= (rolldist))) + { + an = (INT32)((angle_t)tempangle - mo->roll_sprite) / SLOPEROLL_DIV; -static void K_RollPlayerBySlopes(player_t *p, boolean usedistance) -{ - I_Assert(p->mo->subsector != NULL); - I_Assert(p->mo->subsector->sector != NULL); + mo->roll_sprite = an ? mo->roll_sprite + an : (angle_t)tempangle; + } + else + mo->roll_sprite = FixedAngle(0); - INT32 pNum = K_FindPlayerNum(p); - - fixed_t p_dist = R_PointToDist2(p->mo->x, p->mo->y, camera[pNum].x, camera[pNum].y); - fixed_t mos = mapobjectscale; - fixed_t rolldist = cv_sloperolldist.value*mos; - - if (!P_IsObjectOnGround(p->mo)) - { - if (!usedistance) - p->mo->sloperoll = K_GetSlopeRollAngle(p, false, true); - else if (p_dist <= (rolldist)) - p->mo->sloperoll = K_GetSlopeRollAngle(p, false, true); - else - p->mo->sloperoll = FixedAngle(0); - - return; - } - - if (!p->mo->standingslope) - { - p->mo->sloperoll = FixedAngle(0); - p->mo->reservezangle = FixedAngle(0); - p->mo->reservexydir = FixedAngle(0); - return; - } - - if (!usedistance) - p->mo->sloperoll = K_GetSlopeRollAngle(p, false, false); - else if (p_dist <= (rolldist)) - p->mo->sloperoll = K_GetSlopeRollAngle(p, false, false); - else - p->mo->sloperoll = FixedAngle(0); + mo->sloperoll = mo->roll_sprite; + } + else if (P_IsObjectOnGround(mo)) + { + mo->sloperoll = FixedAngle(0); + mo->slopepitch = FixedAngle(0); + } } void K_SpawnBoostTrail(player_t *player) @@ -3364,6 +3337,14 @@ void K_SpawnBoostTrail(player_t *player) K_FlipFromObject(flame, player->mo); flame->momx = 8; + + // since you have to be on the ground for sneaker trails, this should be fine(?) + if (cv_sparkroll.value == 1) + { + flame->slopepitch = player->mo->slopepitch; + flame->sloperoll = player->mo->sloperoll; + } + P_XYMovement(flame); if (P_MobjWasRemoved(flame)) continue; @@ -6459,13 +6440,21 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->mo->spritexscale = player->mo->realxscale; player->mo->spriteyscale = player->mo->realyscale; } + boolean usedist = false; + if (cv_sloperolldist.value > 0) usedist = true; if (cv_sloperoll.value == 1) - K_RollPlayerBySlopes(player, usedist); + { + if ((!player->mo->salty_jump)) // seeing a character rotate mid-hop looks really janky + K_RollMobjBySlopes(player->mo, usedist); + } else + { player->mo->sloperoll = FixedAngle(0); + player->mo->slopepitch = FixedAngle(0); + } // Quick Turning diff --git a/src/k_kart.h b/src/k_kart.h index 40353f5df..803594790 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -49,6 +49,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor); void K_StealBumper(player_t *player, player_t *victim, boolean force); void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source); void K_SpawnMineExplosion(mobj_t *source, UINT8 color); +void K_RollMobjBySlopes(mobj_t *mo, boolean usedistance); void K_SpawnBoostTrail(player_t *player); void K_SpawnSparkleTrail(mobj_t *mo); void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 5fd813dc5..9e42e7e9f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -538,6 +538,18 @@ static int lib_pFlashPal(lua_State *L) return 0; } + +// not sure if this is netsafe... +static int lib_pRollPitchMobj(lua_State *L) +{ + mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + if (!source) + return LUA_ErrInvalid(L, "mobj_t"); + P_RollPitchMobj(source); + return 0; +} + static int lib_pGetClosestAxis(lua_State *L) { mobj_t *source = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -3033,6 +3045,7 @@ static luaL_Reg lib[] = { {"P_GetMobjGravity",lib_pGetMobjGravity}, {"P_WeaponOrPanel",lib_pWeaponOrPanel}, {"P_FlashPal",lib_pFlashPal}, + {"P_RollPitchMobj",lib_pRollPitchMobj}, {"P_GetClosestAxis",lib_pGetClosestAxis}, {"P_SpawnParaloop",lib_pSpawnParaloop}, {"P_BossTargetPlayer",lib_pBossTargetPlayer}, diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 52eda4554..6a5536c1c 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -83,8 +83,11 @@ static const udata_field_t mobj_fields[] = { FIELD(mobj_t, snext, udatalib_getter_mobj, mobj_snext_noset), FIELD(mobj_t, sprev, mobj_sprev_unimplemented, mobj_sprev_unimplemented), FIELD(mobj_t, angle, udatalib_getter_angle, mobj_angle_setter), + FIELD(mobj_t, pitch, udatalib_getter_angle, udatalib_setter_angle), + FIELD(mobj_t, roll, udatalib_getter_angle, udatalib_setter_angle), FIELD(mobj_t, rollangle, udatalib_getter_angle, udatalib_setter_angle), FIELD(mobj_t, sloperoll, udatalib_getter_angle, mobj_sloperoll_noop), + FIELD(mobj_t, slopepitch, udatalib_getter_angle, mobj_sloperoll_noop), // Macro fails here { "rollsum", 0, mobj_rollsum_getter, mobj_rollsum_noset }, FIELD(mobj_t, sprite, udatalib_getter_spritenum, udatalib_setter_spritenum), @@ -624,7 +627,9 @@ int mobj_rollsum_getter(lua_State *L) { mobj_t *mo = GETMO(); - angle_t rollsum = mo->rollangle + cv_sloperoll.value ? mo->sloperoll : 0; + angle_t pitchnroll = P_MobjPitchAndRoll(mo); + + angle_t rollsum = mo->rollangle + pitchnroll; if (mo->player) { diff --git a/src/m_menu.c b/src/m_menu.c index 1e0c28352..b8c9a04e5 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2005,7 +2005,7 @@ static menuitem_t OP_SaturnMenu[] = {IT_STRING | IT_CVAR, NULL, "Midnight Channel Flicker Effect", &cv_lessflicker, 95}, - {IT_SUBMENU|IT_STRING, NULL, "Player distortion...", &OP_PlayerDistortDef, 105}, + {IT_SUBMENU|IT_STRING, NULL, "Sprite Distortion...", &OP_PlayerDistortDef, 105}, {IT_SUBMENU|IT_STRING, NULL, "Hud Offsets...", &OP_HudOffsetDef, 110}, {IT_SUBMENU|IT_STRING, NULL, "Saturn Credits", &OP_SaturnCreditsDef, 120}, // uwu @@ -2029,7 +2029,7 @@ static const char* OP_SaturnTooltips[] = "Show the big Cecho Messages.", "Show Localskin Menus.", "Disables the flicker effect on Midnight Channel.", - "Options for player distortion effects.", + "Options for sprite distortion effects.", "Move position of HUD elements.", "See the people who helped make this project possible!", }; @@ -2057,13 +2057,14 @@ enum static menuitem_t OP_PlayerDistortMenu[] = { - {IT_HEADER, NULL, "Player Distortion", NULL, 0}, + {IT_HEADER, NULL, "Sprite Distortion", NULL, 0}, - {IT_STRING | IT_CVAR, NULL, "Rotate players on slopes", &cv_sloperoll, 20}, - {IT_STRING | IT_CVAR, NULL, "Slope rotation distance", &cv_sloperolldist, 35}, - {IT_STRING | IT_CVAR, NULL, "Rotate players when sliptiding", &cv_sliptideroll, 50}, - {IT_STRING | IT_CVAR, NULL, "Player stretch factor", &cv_gravstretch, 65}, - {IT_STRING | IT_CVAR, NULL, "Squish Sound Effect", &cv_slamsound, 80}, + {IT_STRING | IT_CVAR, NULL, "Rotate Objects on Slopes", &cv_sloperoll, 20}, + {IT_STRING | IT_CVAR, NULL, "Slope Rotation Distance", &cv_sloperolldist, 35}, + {IT_STRING | IT_CVAR, NULL, "Rotate Players when Sliptiding", &cv_sliptideroll, 50}, + {IT_STRING | IT_CVAR, NULL, "Rotate Sparks and Boost Trails", &cv_sparkroll, 65}, + {IT_STRING | IT_CVAR, NULL, "Player Stretch Factor", &cv_gravstretch, 80}, + {IT_STRING | IT_CVAR, NULL, "Squish Sound Effect", &cv_slamsound, 95}, {IT_STRING | IT_CVAR, NULL, "Saltyhop", &cv_saltyhop, 110}, {IT_STRING | IT_CVAR, NULL, "Saltyhop Sound Effect", &cv_saltyhopsfx, 125}, {IT_STRING | IT_CVAR, NULL, "Saltyhop Squish", &cv_saltysquish, 140}, @@ -2072,9 +2073,10 @@ static menuitem_t OP_PlayerDistortMenu[] = static const char* OP_PlayerDistortTooltips[] = { NULL, - "Player rotation on slopes.", - "Distance player rotation should be visable.", + "Object rotation on slopes.", + "Distance object rotation should be visable.", "Player rotation when sliptiding.", + "Rotation of a player's boost trails and drift sparks.", "Player squash and stretch.", "Player landing sound effect.", "Kart hopping while drifting. This is purely visual.", @@ -3136,7 +3138,9 @@ void PDistort_menu_Onchange(void) status = IT_GRAYEDOUT; } + // enable/disable rolldist and sparkroll options OP_PlayerDistortMenu[2].status = status; + OP_PlayerDistortMenu[4].status = status; } void Bird_menu_Onchange(void) diff --git a/src/p_mobj.c b/src/p_mobj.c index c52bb05be..d8237ff7b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6251,6 +6251,84 @@ static void P_KoopaThinker(mobj_t *koopa) } } +// +// P_RollPitchMobj +// Assigns slopepitch and sloperoll to objects, and resets said values when slope-rolling +// is turned off completely. +// +void P_RollPitchMobj(mobj_t* mobj) +{ + boolean usedist = false; + + if (cv_sloperolldist.value > 0) + usedist = true; + + if (cv_sloperoll.value == 1) + { + K_RollMobjBySlopes(mobj, usedist); + } + else + { + mobj->sloperoll = FixedAngle(0); + mobj->slopepitch = FixedAngle(0); + } +} + +angle_t P_MobjPitchAndRoll(mobj_t *mobj) +{ + spritedef_t *sprdef; + spriteframe_t *sprframe; + angle_t ang = 0; + angle_t camang = 0; + angle_t return_angle = 0; + + if (P_MobjWasRemoved(mobj)) + return 0; + + size_t rot = mobj->frame & FF_FRAMEMASK; + boolean papersprite = (mobj->frame & FF_PAPERSPRITE); + + if (mobj->skin && mobj->sprite == SPR_PLAY) + { + sprdef = &((skin_t *)mobj->skin)->spritedef; + + if (rot >= sprdef->numframes) + sprdef = &sprites[mobj->sprite]; + } + else + { + sprdef = &sprites[mobj->sprite]; + } + + if (rot >= sprdef->numframes) + { + sprdef = &sprites[states[S_UNKNOWN].sprite]; + rot = states[S_UNKNOWN].frame&FF_FRAMEMASK; + } + + sprframe = &sprdef->spriteframes[rot]; + + // No sprite frame? I guess it is possible + if (!sprframe) return 0; + + if (sprframe->rotate != SRF_SINGLE || papersprite) + { + ang = R_PointToAngle(mobj->x, mobj->y) - mobj->angle; + camang = R_PointToAngle(mobj->x, mobj->y); + } + + return_angle = FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), mobj->roll) + + FixedMul(FINESINE((ang) >> ANGLETOFINESHIFT), mobj->pitch); + + if (cv_sloperoll.value) + { + return_angle += FixedMul(FINECOSINE((camang) >> ANGLETOFINESHIFT), mobj->sloperoll) + + FixedMul(FINESINE((camang) >> ANGLETOFINESHIFT), mobj->slopepitch); + } + + return return_angle; +} + // // P_MobjThinker // @@ -6393,6 +6471,12 @@ void P_MobjThinker(mobj_t *mobj) return; } + if (mobj->state == &states[S_PLAY_SIGN]) // hack to make the player sign icon roll with the sign itself + { + mobj->slopepitch = mobj->target->slopepitch; + mobj->sloperoll = mobj->target->sloperoll; + } + P_AddOverlay(mobj); break; case MT_SHADOW: @@ -6428,6 +6512,7 @@ void P_MobjThinker(mobj_t *mobj) P_RemoveMobj(mobj); return; } + P_RollPitchMobj(mobj); break; case MT_SMOLDERING: if (leveltime % 2 == 0) @@ -7856,6 +7941,7 @@ void P_MobjThinker(mobj_t *mobj) fixed_t distbarrier = 512*mapobjectscale; fixed_t distaway; + P_RollPitchMobj(mobj); P_SpawnGhostMobj(mobj); if (mobj->threshold > 0) @@ -7923,6 +8009,7 @@ void P_MobjThinker(mobj_t *mobj) } else { + P_RollPitchMobj(mobj); P_SpawnGhostMobj(mobj); mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy); P_InstaThrust(mobj, mobj->angle, mobj->movefactor); @@ -7956,6 +8043,9 @@ void P_MobjThinker(mobj_t *mobj) mobj->momx = mobj->momy = 0; mobj->health = 1; } + + P_RollPitchMobj(mobj); + if (mobj->threshold > 0) mobj->threshold--; break; @@ -8003,6 +8093,8 @@ void P_MobjThinker(mobj_t *mobj) || (mobj->state >= &states[S_SSMINE_DEPLOY8] && mobj->state <= &states[S_SSMINE_DEPLOY13])) A_GrenadeRing(mobj); + P_RollPitchMobj(mobj); + if (mobj->threshold > 0) mobj->threshold--; break; @@ -8355,6 +8447,10 @@ void P_MobjThinker(mobj_t *mobj) } } } + + // fancy sign rotation + P_RollPitchMobj(mobj); + break; case MT_CDUFO: if (!mobj->spawnpoint || mobj->fuse) @@ -9535,6 +9631,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->height = info->height; mobj->flags = info->flags; mobj->sloperoll = 0; + mobj->slopepitch = 0; + + mobj->pitch_sprite = 0; + mobj->roll_sprite = 0; mobj->health = info->spawnhealth; diff --git a/src/p_mobj.h b/src/p_mobj.h index d53d7e3f0..5d26f9b44 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -283,9 +283,9 @@ typedef struct mobj_s struct mobj_s **sprev; // killough 8/11/98: change to ptr-to-ptr // More drawing info: to determine current sprite. - angle_t angle; // orientation - angle_t old_angle; // orientation interpolation - angle_t old_angle2; + angle_t angle, pitch, roll; // orientation + angle_t old_angle, old_pitch, old_roll; // orientation interpolation + angle_t old_angle2, old_pitch2, old_roll2; angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h @@ -302,7 +302,10 @@ typedef struct mobj_s fixed_t stretchslam; // "squish" effect when you land //sloperollangle - angle_t sloperoll, reservezangle, reservexydir; + angle_t sloperoll, slopepitch; + angle_t old_sloperoll, old_slopepitch; + angle_t old_sloperoll2, old_slopepitch2; + angle_t pitch_sprite, roll_sprite; struct msecnode_s *touching_sectorlist; // a linked list of sectors where this object appears @@ -433,9 +436,9 @@ typedef struct precipmobj_s struct precipmobj_s **sprev; // killough 8/11/98: change to ptr-to-ptr // More drawing info: to determine current sprite. - angle_t angle; // orientation - angle_t old_angle; // orientation interpolation - angle_t old_angle2; + angle_t angle, pitch, roll; // orientation + angle_t old_angle, old_pitch, old_roll; // orientation interpolation + angle_t old_angle2, old_pitch2, old_roll2; angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h @@ -452,7 +455,10 @@ typedef struct precipmobj_s fixed_t stretchslam; // "squish" effect when you land //sloperollangle - angle_t sloperoll, reservezangle, reservexydir; + angle_t sloperoll, slopepitch; + angle_t old_sloperoll, old_slopepitch; + angle_t old_sloperoll2, old_slopepitch2; + angle_t pitch_sprite, roll_sprite; struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears @@ -494,6 +500,10 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum); // check mobj against water content, before movement code void P_MobjCheckWater(mobj_t *mobj); +// fancy sprite rotation +void P_RollPitchMobj(mobj_t *mobj); +angle_t P_MobjPitchAndRoll(mobj_t *mobj); + // Player spawn points void P_SpawnPlayer(INT32 playernum); void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing); diff --git a/src/p_saveg.c b/src/p_saveg.c index d4e9b2f5e..3ac86eae6 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1976,9 +1976,15 @@ static void LoadMobjThinker(actionf_p1 thinker) mobj->thinker.function.acp1 = thinker; mobj->rollangle = 0; + + mobj->pitch = 0; + mobj->roll = 0; + mobj->sloperoll = 0; - mobj->reservexydir = 0; - mobj->reservezangle = 0; + mobj->slopepitch = 0; + + mobj->pitch_sprite = 0; + mobj->roll_sprite = 0; mobj->spritexoffset = mobj->old_spritexoffset = 0; mobj->spriteyoffset = mobj->old_spriteyoffset = 0; diff --git a/src/p_user.c b/src/p_user.c index fab59d28b..e759aba4d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1697,11 +1697,15 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) else ghost->angle = mobj->angle; + ghost->pitch = mobj->pitch; + ghost->roll = mobj->roll; + ghost->sprite = mobj->sprite; ghost->frame = mobj->frame; ghost->tics = -1; ghost->frame &= ~FF_TRANSMASK; ghost->frame |= tr_trans50<slopepitch = mobj->slopepitch; ghost->sloperoll = mobj->sloperoll; ghost->fuse = ghost->info->damage; @@ -1724,6 +1728,10 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->old_y = mobj->old_y2; ghost->old_z = mobj->old_z2; ghost->old_angle = (mobj->player ? mobj->player->old_frameangle2 : mobj->old_angle2); + ghost->old_pitch = mobj->old_pitch2; + ghost->old_roll = mobj->old_roll2; + ghost->old_sloperoll = mobj->old_sloperoll2; + ghost->old_slopepitch = mobj->old_slopepitch2; return ghost; } diff --git a/src/r_fps.c b/src/r_fps.c index 8aca51646..2ef5a68ba 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -282,6 +282,10 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) out->scale = mobj->scale; out->subsector = mobj->subsector; out->angle = mobj->player ? mobj->player->frameangle : mobj->angle; + out->pitch = mobj->pitch; + out->roll = mobj->roll; + out->slopepitch = mobj->slopepitch; + out->sloperoll = mobj->sloperoll; out->spritexscale = mobj->spritexscale; out->spriteyscale = mobj->spriteyscale; out->spritexoffset = mobj->spritexoffset; @@ -313,6 +317,14 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) { out->angle = mobj->resetinterp ? mobj->angle : R_LerpAngle(mobj->old_angle, mobj->angle, frac); } + + // pitch roll stuff + out->pitch = mobj->resetinterp ? mobj->pitch : R_LerpAngle(mobj->old_pitch, mobj->pitch, frac); + out->roll = mobj->resetinterp ? mobj->roll : R_LerpAngle(mobj->old_roll, mobj->roll, frac); + + // and the slope stuff + out->slopepitch = mobj->resetinterp ? mobj->slopepitch : R_LerpAngle(mobj->old_slopepitch, mobj->slopepitch, frac); + out->sloperoll = mobj->resetinterp ? mobj->sloperoll : R_LerpAngle(mobj->old_sloperoll, mobj->sloperoll, frac); } void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out) @@ -755,10 +767,27 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) mobj->old_z2 = mobj->old_z; mobj->old_angle2 = mobj->old_angle; mobj->old_scale2 = mobj->old_scale; + + // rotation humor + mobj->old_pitch2 = mobj->old_pitch; + mobj->old_roll2 = mobj->old_roll; + mobj->old_slopepitch2 = mobj->old_slopepitch; + mobj->old_sloperoll2 = mobj->old_sloperoll; + mobj->old_x = mobj->x; mobj->old_y = mobj->y; mobj->old_z = mobj->z; mobj->old_angle = mobj->angle; + + // rotation humor, again + + // pitch and roll first + mobj->old_pitch = mobj->pitch; + mobj->old_roll = mobj->roll; + + mobj->old_slopepitch = mobj->slopepitch; + mobj->old_sloperoll = mobj->sloperoll; + mobj->old_scale = mobj->scale; mobj->old_spritexscale = mobj->spritexscale; mobj->old_spriteyscale = mobj->spriteyscale; diff --git a/src/r_fps.h b/src/r_fps.h index 520843fd2..deb0c8788 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -65,6 +65,8 @@ typedef struct { fixed_t spriteyscale; fixed_t spritexoffset; fixed_t spriteyoffset; + angle_t pitch, roll; + angle_t sloperoll, slopepitch; } interpmobjstate_t; // Level interpolators diff --git a/src/r_main.c b/src/r_main.c index 63d1a7a59..45c56ede1 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1957,6 +1957,7 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_sloperoll); CV_RegisterVar(&cv_sliptideroll); CV_RegisterVar(&cv_sloperolldist); + CV_RegisterVar(&cv_sparkroll); CV_RegisterVar(&cv_showhud); CV_RegisterVar(&cv_translucenthud); diff --git a/src/r_things.c b/src/r_things.c index d112c05f2..43a4aaab9 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1327,6 +1327,7 @@ static void R_ProjectSprite(mobj_t *thing) spritecut_e cut = SC_NONE; angle_t ang = 0; // gcc 4.6 and lower fix + angle_t camang = 0; fixed_t iscale; fixed_t scalestep; // toast '16 fixed_t offset, offset2; @@ -1346,6 +1347,7 @@ static void R_ProjectSprite(mobj_t *thing) patch_t *rotsprite = NULL; INT32 rollangle = 0; angle_t rollsum = 0; + angle_t pitchnroll = 0; angle_t sliptiderollangle = 0; #endif @@ -1446,6 +1448,8 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate != SRF_SINGLE || papersprite) { ang = R_PointToAngle (interp.x, interp.y) - interp.angle; + camang = R_PointToAngle (interp.x, interp.y); + if (mirrored) ang = InvAngle(ang); if (papersprite) @@ -1489,31 +1493,62 @@ static void R_ProjectSprite(mobj_t *thing) spr_topoffset = spritecachedinfo[lump].topoffset; #ifdef ROTSPRITE - if ((thing->rollangle)||(thing->sloperoll)||(thing->player && thing->player->sliproll)) - { - if (thing->player) - { - sliptiderollangle = cv_sliptideroll.value ? thing->player->sliproll*(thing->player->sliptidemem) : 0; - rollsum = (thing->rollangle)+(thing->sloperoll)+FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), sliptiderollangle); - } - else - rollsum = (thing->rollangle)+(thing->sloperoll); + pitchnroll = 0; // set this to 0, non-paper sprites will affect this value - rollangle = R_GetRollAngle(rollsum); - rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); + if (papersprite) + { + if (ang >= ANGLE_180) + { + // Makes Software act much more sane like OpenGL + rollangle = InvAngle(thing->rollangle); + } + else + { + rollangle = thing->rollangle; + } + } + else + { + // this is very messy, but it on-the-fly calculates rotations for all the + // pitch and roll variables + pitchnroll = FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), interp.roll) + + FixedMul(FINESINE((ang) >> ANGLETOFINESHIFT), interp.pitch) + + FixedMul(FINECOSINE((camang) >> ANGLETOFINESHIFT), interp.sloperoll) + + FixedMul(FINESINE((camang) >> ANGLETOFINESHIFT), interp.slopepitch); - if (rotsprite != NULL) - { - spr_width = rotsprite->width << FRACBITS; - spr_height = rotsprite->height << FRACBITS; - spr_offset = rotsprite->leftoffset << FRACBITS; - spr_topoffset = rotsprite->topoffset << FRACBITS; - spr_topoffset += FEETADJUST; + rollangle = thing->rollangle; + } - // flip -> rotate, not rotate -> flip - flip = 0; - } - } + if ((rollangle) || (pitchnroll) || (thing->player && thing->player->sliproll)) + { + rollsum = pitchnroll; + + if (thing->player) + { + sliptiderollangle = + cv_sliptideroll.value ? thing->player->sliproll * (thing->player->sliptidemem) : 0; + rollsum += thing->rollangle + + FixedMul(FINECOSINE((ang) >> ANGLETOFINESHIFT), sliptiderollangle); + } + else + rollsum += thing->rollangle; + + rollangle = R_GetRollAngle(rollsum); + rotsprite = Patch_GetRotatedSprite( + sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); + + if (rotsprite != NULL) + { + spr_width = rotsprite->width << FRACBITS; + spr_height = rotsprite->height << FRACBITS; + spr_offset = rotsprite->leftoffset << FRACBITS; + spr_topoffset = rotsprite->topoffset << FRACBITS; + spr_topoffset += FEETADJUST; + + // flip -> rotate, not rotate -> flip + flip = 0; + } + } #endif // calculate edges of the shape