From 260b461c39bbb06f4d3a6fbab6dcb9f74cfa29e2 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 5 Feb 2017 18:15:20 +0000 Subject: [PATCH 01/61] Drawangle. Mystic wanted it, just play it - too busy to give proper commit description. Will outline everything it is in the merge request when that happens. --- src/d_player.h | 3 +++ src/lua_playerlib.c | 4 ++++ src/p_enemy.c | 13 ++++++++----- src/p_mobj.c | 1 + src/p_saveg.c | 2 ++ src/p_user.c | 13 +++++++++++++ src/r_things.c | 2 +- 7 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 1c57e6167..01c8ee38e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -315,6 +315,9 @@ typedef struct player_s // It is updated with cmd->aiming. angle_t aiming; + // fun thing for player sprite + angle_t drawangle; + // player's ring count INT32 rings; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 29f1c6ff0..cc8b67e88 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -122,6 +122,8 @@ static int player_get(lua_State *L) lua_pushfixed(L, plr->bob); else if (fastcmp(field,"aiming")) lua_pushangle(L, plr->aiming); + else if (fastcmp(field,"drawangle")) + lua_pushangle(L, plr->drawangle); else if (fastcmp(field,"rings")) lua_pushinteger(L, plr->rings); else if (fastcmp(field,"pity")) @@ -382,6 +384,8 @@ static int player_set(lua_State *L) else if (plr == &players[secondarydisplayplayer]) localaiming2 = plr->aiming; } + else if (fastcmp(field,"drawangle")) + plr->drawangle = luaL_checkangle(L, 3); else if (fastcmp(field,"rings")) plr->rings = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"pity")) diff --git a/src/p_enemy.c b/src/p_enemy.c index 08a79b8cf..a74f665ef 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4854,6 +4854,7 @@ void A_CapeChase(mobj_t *actor) fixed_t foffsetx, foffsety, boffsetx, boffsety; INT32 locvar1 = var1; INT32 locvar2 = var2; + angle_t angle; #ifdef HAVE_BLUA if (LUA_CallAction("A_CapeChase", actor)) return; @@ -4875,11 +4876,13 @@ void A_CapeChase(mobj_t *actor) return; } - foffsetx = P_ReturnThrustX(chaser, chaser->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); - foffsety = P_ReturnThrustY(chaser, chaser->angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + angle = (chaser->player ? chaser->player->drawangle : chaser->angle); - boffsetx = P_ReturnThrustX(chaser, chaser->angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); - boffsety = P_ReturnThrustY(chaser, chaser->angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); + foffsetx = P_ReturnThrustX(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + foffsety = P_ReturnThrustY(chaser, angle, FixedMul((locvar2 >> 16)*FRACUNIT, actor->scale)); + + boffsetx = P_ReturnThrustX(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); + boffsety = P_ReturnThrustY(chaser, angle-ANGLE_90, FixedMul((locvar2 & 65535)*FRACUNIT, actor->scale)); P_UnsetThingPosition(actor); actor->x = chaser->x + foffsetx + boffsetx; @@ -4896,7 +4899,7 @@ void A_CapeChase(mobj_t *actor) actor->flags2 &= ~MF2_OBJECTFLIP; actor->z = chaser->z + FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale); } - actor->angle = chaser->angle; + actor->angle = angle; P_SetThingPosition(actor); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 39682a7ef..945451192 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9140,6 +9140,7 @@ void P_AfterPlayerSpawn(INT32 playernum) } SV_SpawnPlayer(playernum, mobj->x, mobj->y, mobj->angle); + p->drawangle = mobj->angle; if (camera.chase) { diff --git a/src/p_saveg.c b/src/p_saveg.c index 6abb4d14c..0e6e79319 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -126,6 +126,7 @@ static void P_NetArchivePlayers(void) // no longer send ticcmds, player name, skin, or color WRITEANGLE(save_p, players[i].aiming); + WRITEANGLE(save_p, players[i].drawangle); WRITEANGLE(save_p, players[i].awayviewaiming); WRITEINT32(save_p, players[i].awayviewtics); WRITEINT32(save_p, players[i].rings); @@ -306,6 +307,7 @@ static void P_NetUnArchivePlayers(void) // (that data is handled in the server config now) players[i].aiming = READANGLE(save_p); + players[i].drawangle = READANGLE(save_p); players[i].awayviewaiming = READANGLE(save_p); players[i].awayviewtics = READINT32(save_p); players[i].rings = READINT32(save_p); diff --git a/src/p_user.c b/src/p_user.c index 905c3be62..a5a951a53 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9194,6 +9194,19 @@ void P_PlayerThink(player_t *player) if (!player->mo) return; // P_MovePlayer removed player->mo. + if (player->climbing // stuff where the direction is forced at all times + || G_RingSlingerGametype()) // no firing rings in directions your player isn't aiming + player->drawangle = player->mo->angle; + else if (P_PlayerInPain(player) && (player->mo->momx || player->mo->momy)) + player->drawangle = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0); + else if (cmd->forwardmove || cmd->sidemove || cmd->buttons) // only when you're pressing buttons + { + if (player->mo->momx || player->mo->momy) // only when you're moing + player->drawangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + else + player->drawangle = player->mo->angle; // spindash, etc + } + // Unset statis flags after moving. // In other words, if you manually set stasis via code, // it lasts for one tic. diff --git a/src/r_things.c b/src/r_things.c index e9080dc05..66d31079a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1210,7 +1210,7 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate != SRF_SINGLE || papersprite) { - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle); if (papersprite) ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT)); } From 90f7ae0188f7492200387d038e8beb0f42e525b8 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 6 Feb 2017 17:31:48 +0000 Subject: [PATCH 02/61] * Handle more missing cases where it should've been forced - namely analog mode, shield abilities, and waterslides * Have special handling for carrying. * Use rmom* instead of mom* - so conveyors are handled properly --- src/p_map.c | 20 ++++++++++++-------- src/p_user.c | 46 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 9d1991237..e4d873370 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -190,16 +190,20 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (spring->flags & MF_ENEMY) // Spring shells P_SetTarget(&spring->target, object); - if (horizspeed && object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0) + if (horizspeed) { - object->angle = spring->angle; - - if (!demoplayback || P_AnalogMove(object->player)) + object->player->drawangle = spring->angle; + if (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0) { - if (object->player == &players[consoleplayer]) - localangle = spring->angle; - else if (object->player == &players[secondarydisplayplayer]) - localangle2 = spring->angle; + object->angle = spring->angle; + + if (!demoplayback || P_AnalogMove(object->player)) + { + if (object->player == &players[consoleplayer]) + localangle = spring->angle; + else if (object->player == &players[secondarydisplayplayer]) + localangle2 = spring->angle; + } } } diff --git a/src/p_user.c b/src/p_user.c index a5a951a53..a3beee04b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -845,6 +845,7 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale); } + player->drawangle = ang + ANGLE_180; P_InstaThrust(player->mo, ang, fallbackspeed); } @@ -7082,6 +7083,7 @@ static void P_MovePlayer(player_t *player) case SH_FLAMEAURA: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale)); + player->drawangle = player->mo->angle; S_StartSound(player->mo, sfx_s3k43); default: break; @@ -7789,12 +7791,16 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target // change angle source->angle = R_PointToAngle2(source->x, source->y, enemy->x, enemy->y); - if (source->player && (!demoplayback || P_AnalogMove(source->player))) + if (source->player) { - if (source->player == &players[consoleplayer]) - localangle = source->angle; - else if (source->player == &players[secondarydisplayplayer]) - localangle2 = source->angle; + source->player->drawangle = source->angle; + if (!demoplayback || P_AnalogMove(source->player)) + { + if (source->player == &players[consoleplayer]) + localangle = source->angle; + else if (source->player == &players[secondarydisplayplayer]) + localangle2 = source->angle; + } } // change slope @@ -9194,15 +9200,35 @@ void P_PlayerThink(player_t *player) if (!player->mo) return; // P_MovePlayer removed player->mo. - if (player->climbing // stuff where the direction is forced at all times + if ((player->climbing // stuff where the direction is forced at all times + || (player->pflags & (/*PF_JUMPED|*/PF_SLIDING|PF_NIGHTSMODE))) + || P_AnalogMove(player) // keep things synchronised up there, since the camera IS seperate from player motion when that happens || G_RingSlingerGametype()) // no firing rings in directions your player isn't aiming player->drawangle = player->mo->angle; - else if (P_PlayerInPain(player) && (player->mo->momx || player->mo->momy)) - player->drawangle = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0); + else if (P_PlayerInPain(player)) + ; + else if (player->powers[pw_carry] && player->mo->tracer) + { + switch (player->powers[pw_carry]) + { + case CR_PLAYER: + player->drawangle = (player->mo->tracer->player ? player->mo->tracer->player->drawangle : player->mo->tracer->angle); + break; + /* -- in case we wanted to have the camera freely movable during zoom tube style stuff + case CR_ZOOMTUBE: + case CR_ROPEHANG: + player->drawangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + break; + */ + default: + player->drawangle = player->mo->angle; + break; + } + } else if (cmd->forwardmove || cmd->sidemove || cmd->buttons) // only when you're pressing buttons { - if (player->mo->momx || player->mo->momy) // only when you're moing - player->drawangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + if (player->rmomx || player->rmomy) // only when you're moing + player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); else player->drawangle = player->mo->angle; // spindash, etc } From 371940205bad58071fad59dc26e2c8009e09b7cc Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 6 Feb 2017 18:11:33 +0000 Subject: [PATCH 03/61] ICE PHYSICS FUN https://gfycat.com/ActualComplicatedBonobo --- src/p_user.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index a3beee04b..f69e276d8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -6687,8 +6687,6 @@ static void P_MovePlayer(player_t *player) if (!player->mo->momx && !player->mo->momy && !player->mo->momz && player->panim == PA_WALK) P_SetPlayerMobjState(player->mo, S_PLAY_STND); - player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame. - ////////////////// //GAMEPLAY STUFF// ////////////////// @@ -9227,12 +9225,16 @@ void P_PlayerThink(player_t *player) } else if (cmd->forwardmove || cmd->sidemove || cmd->buttons) // only when you're pressing buttons { - if (player->rmomx || player->rmomy) // only when you're moing + if (player->mo->movefactor < FRACUNIT) // hilarious absence of traction! + player->drawangle = player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<rmomx || player->rmomy) // only when you're moing player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); else player->drawangle = player->mo->angle; // spindash, etc } + player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame. + // Unset statis flags after moving. // In other words, if you manually set stasis via code, // it lasts for one tic. From 61ec5998308b9900f638b99c8ea25bbbe50e1214 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 6 Feb 2017 20:19:17 +0000 Subject: [PATCH 04/61] * Handles spindash, etc better. * Handled better up against walls. * Now always catches thok and thoklikes. --- src/p_mobj.c | 2 ++ src/p_user.c | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 945451192..cc4c2d2a4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2189,6 +2189,8 @@ void P_XYMovement(mobj_t *mo) #endif P_SlideMove(mo); + if (player) + mo->flags |= MF_SLIDEME; xmove = ymove = 0; #ifdef ESLOPE diff --git a/src/p_user.c b/src/p_user.c index f69e276d8..f7c57df50 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4108,6 +4108,8 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->normalspeed, player->mo->scale)*(80-player->flyangle - (player->actionspd>>FRACBITS)/2)/80); else P_InstaThrust(player->mo, player->mo->angle, ((FixedMul(player->normalspeed - player->actionspd/4, player->mo->scale))*2)/3); + + player->drawangle = player->mo->angle; } } } @@ -4181,6 +4183,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } P_InstaThrust(player->mo, player->mo->angle, FixedMul(actionspd, player->mo->scale)); + player->drawangle = player->mo->angle; if (maptol & TOL_2D) { @@ -9199,7 +9202,7 @@ void P_PlayerThink(player_t *player) return; // P_MovePlayer removed player->mo. if ((player->climbing // stuff where the direction is forced at all times - || (player->pflags & (/*PF_JUMPED|*/PF_SLIDING|PF_NIGHTSMODE))) + || (player->pflags & (/*PF_JUMPED|*/PF_STARTDASH|PF_GLIDING|PF_SLIDING|PF_NIGHTSMODE))) || P_AnalogMove(player) // keep things synchronised up there, since the camera IS seperate from player motion when that happens || G_RingSlingerGametype()) // no firing rings in directions your player isn't aiming player->drawangle = player->mo->angle; @@ -9223,16 +9226,18 @@ void P_PlayerThink(player_t *player) break; } } - else if (cmd->forwardmove || cmd->sidemove || cmd->buttons) // only when you're pressing buttons + else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { - if (player->mo->movefactor < FRACUNIT) // hilarious absence of traction! + if ((player->mo->movefactor < FRACUNIT) // hilarious absence of traction! + || (player->mo->flags & MF_SLIDEME) + || !(player->rmomx || player->rmomy)) // adjust to new angle player->drawangle = player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<rmomx || player->rmomy) // only when you're moing - player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); else - player->drawangle = player->mo->angle; // spindash, etc + player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); } + + player->mo->flags &= ~MF_SLIDEME; player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame. // Unset statis flags after moving. From 0e40299f3e254b7ec30c2d7e8c56759d560c9cec Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 6 Feb 2017 20:36:21 +0000 Subject: [PATCH 05/61] Replace hacky flag abuse with timer (which can be used later when developing pushing sprites). --- src/d_player.h | 1 + src/dehacked.c | 1 + src/p_mobj.c | 2 +- src/p_user.c | 5 +++-- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 01c8ee38e..dd6855786 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -241,6 +241,7 @@ typedef enum pw_underwater, // underwater timer pw_spacetime, // In space, no one can hear you spin! pw_extralife, // Extra Life timer + pw_pushing, pw_super, // Are you super? pw_gravityboots, // gravity boots diff --git a/src/dehacked.c b/src/dehacked.c index c71c55ac1..dda17a2e5 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7118,6 +7118,7 @@ static const char *const POWERS_LIST[] = { "UNDERWATER", // underwater timer "SPACETIME", // In space, no one can hear you spin! "EXTRALIFE", // Extra Life timer + "PUSHING", "SUPER", // Are you super? "GRAVITYBOOTS", // gravity boots diff --git a/src/p_mobj.c b/src/p_mobj.c index cc4c2d2a4..23d917689 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2190,7 +2190,7 @@ void P_XYMovement(mobj_t *mo) P_SlideMove(mo); if (player) - mo->flags |= MF_SLIDEME; + player->powers[pw_pushing] = 3; xmove = ymove = 0; #ifdef ESLOPE diff --git a/src/p_user.c b/src/p_user.c index f7c57df50..1a87c92da 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9229,7 +9229,7 @@ void P_PlayerThink(player_t *player) else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { if ((player->mo->movefactor < FRACUNIT) // hilarious absence of traction! - || (player->mo->flags & MF_SLIDEME) + || (player->powers[pw_pushing]) || !(player->rmomx || player->rmomy)) // adjust to new angle player->drawangle = player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<mo->flags &= ~MF_SLIDEME; + if (player->powers[pw_pushing]) + player->powers[pw_pushing]--; player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame. // Unset statis flags after moving. From 006d25eaac3bc426a714517af5605c8b9fd9c8ce Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 6 Feb 2017 23:34:19 +0000 Subject: [PATCH 06/61] * On Mystic's request, tweak to conditions to always show immediate feedback for everything except thokking. * Melee attack hotfix. --- src/p_user.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/p_user.c b/src/p_user.c index 1a87c92da..95f1f0482 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3857,6 +3857,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) player->mo->momy = player->cmomy = 0; P_SetObjectMomZ(player->mo, player->mindash, false); P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale)); + player->drawangle = player->mo->angle; P_SetPlayerMobjState(player->mo, S_PLAY_MELEE); player->pflags |= PF_USEDOWN; S_StartSound(player->mo, sfx_s3k8b); @@ -9228,8 +9229,16 @@ void P_PlayerThink(player_t *player) } else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { +#if 1 + if (!((player->pflags & PF_SPINNING) + || ((player->pflags & PF_THOKKED) + && (player->charability == CA_THOK + || player->charability == CA_HOMINGTHOK + || player->charability == CA_JUMPTHOK))) +#else if ((player->mo->movefactor < FRACUNIT) // hilarious absence of traction! || (player->powers[pw_pushing]) +#endif || !(player->rmomx || player->rmomy)) // adjust to new angle player->drawangle = player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove< Date: Tue, 7 Feb 2017 10:41:46 +0000 Subject: [PATCH 07/61] This makes more sense. --- src/p_user.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 95f1f0482..385b361b1 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9230,11 +9230,7 @@ void P_PlayerThink(player_t *player) else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { #if 1 - if (!((player->pflags & PF_SPINNING) - || ((player->pflags & PF_THOKKED) - && (player->charability == CA_THOK - || player->charability == CA_HOMINGTHOK - || player->charability == CA_JUMPTHOK))) + if (!(player->pflags & (PF_JUMPED|PF_SPINNING)) #else if ((player->mo->movefactor < FRACUNIT) // hilarious absence of traction! || (player->powers[pw_pushing]) From 66d160be43c3f46de13a668fc207350b2e8ddb20 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 7 Feb 2017 10:55:42 +0000 Subject: [PATCH 08/61] On second thoughts, this is better. --- src/p_user.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 385b361b1..865b05af0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9230,7 +9230,8 @@ void P_PlayerThink(player_t *player) else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { #if 1 - if (!(player->pflags & (PF_JUMPED|PF_SPINNING)) + if (!((player->pflags & PF_SPINNING) + || ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPSPIN))) #else if ((player->mo->movefactor < FRACUNIT) // hilarious absence of traction! || (player->powers[pw_pushing]) From b2de969d5253c3ef2055a23da2fbe3a3a3c89c7d Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 7 Feb 2017 13:13:03 +0000 Subject: [PATCH 09/61] Refactor. --- src/p_user.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 865b05af0..ba0643da6 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9209,7 +9209,7 @@ void P_PlayerThink(player_t *player) player->drawangle = player->mo->angle; else if (P_PlayerInPain(player)) ; - else if (player->powers[pw_carry] && player->mo->tracer) + else if (player->powers[pw_carry] && player->mo->tracer) // carry { switch (player->powers[pw_carry]) { @@ -9227,16 +9227,18 @@ void P_PlayerThink(player_t *player) break; } } + else if ((player->pflags & PF_SPINNING) && (player->rmomx || player->rmomy)) // spin force + player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { #if 1 - if (!((player->pflags & PF_SPINNING) - || ((player->pflags & PF_JUMPED) && !(player->charflags & SF_NOJUMPSPIN))) + if (!((player->pflags & PF_JUMPED) + && !(player->charflags & SF_NOJUMPSPIN)) #else if ((player->mo->movefactor < FRACUNIT) // hilarious absence of traction! || (player->powers[pw_pushing]) #endif - || !(player->rmomx || player->rmomy)) // adjust to new angle + || !(player->rmomx || player->rmomy)) // prevent a flicker when just starting out player->drawangle = player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); From a684f2ee7b9ce5b65007e429d41f936bf525bd4e Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 8 Feb 2017 12:29:45 +0000 Subject: [PATCH 10/61] Fix for ghosts and thok items. --- src/p_user.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index ba0643da6..c82051bee 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1507,7 +1507,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->color = mobj->color; - ghost->angle = mobj->angle; + ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); ghost->sprite = mobj->sprite; ghost->sprite2 = mobj->sprite2; ghost->frame = mobj->frame; @@ -1557,7 +1557,7 @@ void P_SpawnThokMobj(player_t *player) mobj = P_SpawnMobj(player->mo->x, player->mo->y, zheight, type); // set to player's angle, just in case - mobj->angle = player->mo->angle; + mobj->angle = player->drawangle; // color and skin mobj->color = player->mo->color; @@ -1611,7 +1611,7 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type) mobj = P_SpawnMobj(player->mo->x, player->mo->y, zheight, type); // set to player's angle, just in case - mobj->angle = player->mo->angle; + mobj->angle = player->drawangle; // color and skin mobj->color = player->mo->color; From aa6f170daf0ce7014d5ded6505988e6dca518fda Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 8 Feb 2017 12:51:31 +0000 Subject: [PATCH 11/61] Spindash averaging experiment. Much nicer - and clearly communicates the forcing of direction - a little better than the instant jump. --- src/p_user.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index c82051bee..244abc561 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3761,7 +3761,7 @@ static void P_DoSpinDashDust(player_t *player) prandom[2] = P_RandomFixed()<<3; // P_RandomByte()<<11 P_SetObjectMomZ(particle, player->dashspeed/50 + prandom[0], false); P_InstaThrust(particle, - player->mo->angle + (prandom[1]*ANG1), + player->drawangle + (prandom[1]*ANG1), -FixedMul(player->dashspeed/12 + FRACUNIT + prandom[2], player->mo->scale)); P_TryMove(particle, particle->x+particle->momx, particle->y+particle->momy, true); } @@ -9203,10 +9203,19 @@ void P_PlayerThink(player_t *player) return; // P_MovePlayer removed player->mo. if ((player->climbing // stuff where the direction is forced at all times - || (player->pflags & (/*PF_JUMPED|*/PF_STARTDASH|PF_GLIDING|PF_SLIDING|PF_NIGHTSMODE))) + || (player->pflags & (PF_GLIDING|PF_SLIDING|PF_NIGHTSMODE))) || P_AnalogMove(player) // keep things synchronised up there, since the camera IS seperate from player motion when that happens || G_RingSlingerGametype()) // no firing rings in directions your player isn't aiming player->drawangle = player->mo->angle; + else if (player->pflags & PF_STARTDASH) // fun spindash experiment + { + angle_t diff = (player->mo->angle - player->drawangle); + if (diff > ANGLE_180) + diff = InvAngle(InvAngle(diff)/4); + else + diff /= 4; + player->drawangle += diff; + } else if (P_PlayerInPain(player)) ; else if (player->powers[pw_carry] && player->mo->tracer) // carry From af2cf44f9e7b26e0d5f2bb802be651a9430987ec Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 5 Apr 2017 16:43:23 +0100 Subject: [PATCH 12/61] * Skidding doesn't turn. * Rolling only turns on keypresses at minimum horizontal speed. --- src/p_user.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 1ae229528..c3b430482 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9461,8 +9461,10 @@ void P_PlayerThink(player_t *player) break; } } - else if ((player->pflags & PF_SPINNING) && (player->rmomx || player->rmomy)) // spin force + else if ((player->pflags & PF_SPINNING) && (abs(player->rmomx) > 5*player->mo->scale || abs(player->rmomy) > 5*player->mo->scale)) // spin force player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); + else if (player->skidtime) + ; else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { angle_t diff = ((player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<drawangle); @@ -9471,17 +9473,6 @@ void P_PlayerThink(player_t *player) else diff /= 4; player->drawangle += diff; -/*#if 1 - if (!((player->pflags & PF_JUMPED) - && !(player->charflags & SF_NOJUMPSPIN)) -#else - if ((player->mo->movefactor < FRACUNIT) // hilarious absence of traction! - || (player->powers[pw_pushing]) -#endif - || !(player->rmomx || player->rmomy)) // prevent a flicker when just starting out - player->drawangle = player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);*/ } From 7d970fa2f7b078aaa0439717d2d755508b5a8171 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 5 Apr 2017 20:18:40 +0100 Subject: [PATCH 13/61] Tweaked CA2's relationship. --- 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 c3b430482..5846d0b68 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3874,7 +3874,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) #define zpos(posmo) (posmo->z + (posmo->height - mobjinfo[player->revitem].height)/2) if (lockon) { - player->drawangle = player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); + player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); bullet = P_SpawnPointMissile(player->mo, lockon->x, lockon->y, zpos(lockon), player->revitem, player->mo->x, player->mo->y, zpos(player->mo)); if (!demoplayback || P_AnalogMove(player)) { @@ -3894,6 +3894,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) bullet->momy >>= 1; } } + player->drawangle = player->mo->angle; #undef zpos P_SetTarget(&player->mo->tracer, NULL); @@ -9463,7 +9464,7 @@ void P_PlayerThink(player_t *player) } else if ((player->pflags & PF_SPINNING) && (abs(player->rmomx) > 5*player->mo->scale || abs(player->rmomy) > 5*player->mo->scale)) // spin force player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); - else if (player->skidtime) + else if (((player->charability2 == CA2_GUNSLINGER || player->charability2 == CA2_MELEE) && player->panim == PA_ABILITY2) || player->pflags & PF_STASIS || player->skidtime) ; else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { From 5eda275335e5426127d1c6121f436137ffb9ecdd Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 7 Apr 2017 13:08:31 +0100 Subject: [PATCH 14/61] Consider objectplace --- src/m_cheat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index 8ae670662..8eb9551a8 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1093,7 +1093,7 @@ void OP_ObjectplaceMovement(player_t *player) ticcmd_t *cmd = &player->cmd; if (!player->climbing && (netgame || !cv_analog.value || (player->pflags & PF_SPINNING))) - player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */); + player->drawangle = player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */); ticruned++; if (!(cmd->angleturn & TICCMD_RECEIVED)) From 2636375f94cadf490651c8b2cbce175289080dfb Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 7 Apr 2017 16:51:43 +0100 Subject: [PATCH 15/61] GL supporting. --- src/hardware/hw_main.c | 2 +- src/hardware/hw_md2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 7bc12ba75..ac4c896bf 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5128,7 +5128,7 @@ static void HWR_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle); if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right rot = 6; // F7 slot diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 7edf02db0..29a3e72db 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1496,7 +1496,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (sprframe->rotate) { - const fixed_t anglef = AngleFixed(spr->mobj->angle); + const fixed_t anglef = AngleFixed((spr->mobj->player ? spr->mobj->player->drawangle : spr->mobj->angle)); p.angley = FIXED_TO_FLOAT(anglef); } else From 7e4327293236eb3d38cefe692ef1bddb1f1d345b Mon Sep 17 00:00:00 2001 From: yellowtd Date: Tue, 18 Apr 2017 17:23:23 -0400 Subject: [PATCH 16/61] begin titlemap idk my bff jill --- src/d_main.c | 18 ++++++++++++------ src/f_finale.c | 21 +++++++++++++++++---- src/g_game.c | 1 + src/p_user.c | 2 +- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index b23ffebb4..78a2b2d96 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -318,6 +318,12 @@ static void D_Display(void) // do buffered drawing switch (gamestate) { + case GS_TITLESCREEN: + if (!gamemap) { + F_TitleScreenDrawer(); + break; + } + // Intentional fall-through case GS_LEVEL: if (!gametic) break; @@ -366,10 +372,6 @@ static void D_Display(void) HU_Drawer(); break; - case GS_TITLESCREEN: - F_TitleScreenDrawer(); - break; - case GS_WAITINGPLAYERS: // The clientconnect drawer is independent... case GS_DEDICATEDSERVER: @@ -379,9 +381,10 @@ static void D_Display(void) // clean up border stuff // see if the border needs to be initially drawn - if (gamestate == GS_LEVEL) + if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && gamemap)) { // draw the view directly + if (!automapactive && !dedicated && cv_renderview.value) { if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) @@ -436,7 +439,10 @@ static void D_Display(void) lastdraw = false; } - ST_Drawer(); + if (gamestate == GS_LEVEL) + ST_Drawer(); + else + F_TitleScreenDrawer(); HU_Drawer(); } diff --git a/src/f_finale.c b/src/f_finale.c index 167fdd880..2eba96bb7 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -31,6 +31,7 @@ #include "m_random.h" #include "y_inter.h" #include "m_cond.h" +#include "p_local.h" // Stage of animation: // 0 = text, 1 = art screen @@ -999,7 +1000,7 @@ static const char *credits[] = { "", "\1Sprite Artists", "Odi \"Iceman404\" Atunzu", - "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: + "Victor \"VAdaPEGA\" Ara\x1Fjo", // Ara�jo -- sorry for our limited font! D: "Jim \"MotorRoach\" DeMello", "Desmond \"Blade\" DesJardins", "Sherman \"CoatRack\" DesJardins", @@ -1423,13 +1424,16 @@ void F_StartTitleScreen(void) finalecount = 0; else wipegamestate = GS_TITLESCREEN; + + gamemap = 533; titlescrollspeed = (int32_t)ANG1; //@TODO don't hardcode bich + G_DoLoadLevel(true); G_SetGamestate(GS_TITLESCREEN); - CON_ClearHUD(); + players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) + //CON_ClearHUD(); // IWAD dependent stuff. S_ChangeMusicInternal("_title", looptitle); - animtimer = 0; demoDelayLeft = demoDelayTime; @@ -1459,7 +1463,9 @@ void F_TitleScreenDrawer(void) return; // We likely came here from retrying. Don't do a damn thing. // Draw that sky! - F_SkyScroll(titlescrollspeed); + if (!gamemap) { + F_SkyScroll(titlescrollspeed); + } // Don't draw outside of the title screewn, or if the patch isn't there. if (!ttwing || (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)) @@ -1513,6 +1519,13 @@ void F_TitleScreenTicker(boolean run) if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN) return; + // Do a lil' camera spin if a title map is loaded. + if (gamemap) { + camera.x = camera.y = camera.height = camera.aiming = 0; + camera.z = 128*FRACUNIT; + camera.angle += titlescrollspeed; + } + // no demos to play? or, are they disabled? if (!cv_rollingdemos.value || !numDemos) return; diff --git a/src/g_game.c b/src/g_game.c index 1eef85ada..39fdd8ae0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1985,6 +1985,7 @@ void G_Ticker(boolean run) break; case GS_TITLESCREEN: + if (gamemap) P_Ticker(run); // then intentionally fall through case GS_WAITINGPLAYERS: F_TitleScreenTicker(run); break; diff --git a/src/p_user.c b/src/p_user.c index 905c3be62..5d55e9d21 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -165,7 +165,7 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move) boolean P_AutoPause(void) { // Don't pause even on menu-up or focus-lost in netgames or record attack - if (netgame || modeattacking) + if (netgame || modeattacking || gamestate == GS_TITLESCREEN) return false; return (menuactive || window_notinfocus); From 1c93b07c863612dbcae8977b69c78910e72eef97 Mon Sep 17 00:00:00 2001 From: yellowtd Date: Tue, 18 Apr 2017 17:36:54 -0400 Subject: [PATCH 17/61] Titlemap - Maincfg variables, unplayability crash fixes --- src/dehacked.c | 19 ++++++++++ src/doomstat.h | 3 ++ src/f_finale.c | 98 +++++++++++++++++++++++++++++++------------------- src/f_finale.h | 2 ++ src/g_game.c | 3 ++ 5 files changed, 89 insertions(+), 36 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 5ba5d75d4..6734f1427 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3120,6 +3120,25 @@ static void readmaincfg(MYFILE *f) DEH_WriteUndoline(word, va("%d", looptitle), UNDO_NONE); looptitle = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); } + else if (fastcmp(word, "TITLEMAP")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + DEH_WriteUndoline(word, va("%d", titlemap), UNDO_NONE); + titlemap = (INT16)value; + } + else if (fastcmp(word, "HIDETITLEPICS")) + { + DEH_WriteUndoline(word, va("%d", hidetitlepics), UNDO_NONE); + hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + } else if (fastcmp(word, "TITLESCROLLSPEED")) { DEH_WriteUndoline(word, va("%d", titlescrollspeed), UNDO_NONE); diff --git a/src/doomstat.h b/src/doomstat.h index f1b7d2169..013ee0835 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -124,6 +124,9 @@ extern INT16 spstage_start; extern INT16 sstage_start; extern INT16 sstage_end; +extern INT16 titlemap; +extern boolean hidetitlepics; + extern boolean looptitle; extern boolean useNightsSS; diff --git a/src/f_finale.c b/src/f_finale.c index 2eba96bb7..beeb0a2ea 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1425,11 +1425,28 @@ void F_StartTitleScreen(void) else wipegamestate = GS_TITLESCREEN; - gamemap = 533; titlescrollspeed = (int32_t)ANG1; //@TODO don't hardcode bich - G_DoLoadLevel(true); - G_SetGamestate(GS_TITLESCREEN); - players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) - //CON_ClearHUD(); + if (titlemap) + { + gamemap = titlemap; + + if (!mapheaderinfo[gamemap-1]) + P_AllocMapHeader(gamemap-1); + + G_DoLoadLevel(true); + G_SetGamestate(GS_TITLESCREEN); + players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) + //CON_ClearHUD(); + } + else + { + gamemap = 0; + + if (!mapheaderinfo[gamemap-1]) + P_AllocMapHeader(gamemap-1); + + G_SetGamestate(GS_TITLESCREEN); + CON_ClearHUD(); + } // IWAD dependent stuff. @@ -1471,42 +1488,51 @@ void F_TitleScreenDrawer(void) if (!ttwing || (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)) return; - V_DrawScaledPatch(30, 14, 0, ttwing); - - if (finalecount < 57) + // rei|miru: use title pics? + if (hidetitlepics) { - if (finalecount == 35) - V_DrawScaledPatch(115, 15, 0, ttspop1); - else if (finalecount == 36) - V_DrawScaledPatch(114, 15, 0,ttspop2); - else if (finalecount == 37) - V_DrawScaledPatch(113, 15, 0,ttspop3); - else if (finalecount == 38) - V_DrawScaledPatch(112, 15, 0,ttspop4); - else if (finalecount == 39) - V_DrawScaledPatch(111, 15, 0,ttspop5); - else if (finalecount == 40) - V_DrawScaledPatch(110, 15, 0, ttspop6); - else if (finalecount >= 41 && finalecount <= 44) - V_DrawScaledPatch(109, 15, 0, ttspop7); - else if (finalecount >= 45 && finalecount <= 48) - V_DrawScaledPatch(108, 12, 0, ttsprep1); - else if (finalecount >= 49 && finalecount <= 52) - V_DrawScaledPatch(107, 9, 0, ttsprep2); - else if (finalecount >= 53 && finalecount <= 56) - V_DrawScaledPatch(106, 6, 0, ttswip1); - V_DrawScaledPatch(93, 106, 0, ttsonic); + return; } else { - V_DrawScaledPatch(93, 106, 0,ttsonic); - if (finalecount/5 & 1) - V_DrawScaledPatch(100, 3, 0,ttswave1); - else - V_DrawScaledPatch(100,3, 0,ttswave2); - } + V_DrawScaledPatch(30, 14, 0, ttwing); - V_DrawScaledPatch(48, 142, 0,ttbanner); + if (finalecount < 57) + { + if (finalecount == 35) + V_DrawScaledPatch(115, 15, 0, ttspop1); + else if (finalecount == 36) + V_DrawScaledPatch(114, 15, 0,ttspop2); + else if (finalecount == 37) + V_DrawScaledPatch(113, 15, 0,ttspop3); + else if (finalecount == 38) + V_DrawScaledPatch(112, 15, 0,ttspop4); + else if (finalecount == 39) + V_DrawScaledPatch(111, 15, 0,ttspop5); + else if (finalecount == 40) + V_DrawScaledPatch(110, 15, 0, ttspop6); + else if (finalecount >= 41 && finalecount <= 44) + V_DrawScaledPatch(109, 15, 0, ttspop7); + else if (finalecount >= 45 && finalecount <= 48) + V_DrawScaledPatch(108, 12, 0, ttsprep1); + else if (finalecount >= 49 && finalecount <= 52) + V_DrawScaledPatch(107, 9, 0, ttsprep2); + else if (finalecount >= 53 && finalecount <= 56) + V_DrawScaledPatch(106, 6, 0, ttswip1); + V_DrawScaledPatch(93, 106, 0, ttsonic); + } + else + { + V_DrawScaledPatch(93, 106, 0,ttsonic); + if (finalecount/5 & 1) + V_DrawScaledPatch(100, 3, 0,ttswave1); + else + V_DrawScaledPatch(100,3, 0,ttswave2); + } + + V_DrawScaledPatch(48, 142, 0,ttbanner); + + } } // (no longer) De-Demo'd Title Screen diff --git a/src/f_finale.h b/src/f_finale.h index 1f23643be..1e4d3a1e3 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -60,6 +60,8 @@ void F_StartContinue(void); void F_ContinueTicker(void); void F_ContinueDrawer(void); +extern INT16 titlemap; +extern boolean hidetitlepics; extern INT32 titlescrollspeed; // diff --git a/src/g_game.c b/src/g_game.c index 39fdd8ae0..3d89fd6db 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -120,6 +120,9 @@ INT16 spstage_start; INT16 sstage_start; INT16 sstage_end; +INT16 titlemap; +boolean hidetitlepics = false; + boolean looptitle = false; boolean useNightsSS = false; From 217f7ebd386f309d82ff15b68652fb32c7d0ab8e Mon Sep 17 00:00:00 2001 From: yellowtd Date: Tue, 18 Apr 2017 17:45:43 -0400 Subject: [PATCH 18/61] miru asked me for help and im a smelly toast * Fix Crashes With Respect To Switching Between The Normal Title And Her Magic One * Clean Up A Bit Of Code --- src/d_main.c | 9 ++--- src/f_finale.c | 89 ++++++++++++++++++++++++-------------------------- src/f_finale.h | 3 +- src/g_game.c | 4 +-- 4 files changed, 50 insertions(+), 55 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 78a2b2d96..4fb55d728 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -319,7 +319,7 @@ static void D_Display(void) switch (gamestate) { case GS_TITLESCREEN: - if (!gamemap) { + if (!titlemapinaction) { F_TitleScreenDrawer(); break; } @@ -381,7 +381,7 @@ static void D_Display(void) // clean up border stuff // see if the border needs to be initially drawn - if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && gamemap)) + if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) { // draw the view directly @@ -440,11 +440,12 @@ static void D_Display(void) } if (gamestate == GS_LEVEL) + { ST_Drawer(); + HU_Drawer(); + } else F_TitleScreenDrawer(); - - HU_Drawer(); } // change gamma if needed diff --git a/src/f_finale.c b/src/f_finale.c index beeb0a2ea..9959ce0fc 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -32,11 +32,13 @@ #include "y_inter.h" #include "m_cond.h" #include "p_local.h" +#include "p_setup.h" // Stage of animation: // 0 = text, 1 = art screen static INT32 finalecount; INT32 titlescrollspeed = 80; +boolean titlemapinaction = false; static INT32 timetonext; // Delay between screen changes static INT32 continuetime; // Short delay when continuing @@ -1427,27 +1429,26 @@ void F_StartTitleScreen(void) if (titlemap) { + titlemapinaction = true; gamemap = titlemap; if (!mapheaderinfo[gamemap-1]) P_AllocMapHeader(gamemap-1); G_DoLoadLevel(true); - G_SetGamestate(GS_TITLESCREEN); players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) + camera.subsector = NULL; // toast is filthy too //CON_ClearHUD(); } else { - gamemap = 0; - - if (!mapheaderinfo[gamemap-1]) - P_AllocMapHeader(gamemap-1); - - G_SetGamestate(GS_TITLESCREEN); + titlemapinaction = false; + gamemap = 1; // g_game.c CON_ClearHUD(); } + G_SetGamestate(GS_TITLESCREEN); + // IWAD dependent stuff. S_ChangeMusicInternal("_title", looptitle); @@ -1480,9 +1481,8 @@ void F_TitleScreenDrawer(void) return; // We likely came here from retrying. Don't do a damn thing. // Draw that sky! - if (!gamemap) { + if (!titlemapinaction) F_SkyScroll(titlescrollspeed); - } // Don't draw outside of the title screewn, or if the patch isn't there. if (!ttwing || (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)) @@ -1490,49 +1490,44 @@ void F_TitleScreenDrawer(void) // rei|miru: use title pics? if (hidetitlepics) - { return; + + V_DrawScaledPatch(30, 14, 0, ttwing); + + if (finalecount < 57) + { + if (finalecount == 35) + V_DrawScaledPatch(115, 15, 0, ttspop1); + else if (finalecount == 36) + V_DrawScaledPatch(114, 15, 0,ttspop2); + else if (finalecount == 37) + V_DrawScaledPatch(113, 15, 0,ttspop3); + else if (finalecount == 38) + V_DrawScaledPatch(112, 15, 0,ttspop4); + else if (finalecount == 39) + V_DrawScaledPatch(111, 15, 0,ttspop5); + else if (finalecount == 40) + V_DrawScaledPatch(110, 15, 0, ttspop6); + else if (finalecount >= 41 && finalecount <= 44) + V_DrawScaledPatch(109, 15, 0, ttspop7); + else if (finalecount >= 45 && finalecount <= 48) + V_DrawScaledPatch(108, 12, 0, ttsprep1); + else if (finalecount >= 49 && finalecount <= 52) + V_DrawScaledPatch(107, 9, 0, ttsprep2); + else if (finalecount >= 53 && finalecount <= 56) + V_DrawScaledPatch(106, 6, 0, ttswip1); + V_DrawScaledPatch(93, 106, 0, ttsonic); } else { - V_DrawScaledPatch(30, 14, 0, ttwing); - - if (finalecount < 57) - { - if (finalecount == 35) - V_DrawScaledPatch(115, 15, 0, ttspop1); - else if (finalecount == 36) - V_DrawScaledPatch(114, 15, 0,ttspop2); - else if (finalecount == 37) - V_DrawScaledPatch(113, 15, 0,ttspop3); - else if (finalecount == 38) - V_DrawScaledPatch(112, 15, 0,ttspop4); - else if (finalecount == 39) - V_DrawScaledPatch(111, 15, 0,ttspop5); - else if (finalecount == 40) - V_DrawScaledPatch(110, 15, 0, ttspop6); - else if (finalecount >= 41 && finalecount <= 44) - V_DrawScaledPatch(109, 15, 0, ttspop7); - else if (finalecount >= 45 && finalecount <= 48) - V_DrawScaledPatch(108, 12, 0, ttsprep1); - else if (finalecount >= 49 && finalecount <= 52) - V_DrawScaledPatch(107, 9, 0, ttsprep2); - else if (finalecount >= 53 && finalecount <= 56) - V_DrawScaledPatch(106, 6, 0, ttswip1); - V_DrawScaledPatch(93, 106, 0, ttsonic); - } + V_DrawScaledPatch(93, 106, 0,ttsonic); + if (finalecount/5 & 1) + V_DrawScaledPatch(100, 3, 0,ttswave1); else - { - V_DrawScaledPatch(93, 106, 0,ttsonic); - if (finalecount/5 & 1) - V_DrawScaledPatch(100, 3, 0,ttswave1); - else - V_DrawScaledPatch(100,3, 0,ttswave2); - } - - V_DrawScaledPatch(48, 142, 0,ttbanner); - + V_DrawScaledPatch(100,3, 0,ttswave2); } + + V_DrawScaledPatch(48, 142, 0,ttbanner); } // (no longer) De-Demo'd Title Screen @@ -1546,7 +1541,7 @@ void F_TitleScreenTicker(boolean run) return; // Do a lil' camera spin if a title map is loaded. - if (gamemap) { + if (titlemapinaction) { camera.x = camera.y = camera.height = camera.aiming = 0; camera.z = 128*FRACUNIT; camera.angle += titlescrollspeed; diff --git a/src/f_finale.h b/src/f_finale.h index 1e4d3a1e3..f710a74fb 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -60,9 +60,8 @@ void F_StartContinue(void); void F_ContinueTicker(void); void F_ContinueDrawer(void); -extern INT16 titlemap; -extern boolean hidetitlepics; extern INT32 titlescrollspeed; +extern boolean titlemapinaction; // // WIPE diff --git a/src/g_game.c b/src/g_game.c index 3d89fd6db..c8fa261f2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -120,7 +120,7 @@ INT16 spstage_start; INT16 sstage_start; INT16 sstage_end; -INT16 titlemap; +INT16 titlemap = 0; boolean hidetitlepics = false; boolean looptitle = false; @@ -1988,7 +1988,7 @@ void G_Ticker(boolean run) break; case GS_TITLESCREEN: - if (gamemap) P_Ticker(run); // then intentionally fall through + if (titlemapinaction) P_Ticker(run); // then intentionally fall through case GS_WAITINGPLAYERS: F_TitleScreenTicker(run); break; From eea7dc4224e8e016f44de83e07515f2b712ed88f Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 28 Mar 2017 17:54:54 +0100 Subject: [PATCH 19/61] Fixed titlemap wipe lasting too long/happening twice over --- src/d_main.c | 2 +- src/f_finale.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index 4fb55d728..e2cb35f32 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -302,7 +302,7 @@ static void D_Display(void) if (rendermode != render_none) { // Fade to black first - if (gamestate != GS_LEVEL // fades to black on its own timing, always + if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) // fades to black on its own timing, always && wipedefs[wipedefindex] != UINT8_MAX) { F_WipeStartScreen(); diff --git a/src/f_finale.c b/src/f_finale.c index 9959ce0fc..50c94eec3 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1429,6 +1429,7 @@ void F_StartTitleScreen(void) if (titlemap) { + gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = true; gamemap = titlemap; @@ -1439,6 +1440,8 @@ void F_StartTitleScreen(void) players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) camera.subsector = NULL; // toast is filthy too //CON_ClearHUD(); + + wipegamestate = prevwipegamestate; } else { From b68d1ebdb36632327f75969c9d2d24dee25d8bf6 Mon Sep 17 00:00:00 2001 From: yellowtd Date: Mon, 3 Apr 2017 22:12:53 -0400 Subject: [PATCH 20/61] titlemap - fix game crash with skybox point game crash on skybox object use fix --- src/f_finale.c | 38 +++++++++++++++++++++++++++++++++++--- src/r_main.c | 2 +- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 50c94eec3..07812946d 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1436,9 +1436,42 @@ void F_StartTitleScreen(void) if (!mapheaderinfo[gamemap-1]) P_AllocMapHeader(gamemap-1); + maptol = mapheaderinfo[gamemap-1]->typeoflevel; + globalweather = mapheaderinfo[gamemap-1]->weather; + G_DoLoadLevel(true); players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) - camera.subsector = NULL; // toast is filthy too + //camera.subsector = NULL; // toast is filthy too + + // Set Default Position + mapthing_t *startpos; + if (playerstarts[0]) + startpos = playerstarts[0]; + else if (deathmatchstarts[0]) + startpos = deathmatchstarts[0]; + else + startpos = NULL; + + if (startpos) + { + camera.x = startpos->x << FRACBITS; + camera.y = startpos->y << FRACBITS; + camera.subsector = R_PointInSubsector(camera.x, camera.y); + camera.z = camera.subsector->sector->floorheight + ((startpos->options >> ZSHIFT) << FRACBITS); + camera.angle = (startpos->angle % 360)*ANG1; + camera.aiming = 0; + } + else + { + camera.x = camera.y = camera.z = camera.angle = camera.aiming = 0; + camera.subsector = NULL; // toast is filthy too + } + camera.chase = true; + camera.height = 0; + + //camera.x = camera.y = camera.height = camera.aiming = 0; + //camera.z = 128*FRACUNIT; + //CON_ClearHUD(); wipegamestate = prevwipegamestate; @@ -1545,8 +1578,7 @@ void F_TitleScreenTicker(boolean run) // Do a lil' camera spin if a title map is loaded. if (titlemapinaction) { - camera.x = camera.y = camera.height = camera.aiming = 0; - camera.z = 128*FRACUNIT; + // Default behavior camera.angle += titlescrollspeed; } diff --git a/src/r_main.c b/src/r_main.c index 4cff0ff83..c4ca7784b 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1000,7 +1000,7 @@ void R_SetupFrame(player_t *player, boolean skybox) chasecam = (cv_chasecam.value != 0); } - if (player->climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD) + if (player->climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN) chasecam = true; // force chasecam on else if (player->spectator) // no spectator chasecam chasecam = false; // force chasecam off From f70b89b22aad5d36172234805ef75a1bb2713e8f Mon Sep 17 00:00:00 2001 From: yellowtd Date: Thu, 20 Apr 2017 17:15:57 -0400 Subject: [PATCH 21/61] titlemap - support for map camera object allows a camera thing to be placed for alternate camera placement besides player and DM starts --- src/dehacked.c | 6 ++++++ src/f_finale.c | 42 +++++++++++++++++++++++++++++++++++++++--- src/p_mobj.c | 4 ++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 6734f1427..95ce0a862 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8595,6 +8595,12 @@ static inline int lib_getenum(lua_State *L) } else if (fastcmp(word,"paused")) { lua_pushboolean(L, paused); return 1; + } else if (fastcmp(word,"titlemap")) { + lua_pushinteger(L, titlemap); + return 1; + } else if (fastcmp(word,"titlemapinaction")) { + lua_pushboolean(L, titlemapinaction); + return 1; } else if (fastcmp(word,"gametype")) { lua_pushinteger(L, gametype); return 1; diff --git a/src/f_finale.c b/src/f_finale.c index 07812946d..efc87e040 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1576,10 +1576,46 @@ void F_TitleScreenTicker(boolean run) if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN) return; - // Do a lil' camera spin if a title map is loaded. + thinker_t *th; + mobj_t *mo2; + mobj_t *cameraref = NULL; + + // Execute the titlemap camera settings if (titlemapinaction) { - // Default behavior - camera.angle += titlescrollspeed; + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_ALTVIEWMAN) + continue; + + if (mo2) + { + cameraref = mo2; + break; + } + else + break; + } + + if (cameraref) + { + camera.x = cameraref->x; + camera.y = cameraref->y; + camera.z = cameraref->z; + camera.angle = cameraref->angle; + camera.aiming = cameraref->cusval; + } + else + { + // Default behavior: Do a lil' camera spin if a title map is loaded; + // TODO: titlescrollspeed scrolls slow here because it is not an angle + //camera.angle += titlescrollspeed; + } } // no demos to play? or, are they disabled? diff --git a/src/p_mobj.c b/src/p_mobj.c index 8f6b9797e..319845668 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -34,6 +34,7 @@ #ifdef ESLOPE #include "p_slopes.h" #endif +#include "f_finale.h" // protos. static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}}; @@ -8423,6 +8424,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) #endif switch (mobj->type) { + case MT_ALTVIEWMAN: + if (titlemapinaction) mobj->flags &= ~MF_NOTHINK; + break; case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: mobj->fuse = mobj->info->mass; break; From cf454dd6fcb17b3c30729888019aca2e8c7d7f84 Mon Sep 17 00:00:00 2001 From: yellowtd Date: Thu, 20 Apr 2017 19:18:07 -0400 Subject: [PATCH 22/61] titlemap - Fix impending doom (???) camera mobj search the last implimentation would have apparently stopped working eventually? Idk --- src/f_finale.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index efc87e040..e3a6e9164 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1590,16 +1590,14 @@ void F_TitleScreenTicker(boolean run) mo2 = (mobj_t *)th; + if (!mo2) + continue; + if (mo2->type != MT_ALTVIEWMAN) continue; - if (mo2) - { - cameraref = mo2; - break; - } - else - break; + cameraref = mo2; + break; } if (cameraref) @@ -1613,8 +1611,7 @@ void F_TitleScreenTicker(boolean run) else { // Default behavior: Do a lil' camera spin if a title map is loaded; - // TODO: titlescrollspeed scrolls slow here because it is not an angle - //camera.angle += titlescrollspeed; + camera.angle += titlescrollspeed*ANG1/64; } } From fd97fdd6839f0c1938ae77118d872c0d755bf8c8 Mon Sep 17 00:00:00 2001 From: yellowtd Date: Thu, 20 Apr 2017 19:36:57 -0400 Subject: [PATCH 23/61] titlemap - cameraref subsector apparently it recalculates without this line, so it should give a tiny performance boost? --- src/f_finale.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/f_finale.c b/src/f_finale.c index e3a6e9164..0f29fadb4 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1607,6 +1607,7 @@ void F_TitleScreenTicker(boolean run) camera.z = cameraref->z; camera.angle = cameraref->angle; camera.aiming = cameraref->cusval; + camera.subsector = cameraref->subsector; } else { From 068c9d6294cb25f7d2cabd93721739f4806e7880 Mon Sep 17 00:00:00 2001 From: yellowtd Date: Sat, 22 Apr 2017 19:40:18 -0400 Subject: [PATCH 24/61] titlemap - skipintro bugfix game crash with -skipintro enabled, hopefully fixes it and causes no issues anywhere else --- src/r_sky.c | 4 ---- src/screen.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/r_sky.c b/src/r_sky.c index 5162518cb..898424a99 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -64,10 +64,6 @@ void R_SetupSkyDraw(void) // the horizon line in a 256x128 sky texture skytexturemid = (textures[skytexture]->height/2)< Date: Mon, 8 May 2017 23:51:12 +0100 Subject: [PATCH 25/61] Compiling fixes --- src/f_finale.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 0f29fadb4..bcd431d7c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1429,6 +1429,8 @@ void F_StartTitleScreen(void) if (titlemap) { + mapthing_t *startpos; + gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = true; gamemap = titlemap; @@ -1444,7 +1446,6 @@ void F_StartTitleScreen(void) //camera.subsector = NULL; // toast is filthy too // Set Default Position - mapthing_t *startpos; if (playerstarts[0]) startpos = playerstarts[0]; else if (deathmatchstarts[0]) @@ -1576,12 +1577,12 @@ void F_TitleScreenTicker(boolean run) if (gameaction != ga_nothing || gamestate != GS_TITLESCREEN) return; - thinker_t *th; - mobj_t *mo2; - mobj_t *cameraref = NULL; - // Execute the titlemap camera settings - if (titlemapinaction) { + if (titlemapinaction) + { + thinker_t *th; + mobj_t *mo2; + mobj_t *cameraref = NULL; for (th = thinkercap.next; th != &thinkercap; th = th->next) { From 3a4e091ba6de7ddb425c7c63cfd32fe1303f6b46 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 9 May 2017 00:48:07 +0100 Subject: [PATCH 26/61] * Fix titlemap music change bug reported by Larztard * Clean up titlemapinaction so that it isn't true when you're playing * Don't print "SPEEDING OFF TO [ZONE] [ACT 1]..." on screen if it's a titlemap - keep a nice and pretty black screen --- src/f_finale.c | 10 ++++++---- src/f_finale.h | 1 + src/g_game.c | 6 ++++++ src/p_setup.c | 8 ++++++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 9cd2f6e14..2d391a4d8 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -39,6 +39,7 @@ static INT32 finalecount; INT32 titlescrollspeed = 80; boolean titlemapinaction = false; +boolean titlemaptransition = false; static INT32 timetonext; // Delay between screen changes static INT32 continuetime; // Short delay when continuing @@ -281,6 +282,8 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset void F_StartIntro(void) { + S_StopMusic(); + if (introtoplay) { if (!cutscenes[introtoplay - 1]) @@ -1428,7 +1431,7 @@ void F_StartTitleScreen(void) mapthing_t *startpos; gamestate_t prevwipegamestate = wipegamestate; - titlemapinaction = true; + titlemapinaction = titlemaptransition = true; gamemap = titlemap; if (!mapheaderinfo[gamemap-1]) @@ -1437,9 +1440,8 @@ void F_StartTitleScreen(void) maptol = mapheaderinfo[gamemap-1]->typeoflevel; globalweather = mapheaderinfo[gamemap-1]->weather; - G_DoLoadLevel(true); + G_DoLoadLevel(true); // handles music change players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) - //camera.subsector = NULL; // toast is filthy too // Set Default Position if (playerstarts[0]) @@ -1477,6 +1479,7 @@ void F_StartTitleScreen(void) { titlemapinaction = false; gamemap = 1; // g_game.c + S_ChangeMusicInternal("_title", looptitle); CON_ClearHUD(); } @@ -1484,7 +1487,6 @@ void F_StartTitleScreen(void) // IWAD dependent stuff. - S_ChangeMusicInternal("_title", looptitle); animtimer = 0; demoDelayLeft = demoDelayTime; diff --git a/src/f_finale.h b/src/f_finale.h index f710a74fb..7d41b5720 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -62,6 +62,7 @@ void F_ContinueDrawer(void); extern INT32 titlescrollspeed; extern boolean titlemapinaction; +extern boolean titlemaptransition; // // WIPE diff --git a/src/g_game.c b/src/g_game.c index 08d849a80..a3b2d9528 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1635,6 +1635,12 @@ void G_DoLoadLevel(boolean resetplayer) if (gamestate == GS_INTERMISSION) Y_EndIntermission(); + // cleanup + if (titlemaptransition) + titlemaptransition = false; + else + titlemapinaction = false; + G_SetGamestate(GS_LEVEL); for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/p_setup.c b/src/p_setup.c index 4f11c10d0..85f5d346c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2643,7 +2643,11 @@ boolean P_SetupLevel(boolean skipprecip) // As oddly named as this is, this handles music only. // We should be fine starting it here. - S_Start(); + /// ... as long as this isn't a titlemap transition, that is + if (!titlemapinaction) + S_Start(); + else + S_ChangeMusicInternal("_title", looptitle); // Let's fade to black here // But only if we didn't do the special stage wipe @@ -2657,7 +2661,7 @@ boolean P_SetupLevel(boolean skipprecip) } // Print "SPEEDING OFF TO [ZONE] [ACT 1]..." - if (rendermode != render_none) + if (!titlemapinaction && rendermode != render_none) { // Don't include these in the fade! char tx[64]; From 7f83e0d1343e89b2dc584d018ee1e45dd343f7a9 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 9 May 2017 11:09:58 +0100 Subject: [PATCH 27/61] * Prevent crash if you go to a map and it doesn't exist. * Handle music fix in smarter way. * Enums! --- src/dehacked.c | 2 +- src/f_finale.c | 21 ++++++++++----------- src/f_finale.h | 11 +++++++++-- src/g_game.c | 17 +++++++++++++---- src/p_setup.c | 2 -- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 71939ade5..73d52d9bf 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8646,7 +8646,7 @@ static inline int lib_getenum(lua_State *L) lua_pushinteger(L, titlemap); return 1; } else if (fastcmp(word,"titlemapinaction")) { - lua_pushboolean(L, titlemapinaction); + lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF)); return 1; } else if (fastcmp(word,"gametype")) { lua_pushinteger(L, gametype); diff --git a/src/f_finale.c b/src/f_finale.c index 2d391a4d8..29e7e83fa 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -38,8 +38,7 @@ // 0 = text, 1 = art screen static INT32 finalecount; INT32 titlescrollspeed = 80; -boolean titlemapinaction = false; -boolean titlemaptransition = false; +UINT8 titlemapinaction = TITLEMAP_OFF; static INT32 timetonext; // Delay between screen changes static INT32 continuetime; // Short delay when continuing @@ -1421,6 +1420,8 @@ void F_GameEndTicker(void) // ============== void F_StartTitleScreen(void) { + S_ChangeMusicInternal("_title", looptitle); + if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) finalecount = 0; else @@ -1431,7 +1432,7 @@ void F_StartTitleScreen(void) mapthing_t *startpos; gamestate_t prevwipegamestate = wipegamestate; - titlemapinaction = titlemaptransition = true; + titlemapinaction = TITLEMAP_LOADING; gamemap = titlemap; if (!mapheaderinfo[gamemap-1]) @@ -1440,7 +1441,10 @@ void F_StartTitleScreen(void) maptol = mapheaderinfo[gamemap-1]->typeoflevel; globalweather = mapheaderinfo[gamemap-1]->weather; - G_DoLoadLevel(true); // handles music change + G_DoLoadLevel(true); + if (!titlemap) + return; + players[displayplayer].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) // Set Default Position @@ -1465,21 +1469,16 @@ void F_StartTitleScreen(void) camera.x = camera.y = camera.z = camera.angle = camera.aiming = 0; camera.subsector = NULL; // toast is filthy too } + camera.chase = true; camera.height = 0; - //camera.x = camera.y = camera.height = camera.aiming = 0; - //camera.z = 128*FRACUNIT; - - //CON_ClearHUD(); - wipegamestate = prevwipegamestate; } else { - titlemapinaction = false; + titlemapinaction = TITLEMAP_OFF; gamemap = 1; // g_game.c - S_ChangeMusicInternal("_title", looptitle); CON_ClearHUD(); } diff --git a/src/f_finale.h b/src/f_finale.h index 7d41b5720..aadc64ad0 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -61,8 +61,15 @@ void F_ContinueTicker(void); void F_ContinueDrawer(void); extern INT32 titlescrollspeed; -extern boolean titlemapinaction; -extern boolean titlemaptransition; + +typedef enum +{ + TITLEMAP_OFF = 0, + TITLEMAP_LOADING, + TITLEMAP_RUNNING +} titlemap_enum; + +extern UINT8 titlemapinaction; // // WIPE diff --git a/src/g_game.c b/src/g_game.c index a3b2d9528..01d744077 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1636,10 +1636,19 @@ void G_DoLoadLevel(boolean resetplayer) Y_EndIntermission(); // cleanup - if (titlemaptransition) - titlemaptransition = false; + if (titlemapinaction == TITLEMAP_LOADING) + { + if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR) + { + titlemap = 0; // let's not infinite recursion ok + Command_ExitGame_f(); + return; + } + + titlemapinaction = TITLEMAP_RUNNING; + } else - titlemapinaction = false; + titlemapinaction = TITLEMAP_OFF; G_SetGamestate(GS_LEVEL); @@ -1650,7 +1659,7 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. - if (!P_SetupLevel(false)) + if (!P_SetupLevel(false)) // this never returns false? { // fail so reset game stuff Command_ExitGame_f(); diff --git a/src/p_setup.c b/src/p_setup.c index 85f5d346c..69c60c3ac 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2646,8 +2646,6 @@ boolean P_SetupLevel(boolean skipprecip) /// ... as long as this isn't a titlemap transition, that is if (!titlemapinaction) S_Start(); - else - S_ChangeMusicInternal("_title", looptitle); // Let's fade to black here // But only if we didn't do the special stage wipe From 13c748531ffb7348fdc5f113b2edb1e0741c1d94 Mon Sep 17 00:00:00 2001 From: yellowtd Date: Fri, 12 May 2017 20:47:42 -0400 Subject: [PATCH 28/61] bootmap (+indentation fix) --- src/d_main.c | 13 +++++++++++++ src/dehacked.c | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/d_main.c b/src/d_main.c index 616d64d52..5e357ed1d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1341,6 +1341,19 @@ void D_SRB2Main(void) ultimatemode = true; } + // rei/miru: bootmap (Idea: starts the game on a predefined map) + if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm())) + { + pstartmap = bootmap; + + if (pstartmap < 1 || pstartmap > NUMMAPS) + I_Error("Cannot warp to map %d (out of range)\n", pstartmap); + else + { + autostart = true; + } + } + if (autostart || netgame || M_CheckParm("+connect") || M_CheckParm("-connect")) { gameaction = ga_nothing; diff --git a/src/dehacked.c b/src/dehacked.c index 73d52d9bf..174447ef2 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3241,6 +3241,20 @@ static void readmaincfg(MYFILE *f) DEH_WriteUndoline(word, customversionstring, UNDO_NONE); strlcpy(customversionstring, word2, sizeof (customversionstring)); } + else if (fastcmp(word, "BOOTMAP")) + { + // Support using the actual map name, + // i.e., Level AB, Level FZ, etc. + + // Convert to map number + if (word2[0] >= 'A' && word2[0] <= 'Z') + value = M_MapNumber(word2[0], word2[1]); + else + value = get_number(word2); + + DEH_WriteUndoline(word, va("%d", bootmap), UNDO_NONE); + bootmap = (INT16)value; + } else deh_warning("Maincfg: unknown word '%s'", word); } From f5fa67b7ad7be30c871e7fb1fad40c9ae346eaa0 Mon Sep 17 00:00:00 2001 From: yellowtd Date: Fri, 12 May 2017 20:54:06 -0400 Subject: [PATCH 29/61] no idea why this was stashed while the last commit before this one was made.. --- src/doomstat.h | 1 + src/g_game.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/doomstat.h b/src/doomstat.h index 033381435..0d6dc2bae 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -126,6 +126,7 @@ extern INT16 sstage_end; extern INT16 titlemap; extern boolean hidetitlepics; +extern INT16 bootmap; //bootmap for loading a map on startup extern boolean looptitle; extern boolean useNightsSS; diff --git a/src/g_game.c b/src/g_game.c index 01d744077..c118eba29 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -122,6 +122,7 @@ INT16 sstage_end; INT16 titlemap = 0; boolean hidetitlepics = false; +INT16 bootmap; //bootmap for loading a map on startup boolean looptitle = false; boolean useNightsSS = false; From ba4275c415cf5fe021619d0d9b1f694dd38210f2 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 13 May 2017 22:38:06 +0100 Subject: [PATCH 30/61] title screen hud hook --- src/f_finale.c | 13 +++++++++++++ src/lua_hud.h | 1 + src/lua_hudlib.c | 32 +++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index 29e7e83fa..4dd73aa02 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -34,6 +34,10 @@ #include "p_local.h" #include "p_setup.h" +#ifdef HAVE_BLUA +#include "lua_hud.h" +#endif + // Stage of animation: // 0 = text, 1 = art screen static INT32 finalecount; @@ -1524,7 +1528,11 @@ void F_TitleScreenDrawer(void) // rei|miru: use title pics? if (hidetitlepics) +#ifdef HAVE_BLUA + goto luahook; +#else return; +#endif V_DrawScaledPatch(30, 14, 0, ttwing); @@ -1562,6 +1570,11 @@ void F_TitleScreenDrawer(void) } V_DrawScaledPatch(48, 142, 0,ttbanner); + +#ifdef HAVE_BLUA +luahook: + LUAh_TitleHUD(); +#endif } // (no longer) De-Demo'd Title Screen diff --git a/src/lua_hud.h b/src/lua_hud.h index ba0a1d894..beaca7883 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -42,3 +42,4 @@ boolean LUA_HudEnabled(enum hud option); void LUAh_GameHUD(player_t *stplyr); void LUAh_ScoresHUD(void); +void LUAh_TitleHUD(void); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 5b3cd46ce..f2a2be847 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -87,11 +87,13 @@ static const char *const patch_opt[] = { enum hudhook { hudhook_game = 0, - hudhook_scores + hudhook_scores, + hudhook_title }; static const char *const hudhook_opt[] = { "game", "scores", + "title", NULL}; // alignment types for v.drawString @@ -650,6 +652,9 @@ int LUA_HudLib(lua_State *L) lua_newtable(L); lua_rawseti(L, -2, 3); // HUD[2] = scores rendering functions array + + lua_newtable(L); + lua_rawseti(L, -2, 4); // HUD[3] = title rendering functions array lua_setfield(L, LUA_REGISTRYINDEX, "HUD"); luaL_newmetatable(L, META_HUDINFO); @@ -762,4 +767,29 @@ void LUAh_ScoresHUD(void) hud_running = false; } +void LUAh_TitleHUD(void) +{ + if (!gL || !(hudAvailable & (1< Date: Sun, 14 May 2017 16:45:08 +0100 Subject: [PATCH 31/61] Added reset for titlemap (and other title attribute) changes so that the title screen never ends up being some half-formed hybrid Also because I could I added it for intro changes too --- src/d_main.c | 3 +++ src/dehacked.c | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index 5e357ed1d..1d3680ff0 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -683,6 +683,9 @@ void D_AdvanceDemo(void) void D_StartTitle(void) { INT32 i; + + S_StopMusic(); + if (netgame) { if (gametype == GT_COOP) diff --git a/src/dehacked.c b/src/dehacked.c index 174447ef2..406e10716 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -77,6 +77,8 @@ boolean deh_loaded = false; static int dbg_line; static boolean gamedataadded = false; +static boolean titlechanged = false; +static boolean introchanged = false; #ifdef DELFILE typedef struct undehacked_s @@ -3137,11 +3139,13 @@ static void readmaincfg(MYFILE *f) // range check, you morons. if (introtoplay > 128) introtoplay = 128; + introchanged = true; } else if (fastcmp(word, "LOOPTITLE")) { DEH_WriteUndoline(word, va("%d", looptitle), UNDO_NONE); looptitle = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; } else if (fastcmp(word, "TITLEMAP")) { @@ -3156,16 +3160,19 @@ static void readmaincfg(MYFILE *f) DEH_WriteUndoline(word, va("%d", titlemap), UNDO_NONE); titlemap = (INT16)value; + titlechanged = true; } else if (fastcmp(word, "HIDETITLEPICS")) { DEH_WriteUndoline(word, va("%d", hidetitlepics), UNDO_NONE); hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); + titlechanged = true; } else if (fastcmp(word, "TITLESCROLLSPEED")) { DEH_WriteUndoline(word, va("%d", titlescrollspeed), UNDO_NONE); titlescrollspeed = get_number(word2); + titlechanged = true; } else if (fastcmp(word, "CREDITSCUTSCENE")) { @@ -3184,16 +3191,19 @@ static void readmaincfg(MYFILE *f) { DEH_WriteUndoline(word, va("%d", numDemos), UNDO_NONE); numDemos = (UINT8)get_number(word2); + titlechanged = true; } else if (fastcmp(word, "DEMODELAYTIME")) { DEH_WriteUndoline(word, va("%d", demoDelayTime), UNDO_NONE); demoDelayTime = get_number(word2); + titlechanged = true; } else if (fastcmp(word, "DEMOIDLETIME")) { DEH_WriteUndoline(word, va("%d", demoIdleTime), UNDO_NONE); demoIdleTime = get_number(word2); + titlechanged = true; } else if (fastcmp(word, "USE1UPSOUND")) { @@ -3230,16 +3240,19 @@ static void readmaincfg(MYFILE *f) strlcat(savegamename, "%u.ssg", sizeof(savegamename)); gamedataadded = true; + titlechanged = true; } else if (fastcmp(word, "RESETDATA")) { DEH_WriteUndoline(word, "0", UNDO_TODO); /// \todo P_ResetData(value); + titlechanged = true; } else if (fastcmp(word, "CUSTOMVERSION")) { DEH_WriteUndoline(word, customversionstring, UNDO_NONE); strlcpy(customversionstring, word2, sizeof (customversionstring)); + //titlechanged = true; } else if (fastcmp(word, "BOOTMAP")) { @@ -3254,6 +3267,7 @@ static void readmaincfg(MYFILE *f) DEH_WriteUndoline(word, va("%d", bootmap), UNDO_NONE); bootmap = (INT16)value; + //titlechanged = true; } else deh_warning("Maincfg: unknown word '%s'", word); @@ -3463,7 +3477,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) for (i = 0; i < NUMSFX; i++) savesfxnames[i] = S_sfx[i].name; - gamedataadded = false; + gamedataadded = titlechanged = introchanged = false; // it doesn't test the version of SRB2 and version of dehacked file dbg_line = -1; // start at -1 so the first line is 0. @@ -3834,6 +3848,14 @@ static void DEH_LoadDehackedFile(MYFILE *f, UINT16 wad) if (gamedataadded) G_LoadGameData(); + if (gamestate == GS_TITLESCREEN) + { + if (introchanged) + COM_BufAddText("playintro"); + else if (titlechanged) + COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed + } + dbg_line = -1; if (deh_num_warning) { From b13a9ad9d16637b76c544dcfd9cbe665cbe3136f Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 14 May 2017 19:20:00 +0100 Subject: [PATCH 32/61] Support for negative scroll speeds on title screen --- src/f_finale.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index 4dd73aa02..eb25e1bec 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -227,7 +227,8 @@ static void F_SkyScroll(INT32 scrollspeed) pat = W_CachePatchName("TITLESKY", PU_CACHE); - animtimer = ((finalecount*scrollspeed)/16) % SHORT(pat->width); + fakedwidth = SHORT(pat->width); + animtimer = ((finalecount*scrollspeed)/16 + fakedwidth) % fakedwidth; fakedwidth = vid.width / vid.dupx; From 65a202e84345d24e39291461fa31d010e613963b Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 14 May 2017 19:25:46 +0100 Subject: [PATCH 33/61] ACTUALLY let's do this better --- src/f_finale.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index eb25e1bec..b46b92945 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -224,18 +224,19 @@ static void F_SkyScroll(INT32 scrollspeed) { INT32 scrolled, x, mx, fakedwidth; patch_t *pat; + INT16 patwidth; pat = W_CachePatchName("TITLESKY", PU_CACHE); - fakedwidth = SHORT(pat->width); - animtimer = ((finalecount*scrollspeed)/16 + fakedwidth) % fakedwidth; + patwidth = SHORT(pat->width); + animtimer = ((finalecount*scrollspeed)/16 + patwidth) % patwidth; fakedwidth = vid.width / vid.dupx; if (rendermode == render_soft) { // if only hardware rendering could be this elegant and complete - scrolled = (SHORT(pat->width) - animtimer) - 1; - for (x = 0, mx = scrolled; x < fakedwidth; x++, mx = (mx+1)%SHORT(pat->width)) + scrolled = (patwidth - animtimer) - 1; + for (x = 0, mx = scrolled; x < fakedwidth; x++, mx = (mx+1)%patwidth) F_DrawPatchCol(x, pat, mx); } #ifdef HWRENDER @@ -243,8 +244,8 @@ static void F_SkyScroll(INT32 scrollspeed) { // if only software rendering could be this simple and retarded scrolled = animtimer; if (scrolled > 0) - V_DrawScaledPatch(scrolled - SHORT(pat->width), 0, 0, pat); - for (x = 0; x < fakedwidth; x += SHORT(pat->width)) + V_DrawScaledPatch(scrolled - patwidth, 0, 0, pat); + for (x = 0; x < fakedwidth; x += patwidth) V_DrawScaledPatch(x + scrolled, 0, 0, pat); } #endif From 87f32abc24e6751f46ee67feab796c120c8e3c62 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 16 May 2017 14:11:10 +0100 Subject: [PATCH 34/61] i have no idea whether this will fix the garbage or whether it'll get broken again, but here's an attempted fix for VAda's name --- src/f_finale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index b46b92945..eab565ca1 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1009,7 +1009,7 @@ static const char *credits[] = { "", "\1Sprite Artists", "Odi \"Iceman404\" Atunzu", - "Victor \"VAdaPEGA\" Ara\x1Fjo", // Ara�jo -- sorry for our limited font! D: + "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: "Jim \"MotorRoach\" DeMello", "Desmond \"Blade\" DesJardins", "Sherman \"CoatRack\" DesJardins", From 34908c9b29699881cafe6f914a945e7e923dfba4 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 6 Aug 2017 18:57:02 +0100 Subject: [PATCH 35/61] Re-order P_RemoveShield's first/second layer shield code --- src/p_inter.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 4bd9b998a..3ae68814c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2920,7 +2920,17 @@ void P_RemoveShield(player_t *player) else player->powers[pw_shield] &= SH_STACK; } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_NONE) + else if (player->powers[pw_shield] & SH_NOSTACK) + { // First layer shields + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ARMAGEDDON) // Give them what's coming to them! + { + P_BlackOw(player); // BAM! + player->pflags |= PF_JUMPDOWN; + } + else + player->powers[pw_shield] &= SH_STACK; + } + else { // Second layer shields if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->powers[pw_super] || (mariomode && player->powers[pw_invulnerability]))) { @@ -2929,13 +2939,6 @@ void P_RemoveShield(player_t *player) } player->powers[pw_shield] = SH_NONE; } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ARMAGEDDON) // Give them what's coming to them! - { - P_BlackOw(player); // BAM! - player->pflags |= PF_JUMPDOWN; - } - else - player->powers[pw_shield] = player->powers[pw_shield] & SH_STACK; } static void P_ShieldDamage(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) From a0204c67221885a72eaa204aa61f7dcb076eab54 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sun, 6 Aug 2017 22:10:29 +0100 Subject: [PATCH 36/61] Made P_SpecialStageDamage for the lose 10 rings damaging code shared by spikeballs and SS damage sector special --- src/p_inter.c | 58 +++++++++++++++++++++++++++++++-------------------- src/p_local.h | 1 + src/p_spec.c | 23 +++----------------- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 3ae68814c..4686c68f8 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1493,30 +1493,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetMobjState(special, special->info->deathstate); return; case MT_SPECIALSPIKEBALL: - if (!(!useNightsSS && G_IsSpecialStage(gamemap))) // Only for old special stages - { - P_DamageMobj(toucher, special, special, 1, 0); - return; - } - - if (player->powers[pw_invulnerability] || player->powers[pw_flashing] - || player->powers[pw_super]) - return; - if (player->powers[pw_shield] || player->bot) //If One-Hit Shield - { - P_RemoveShield(player); - S_StartSound(toucher, sfx_shldls); // Ba-Dum! Shield loss. - } + if (!useNightsSS && G_IsSpecialStage(gamemap)) // Only for old special stages + P_SpecialStageDamage(player, special, NULL); else - { - P_PlayRinglossSound(toucher); - if (player->rings >= 10) - player->rings -= 10; - else - player->rings = 0; - } - - P_DoPlayerPain(player, special, NULL); + P_DamageMobj(toucher, special, special, 1, 0); return; case MT_EGGMOBILE2_POGO: // sanity checks @@ -3008,6 +2988,38 @@ static void P_RingDamage(player_t *player, mobj_t *inflictor, mobj_t *source, IN player->rings = 0; } +// +// P_SpecialStageDamage +// +// Do old special stage-style damaging +// Removes 10 rings from the player, or knocks off their shield if they have one. +// If they don't have anything, just knock the player back anyway (this doesn't kill them). +// +void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source) +{ + if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super]) + return; + + if (player->powers[pw_shield] || player->bot) //If One-Hit Shield + { + P_RemoveShield(player); + S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss. + } + else + { + P_PlayRinglossSound(player->mo); + if (player->rings >= 10) + player->rings -= 10; + else + player->rings = 0; + } + + P_DoPlayerPain(player, inflictor, source); + + if (gametype == GT_CTF && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)) + P_PlayerFlagBurst(player, false); +} + /** Damages an object, which may or may not be a player. * For melee attacks, source and inflictor are the same. * diff --git a/src/p_local.h b/src/p_local.h index a2831222a..64ab47975 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -414,6 +414,7 @@ void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duratio void P_ForceConstant(const BasicFF_t *FFInfo); void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End); void P_RemoveShield(player_t *player); +void P_SpecialStageDamage(player_t *player, mobj_t *inflictor, mobj_t *source); boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); void P_PlayerRingBurst(player_t *player, INT32 num_rings); /// \todo better fit in p_user.c diff --git a/src/p_spec.c b/src/p_spec.c index 8a3ac0748..03ee30281 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3660,31 +3660,14 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers S_StartSound(player->mo, sfx_itemup); } break; - case 11: // Special Stage Damage - Kind of like a mini-P_DamageMobj() - if (player->powers[pw_invulnerability] || player->powers[pw_flashing] || player->powers[pw_super] || player->exiting || player->bot) + case 11: // Special Stage Damage + if (player->exiting || player->bot) // Don't do anything for bots or players who have just finished break; if (!(player->powers[pw_shield] || player->rings > 0)) // Don't do anything if no shield or rings anyway break; - if (player->powers[pw_shield]) - { - P_RemoveShield(player); - S_StartSound(player->mo, sfx_shldls); // Ba-Dum! Shield loss. - } - else if (player->rings > 0) - { - P_PlayRinglossSound(player->mo); - if (player->rings >= 10) - player->rings -= 10; - else - player->rings = 0; - } - - P_DoPlayerPain(player, NULL, NULL); // this does basically everything that was here before - - if (gametype == GT_CTF && player->gotflag & (GF_REDFLAG|GF_BLUEFLAG)) - P_PlayerFlagBurst(player, false); + P_SpecialStageDamage(player, NULL, NULL); break; case 12: // Space Countdown if (!(player->powers[pw_shield] & SH_PROTECTWATER) && !player->powers[pw_spacetime]) From fd63db0aaff3488cde8374235297b7d14a027aff Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 18 Aug 2017 00:58:16 +0100 Subject: [PATCH 37/61] Starting lives revamp, per the 2.2 priorities topic list! * Each time you die, the number of game overs you've had is counted. * Your save file updates to record this. * The number of startinglives is determined by the number of times you'ved game-overed, with the maximum being infinity lives (thereby providing a cap on the number of game overs you can go through in a typical game). Requires a new patch.dta, but I'm not uploading that yet because not happy with the icon we've got going for infinity lives on the save select menu. --- src/doomstat.h | 4 ++ src/g_game.c | 116 ++++++++++++++++++++++++++++++++++++++++++++----- src/g_game.h | 2 + src/hu_stuff.c | 6 ++- src/hu_stuff.h | 1 + src/m_menu.c | 12 +++-- src/m_menu.h | 1 - src/p_inter.c | 9 +++- src/p_saveg.c | 14 +++--- src/p_saveg.h | 1 + src/p_setup.c | 1 + src/p_user.c | 12 +++-- src/st_stuff.c | 85 +++++++++++++++--------------------- 13 files changed, 184 insertions(+), 80 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index a24bad79d..a172eae43 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -45,6 +45,10 @@ extern INT32 cursaveslot; extern INT16 lastmaploaded; extern boolean gamecomplete; +#define maxgameovers 13 +extern UINT8 numgameovers; +extern SINT8 startinglivesbalance[maxgameovers+1]; + #define PRECIP_NONE 0 #define PRECIP_STORM 1 #define PRECIP_SNOW 2 diff --git a/src/g_game.c b/src/g_game.c index e996938ab..e16816e44 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -81,6 +81,9 @@ INT32 cursaveslot = -1; // Auto-save 1p savegame slot INT16 lastmaploaded = 0; // Last map the game loaded boolean gamecomplete = false; +UINT8 numgameovers = 0; // for startinglives balance +SINT8 startinglivesbalance[maxgameovers+1] = {3, 5, 7, 9, 12, 15, 20, 25, 30, 40, 50, 75, 99, 0x7F}; + UINT16 mainwads = 0; boolean modifiedgame; // Set if homebrew PWAD stuff has been added. boolean savemoddata = false; @@ -3130,7 +3133,7 @@ static void G_DoContinued(void) token = 0; // Reset # of lives - pl->lives = (ultimatemode) ? 1 : 3; + pl->lives = (ultimatemode) ? 1 : startinglivesbalance[numgameovers]; D_MapChange(gamemap, gametype, ultimatemode, false, 0, false, false); @@ -3614,13 +3617,13 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) // G_SaveGame // Saves your game. // -void G_SaveGame(UINT32 savegameslot) +void G_SaveGame(UINT32 slot) { boolean saved; char savename[256] = ""; const char *backup; - sprintf(savename, savegamename, savegameslot); + sprintf(savename, savegamename, slot); backup = va("%s",savename); // save during evaluation or credits? game's over, folks! @@ -3656,9 +3659,103 @@ void G_SaveGame(UINT32 savegameslot) if (cv_debug && saved) CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) - CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, savegameslot, savegamename); + CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, savegamename); } +#define BADSAVE goto cleanup; +#define CHECKPOS if (save_p >= end_p) BADSAVE +void G_SaveGameOver(UINT32 slot) +{ + boolean saved = false; + size_t length; + char vcheck[VERSIONSIZE]; + char savename[255]; + const char *backup; + + sprintf(savename, savegamename, slot); + backup = va("%s",savename); + + length = FIL_ReadFile(savename, &savebuffer); + if (!length) + { + CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); + return; + } + + { + char temp[sizeof(timeattackfolder)]; + INT32 fake; // Dummy variable + UINT8 *end_p = savebuffer + length; + UINT8 *lives_p; + SINT8 pllives; + + save_p = savebuffer; + // Version check + memset(vcheck, 0, sizeof (vcheck)); + sprintf(vcheck, "version %d", VERSION); +#ifndef SAVEGAMES_OTHERVERSIONS + if (strcmp((const char *)save_p, (const char *)vcheck)) + BADSAVE; +#endif + save_p += VERSIONSIZE; + + // P_UnArchiveMisc() + fake = READINT16(save_p); + CHECKPOS + (void)READUINT16(save_p); // emeralds + CHECKPOS + READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to + if (strcmp(temp, timeattackfolder)) BADSAVE + CHECKPOS + (void)READUINT8(save_p); + CHECKPOS + (void)READUINT8(save_p); + CHECKPOS + + WRITEUINT8(save_p, numgameovers); + CHECKPOS + + lives_p = save_p; + pllives = READSINT8(save_p); // lives + CHECKPOS + if (pllives < startinglivesbalance[numgameovers]) + { + pllives = startinglivesbalance[numgameovers]; + WRITESINT8(lives_p, pllives); + } + + (void)READINT32(save_p); // Score + CHECKPOS + (void)READINT32(save_p); // continues + + if (fake & (1<<10)) + { + CHECKPOS + (void)READUINT8(save_p); + CHECKPOS + (void)READUINT8(save_p); // because why not. + } + + // File end marker check + CHECKPOS + if (READUINT8(save_p) != 0x1d) BADSAVE; + + // done + saved = FIL_WriteFile(backup, savebuffer, length); + } + +cleanup: + if (cv_debug && saved) + CONS_Printf(M_GetText("Game saved.\n")); + else if (!saved) + CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, savegamename); + Z_Free(savebuffer); + save_p = savebuffer = NULL; + +} +#undef CHECKPOS +#undef BADSAVE + // // G_DeferedInitNew // Can be called by the startup code or the menu task, @@ -3722,7 +3819,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean if (resetplayer) { // Clear a bunch of variables - tokenlist = token = sstimer = redscore = bluescore = lastmap = 0; + numgameovers = tokenlist = token = sstimer = redscore = bluescore = lastmap = 0; countdown = countdown2 = 0; for (i = 0; i < MAXPLAYERS; i++) @@ -3737,15 +3834,10 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean players[i].lives = cv_startinglives.value; players[i].continues = 0; } - else if (pultmode) - { - players[i].lives = 1; - players[i].continues = 0; - } else { - players[i].lives = 3; - players[i].continues = 1; + players[i].lives = (pultmode) ? 1 : startinglivesbalance[0]; + players[i].continues = (pultmode) ? 0 : 1; } if (!((netgame || multiplayer) && (FLS))) diff --git a/src/g_game.h b/src/g_game.h index 72a6f3d6e..4ac78ab10 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -116,6 +116,8 @@ void G_SaveGameData(void); void G_SaveGame(UINT32 slot); +void G_SaveGameOver(UINT32 slot); + // Only called by startup code. void G_RecordDemo(const char *name); void G_RecordMetal(void); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index e92b96995..b49d3eb96 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -83,6 +83,7 @@ patch_t *rmatcico; patch_t *bmatcico; patch_t *tagico; patch_t *tallminus; +patch_t *tallinfin; //------------------------------------------- // coop hud @@ -235,6 +236,7 @@ void HU_LoadGraphics(void) // minus for negative tallnums tallminus = (patch_t *)W_CachePatchName("STTMINUS", PU_HUDGFX); + tallinfin = (patch_t *)W_CachePatchName("STTINFIN", PU_HUDGFX); // cache the crosshairs, don't bother to know which one is being used, // just cache all 3, they're so small anyway. @@ -1250,7 +1252,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I } } - if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3))) //show lives + if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != 0x7f)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE|(greycheck ? V_60TRANS : 0), va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) { @@ -1388,7 +1390,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline | (greycheck ? V_TRANSLUCENT : 0) | V_ALLOWLOWERCASE, name); - if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3))) //show lives + if (G_GametypeUsesLives() && !(gametype == GT_COOP && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != 0x7f)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives)); else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT) V_DrawSmallScaledPatch(x-28, y-4, 0, tagico); diff --git a/src/hu_stuff.h b/src/hu_stuff.h index e757db85a..2dbeb556d 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -71,6 +71,7 @@ extern patch_t *rmatcico; extern patch_t *bmatcico; extern patch_t *tagico; extern patch_t *tallminus; +extern patch_t *tallinfin; extern patch_t *tokenicon; // set true when entering a chat message diff --git a/src/m_menu.c b/src/m_menu.c index 64255e71a..af3b0c7ca 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6097,7 +6097,10 @@ static void M_DrawLoadGameData(void) // Use the big face pic for lives, duh. :3 V_DrawScaledPatch(ecks + 12, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); + if (savegameinfo[saveSlotSelected].lives == 0x7F) + V_DrawScaledPatch(ecks + 40 - 18, 172, 0, tallinfin); + else + V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); // Absolute ridiculousness, condensed into another function. V_DrawContinueIcon(ecks + 58, 182, 0, savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor); @@ -6291,10 +6294,11 @@ static void M_ReadSavegameInfo(UINT32 slot) savegameinfo[slot].skinnum = READUINT8(save_p); CHECKPOS - (void)READINT32(save_p); // Score - + (void)READUINT8(save_p); // numgameovers CHECKPOS - savegameinfo[slot].lives = READINT32(save_p); // lives + savegameinfo[slot].lives = READSINT8(save_p); // lives + CHECKPOS + (void)READINT32(save_p); // Score CHECKPOS savegameinfo[slot].continues = READINT32(save_p); // continues diff --git a/src/m_menu.h b/src/m_menu.h index 53dc266d1..2d2d3378b 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -226,7 +226,6 @@ typedef struct INT32 lives; INT32 continues; INT32 gamemap; - UINT8 netgame; } saveinfo_t; extern description_t description[32]; diff --git a/src/p_inter.c b/src/p_inter.c index d2101ca57..284003c31 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2259,7 +2259,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if ((target->player->lives <= 1) && (netgame || multiplayer) && (gametype == GT_COOP) && (cv_cooplives.value == 0)) ; - else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) + else if (!target->player->bot && !target->player->spectator && !G_IsSpecialStage(gamemap) && (target->player->lives != 0x7f) && G_GametypeUsesLives()) { target->player->lives -= 1; // Lose a life Tails 03-11-2000 @@ -2289,6 +2289,13 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget S_StopMusic(); // Stop the Music! Tails 03-14-2000 S_ChangeMusicInternal("_gover", false); // Yousa dead now, Okieday? Tails 03-14-2000 } + + if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && numgameovers < maxgameovers) + { + numgameovers++; + if ((!modifiedgame || savemoddata) && cursaveslot >= 0) + G_SaveGameOver((UINT32)cursaveslot); + } } } target->player->playerstate = PST_DEAD; diff --git a/src/p_saveg.c b/src/p_saveg.c index 2d3412e65..9e1206c49 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -64,15 +64,16 @@ typedef enum static inline void P_ArchivePlayer(void) { const player_t *player = &players[consoleplayer]; - INT32 pllives = player->lives; - if (pllives < 3) // Bump up to 3 lives if the player - pllives = 3; // has less than that. + SINT8 pllives = player->lives; + if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player + pllives = startinglivesbalance[numgameovers]; // has less than that. WRITEUINT8(save_p, player->skincolor); WRITEUINT8(save_p, player->skin); + WRITEUINT8(save_p, numgameovers); + WRITESINT8(save_p, pllives); WRITEUINT32(save_p, player->score); - WRITEINT32(save_p, pllives); WRITEINT32(save_p, player->continues); if (botskin) @@ -90,8 +91,9 @@ static inline void P_UnArchivePlayer(void) savedata.skincolor = READUINT8(save_p); savedata.skin = READUINT8(save_p); - savedata.score = READINT32(save_p); - savedata.lives = READINT32(save_p); + savedata.numgameovers = READUINT8(save_p); + savedata.lives = READSINT8(save_p); + savedata.score = READUINT32(save_p); savedata.continues = READINT32(save_p); if (savedata.botcolor) diff --git a/src/p_saveg.h b/src/p_saveg.h index 3670d3503..376552c95 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -38,6 +38,7 @@ typedef struct INT32 lives; INT32 continues; UINT16 emeralds; + UINT8 numgameovers; } savedata_t; extern savedata_t savedata; diff --git a/src/p_setup.c b/src/p_setup.c index 9c4bede74..c131f6677 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3026,6 +3026,7 @@ boolean P_SetupLevel(boolean skipprecip) if (savedata.lives > 0) { + numgameovers = savedata.numgameovers; players[consoleplayer].continues = savedata.continues; players[consoleplayer].lives = savedata.lives; players[consoleplayer].score = savedata.score; diff --git a/src/p_user.c b/src/p_user.c index 09cafa0b3..482bcc65d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -950,6 +950,8 @@ void P_GivePlayerRings(player_t *player, INT32 num_rings) // void P_GivePlayerLives(player_t *player, INT32 numlives) { + if (player->lives == 0x7f) return; + player->lives += numlives; if (player->lives > 99) @@ -1153,7 +1155,9 @@ void P_PlayLivesJingle(player_t *player) if (player && !P_IsLocalPlayer(player)) return; - if (gametype == GT_COOP && (netgame || multiplayer) && cv_cooplives.value == 0) + if ((player && player->lives == 0x7f) + || (!player && &players[consoleplayer] && players[consoleplayer].lives == 0x7f) + || (gametype == GT_COOP && (netgame || multiplayer) && cv_cooplives.value == 0)) S_StartSound(NULL, sfx_lose); else if (use1upSound) S_StartSound(NULL, sfx_oneup); @@ -8160,7 +8164,8 @@ boolean P_GetLives(player_t *player) INT32 i, maxlivesplayer = -1, livescheck = 1; if (!(netgame || multiplayer) || (gametype != GT_COOP) - || (cv_cooplives.value == 1)) + || (cv_cooplives.value == 1) + || (player->lives == 0x7f)) return true; if ((cv_cooplives.value == 2 || cv_cooplives.value == 0) && player->lives > 0) @@ -8187,7 +8192,8 @@ boolean P_GetLives(player_t *player) { if (cv_cooplives.value == 2 && (P_IsLocalPlayer(player) || P_IsLocalPlayer(&players[maxlivesplayer]))) S_StartSound(NULL, sfx_jshard); // placeholder - players[maxlivesplayer].lives--; + if (players[maxlivesplayer].lives != 0x7f) + players[maxlivesplayer].lives--; player->lives++; if (player->lives < 1) player->lives = 1; diff --git a/src/st_stuff.c b/src/st_stuff.c index 4515495af..ceef586a4 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -684,6 +684,8 @@ static inline void ST_drawRings(void) static void ST_drawLives(void) { const INT32 v_splitflag = (splitscreen && stplyr == &players[displayplayer] ? V_SPLITSCREEN : 0); + INT32 livescount; + boolean notgreyedout; if (!stplyr->skincolor) return; // Just joined a server, skin isn't loaded yet! @@ -723,66 +725,47 @@ static void ST_drawLives(void) V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, stlivex); // lives number - if ((netgame || multiplayer) && gametype == GT_COOP) + if ((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 3) { - switch (cv_cooplives.value) + INT32 i; + livescount = 0; + notgreyedout = (stplyr->lives > 0); + for (i = 0; i < MAXPLAYERS; i++) { - case 0: - V_DrawCharacter(hudinfo[HUD_LIVESNUM].x - 8, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), '\x16' | 0x80 | V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, false); - return; - case 3: - { - INT32 i, sum = 0; - boolean canrespawn = (stplyr->lives > 0); - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; + if (!playeringame[i]) + continue; - if (players[i].lives < 1) - continue; + if (players[i].lives < 1) + continue; - if (players[i].lives > 1) - canrespawn = true; + if (players[i].lives > 1) + notgreyedout = true; - sum += (players[i].lives); - } - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|(canrespawn ? V_HUDTRANS : V_HUDTRANSHALF)|v_splitflag, - va("%d",sum)); - return; - } -#if 0 // render the number of lives you COULD steal - case 2: - { - INT32 i, sum = 0; - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - if (&players[i] == stplyr) - continue; - - if (players[i].lives < 2) - continue; - - sum += (players[i].lives - 1); - } - V_DrawString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANSHALF|v_splitflag, va("/%d",sum)); - } - // intentional fallthrough -#endif - default: - // don't return so the SP one can be drawn below + if (players[i].lives == 0x7f) + { + livescount = 0x7f; break; + } + else if (livescount < 99) + livescount += (players[i].lives); } } + else + { + livescount = stplyr->lives; + notgreyedout = true; + } - V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, - va("%d",stplyr->lives)); + if (livescount == 0x7f) + V_DrawCharacter(hudinfo[HUD_LIVESNUM].x - 8, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), '\x16' | 0x80 | V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag, false); + else + { + if (livescount > 99) + livescount = 99; + V_DrawRightAlignedString(hudinfo[HUD_LIVESNUM].x, hudinfo[HUD_LIVESNUM].y + (v_splitflag ? -4 : 0), + V_SNAPTOLEFT|V_SNAPTOBOTTOM|(notgreyedout ? V_HUDTRANS : V_HUDTRANSHALF)|v_splitflag, + ((livescount > 99) ? "!!" : va("%d",livescount))); + } } static void ST_drawLevelTitle(void) From 9805b82feca902d798301e26c9dce1f0a1f91419 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 18 Aug 2017 18:14:03 +0100 Subject: [PATCH 38/61] Disable "connect self" due to being broken, cleaned up ip+port part Anyone know if "connect any" work at all? Would have disabled that too but apparently the game uses it if "-connect" is given with no params --- src/d_clisrv.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3878d8795..bb0978cdb 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2253,7 +2253,8 @@ static void Command_connect(void) CONS_Printf(M_GetText( "Connect (port): connect to a server\n" "Connect ANY: connect to the first lan server found\n" - "Connect SELF: connect to your own server.\n")); + //"Connect SELF: connect to your own server.\n" + )); return; } @@ -2267,7 +2268,7 @@ static void Command_connect(void) // we don't request a restart unless the filelist differs server = false; - +/* if (!stricmp(COM_Argv(1), "self")) { servernode = 0; @@ -2276,6 +2277,7 @@ static void Command_connect(void) //SV_SpawnServer(); } else +*/ { // used in menu to connect to a server in the list if (netgame && !stricmp(COM_Argv(1), "node")) @@ -2299,10 +2301,13 @@ static void Command_connect(void) if (!stricmp(COM_Argv(1), "any")) servernode = BROADCASTADDR; - else if (I_NetMakeNodewPort && COM_Argc() >= 3) - servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2)); else if (I_NetMakeNodewPort) - servernode = I_NetMakeNode(COM_Argv(1)); + { + if (COM_Argc() >= 3) // address AND port + servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2)); + else // address only, or address:port + servernode = I_NetMakeNode(COM_Argv(1)); + } else { CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n")); From d4141ae2302f229cc8e6e0836281a0c9d66f27a6 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 19 Aug 2017 18:51:56 +0100 Subject: [PATCH 39/61] Remove unused floorinfo_t struct and some unused vars in the hardware code --- src/hardware/hw_main.c | 2 -- src/hardware/hw_main.h | 12 +----------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d74cd0587..5ecde8a0b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4753,8 +4753,6 @@ static polyplaneinfo_t *polyplaneinfo = NULL; #ifndef SORTING size_t numfloors = 0; #else -//static floorinfo_t *floorinfo = NULL; -//static size_t numfloors = 0; //Hurdler: 3D water sutffs typedef struct gr_drawnode_s { diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index b0a14d3b5..cb49f817c 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -46,8 +46,7 @@ void HWR_SetViewSize(void); void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, const UINT8 *colormap); void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); -void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, INT32 option, fixed_t scale, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); -void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); +void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum); void HWR_PrepLevelCache(size_t pnumtextures); @@ -104,13 +103,4 @@ extern float gr_viewwindowx, gr_basewindowcentery; extern fixed_t *hwbbox; extern FTransform atransform; -typedef struct -{ - wallVert3D floorVerts[4]; - FSurfaceInfo Surf; - INT32 texnum; - INT32 blend; - INT32 drawcount; -} floorinfo_t; - #endif From 42211f02b45de766051a6b1ec68cf38489cb2aba Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 20 Aug 2017 13:14:17 +0100 Subject: [PATCH 40/61] * Per Mystic's request, only set the number of lives in the save file if you actually use a continue, or completely wipe out your lives and continues. * Fix a bug where I got emeralds and mapnumbers mixed up when checking for the "there's a tailsbot" flag. * Consider a save with an invalid skin an invalid save, rather than allowing its continued presence. --- src/g_game.c | 13 +++++++++---- src/g_game.h | 2 +- src/m_menu.c | 4 +++- src/p_inter.c | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index e16816e44..7ee7ccfbf 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3132,6 +3132,9 @@ static void G_DoContinued(void) tokenlist = 0; token = 0; + if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && (!modifiedgame || savemoddata) && cursaveslot >= 0) + G_SaveGameOver((UINT32)cursaveslot, true); + // Reset # of lives pl->lives = (ultimatemode) ? 1 : startinglivesbalance[numgameovers]; @@ -3664,7 +3667,7 @@ void G_SaveGame(UINT32 slot) #define BADSAVE goto cleanup; #define CHECKPOS if (save_p >= end_p) BADSAVE -void G_SaveGameOver(UINT32 slot) +void G_SaveGameOver(UINT32 slot, boolean modifylives) { boolean saved = false; size_t length; @@ -3700,12 +3703,14 @@ void G_SaveGameOver(UINT32 slot) save_p += VERSIONSIZE; // P_UnArchiveMisc() - fake = READINT16(save_p); + (void)READINT16(save_p); CHECKPOS - (void)READUINT16(save_p); // emeralds + fake = READUINT16(save_p)-357; // emeralds CHECKPOS READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to if (strcmp(temp, timeattackfolder)) BADSAVE + + // P_UnArchivePlayer() CHECKPOS (void)READUINT8(save_p); CHECKPOS @@ -3718,7 +3723,7 @@ void G_SaveGameOver(UINT32 slot) lives_p = save_p; pllives = READSINT8(save_p); // lives CHECKPOS - if (pllives < startinglivesbalance[numgameovers]) + if (modifylives && pllives < startinglivesbalance[numgameovers]) { pllives = startinglivesbalance[numgameovers]; WRITESINT8(lives_p, pllives); diff --git a/src/g_game.h b/src/g_game.h index 4ac78ab10..de04e2846 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -116,7 +116,7 @@ void G_SaveGameData(void); void G_SaveGame(UINT32 slot); -void G_SaveGameOver(UINT32 slot); +void G_SaveGameOver(UINT32 slot, boolean modifylives); // Only called by startup code. void G_RecordDemo(const char *name); diff --git a/src/m_menu.c b/src/m_menu.c index af3b0c7ca..36b0bc54e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6098,7 +6098,7 @@ static void M_DrawLoadGameData(void) // Use the big face pic for lives, duh. :3 V_DrawScaledPatch(ecks + 12, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); if (savegameinfo[saveSlotSelected].lives == 0x7F) - V_DrawScaledPatch(ecks + 40 - 18, 172, 0, tallinfin); + V_DrawScaledPatch(ecks + 40 - 17, 172, 0, tallinfin); else V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); @@ -6290,8 +6290,10 @@ static void M_ReadSavegameInfo(UINT32 slot) // P_UnArchivePlayer() CHECKPOS savegameinfo[slot].skincolor = READUINT8(save_p); + CHECKPOS savegameinfo[slot].skinnum = READUINT8(save_p); + if (savegameinfo[slot].skinnum >= numskins) BADSAVE CHECKPOS (void)READUINT8(save_p); // numgameovers diff --git a/src/p_inter.c b/src/p_inter.c index 284003c31..f356c642c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2294,7 +2294,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { numgameovers++; if ((!modifiedgame || savemoddata) && cursaveslot >= 0) - G_SaveGameOver((UINT32)cursaveslot); + G_SaveGameOver((UINT32)cursaveslot, (target->player->continues <= 0)); } } } From 706eb5efeb224e8d9f5a4c7140568b2fffde5703 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 20 Aug 2017 23:18:47 +0100 Subject: [PATCH 41/61] * New, pretty save select! Requires patch.dta to really appreciate. * Changed the save format a little more, since I had free reign over it. * Modified the string drawing functions to not awkwardly clip at the very edges of the screen, considering the relevant patch drawing functions avoid out-of-range memory writes. --- src/f_finale.c | 6 +- src/g_game.c | 88 +------- src/m_menu.c | 533 ++++++++++++++++++++++++++++++------------------- src/m_menu.h | 5 +- src/p_inter.c | 2 +- src/p_saveg.c | 31 +-- src/p_saveg.h | 2 - src/p_setup.c | 11 +- src/v_video.c | 8 +- 9 files changed, 357 insertions(+), 329 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index db497daf7..e9d3524b8 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1114,7 +1114,7 @@ void F_StartCredits(void) M_ClearMenus(true); // Save the second we enter the credits - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot >= 0) + if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) G_SaveGame((UINT32)cursaveslot); if (creditscutscene) @@ -1252,7 +1252,7 @@ static boolean drawemblem = false, drawchaosemblem = false; void F_StartGameEvaluation(void) { // Credits option in secrets menu - if (cursaveslot == -2) + if (cursaveslot == -1) { F_StartGameEnd(); return; @@ -1266,7 +1266,7 @@ void F_StartGameEvaluation(void) // Save the second we enter the evaluation // We need to do this again! Remember, it's possible a mod designed skipped // the credits sequence! - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot >= 0) + if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) G_SaveGame((UINT32)cursaveslot); gameaction = ga_nothing; diff --git a/src/g_game.c b/src/g_game.c index 7ee7ccfbf..dd0a8acb3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -76,7 +76,7 @@ INT16 gamemap = 1; INT16 maptol; UINT8 globalweather = 0; INT32 curWeather = PRECIP_NONE; -INT32 cursaveslot = -1; // Auto-save 1p savegame slot +INT32 cursaveslot = 0; // Auto-save 1p savegame slot //INT16 lastmapsaved = 0; // Last map we auto-saved at INT16 lastmaploaded = 0; // Last map the game loaded boolean gamecomplete = false; @@ -3132,7 +3132,7 @@ static void G_DoContinued(void) tokenlist = 0; token = 0; - if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && (!modifiedgame || savemoddata) && cursaveslot >= 0) + if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && (!modifiedgame || savemoddata) && cursaveslot > 0) G_SaveGameOver((UINT32)cursaveslot, true); // Reset # of lives @@ -3475,59 +3475,6 @@ void G_SaveGameData(void) #define VERSIONSIZE 16 -#ifdef SAVEGAMES_OTHERVERSIONS -static INT16 startonmapnum = 0; - -// -// User wants to load a savegame from a different version? -// -static void M_ForceLoadGameResponse(INT32 ch) -{ - if (ch != 'y' && ch != KEY_ENTER) - { - //refused - Z_Free(savebuffer); - save_p = savebuffer = NULL; - startonmapnum = 0; - M_SetupNextMenu(&SP_LoadDef); - return; - } - - // pick up where we left off. - save_p += VERSIONSIZE; - if (!P_LoadGame(startonmapnum)) - { - M_ClearMenus(true); // so ESC backs out to title - M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING); - Command_ExitGame_f(); - Z_Free(savebuffer); - save_p = savebuffer = NULL; - startonmapnum = 0; - - // no cheating! - memset(&savedata, 0, sizeof(savedata)); - return; - } - - // done - Z_Free(savebuffer); - save_p = savebuffer = NULL; - startonmapnum = 0; - - //set cursaveslot to -1 so nothing gets saved. - cursaveslot = -1; - - displayplayer = consoleplayer; - multiplayer = splitscreen = false; - - if (setsizeneeded) - R_ExecuteSetViewSize(); - - M_ClearMenus(true); - CON_ToggleOff(); -} -#endif - // // G_InitFromSavegame // Can be called by the startup code or the menu task. @@ -3687,7 +3634,6 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) { char temp[sizeof(timeattackfolder)]; - INT32 fake; // Dummy variable UINT8 *end_p = savebuffer + length; UINT8 *lives_p; SINT8 pllives; @@ -3696,25 +3642,20 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, "version %d", VERSION); -#ifndef SAVEGAMES_OTHERVERSIONS - if (strcmp((const char *)save_p, (const char *)vcheck)) - BADSAVE; -#endif + if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE save_p += VERSIONSIZE; // P_UnArchiveMisc() (void)READINT16(save_p); CHECKPOS - fake = READUINT16(save_p)-357; // emeralds + (void)READUINT16(save_p); // emeralds CHECKPOS READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to if (strcmp(temp, timeattackfolder)) BADSAVE // P_UnArchivePlayer() CHECKPOS - (void)READUINT8(save_p); - CHECKPOS - (void)READUINT8(save_p); + (void)READUINT16(save_p); CHECKPOS WRITEUINT8(save_p, numgameovers); @@ -3733,14 +3674,6 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) CHECKPOS (void)READINT32(save_p); // continues - if (fake & (1<<10)) - { - CHECKPOS - (void)READUINT8(save_p); - CHECKPOS - (void)READUINT8(save_p); // because why not. - } - // File end marker check CHECKPOS if (READUINT8(save_p) != 0x1d) BADSAVE; @@ -3768,7 +3701,7 @@ cleanup: // void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, boolean SSSG, boolean FLS) { - UINT8 color = 0; + UINT8 color = skins[pickedchar].prefcolor; paused = false; if (demoplayback) @@ -3780,10 +3713,8 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b if (savedata.lives > 0) { - color = savedata.skincolor; - botskin = savedata.botskin; - botcolor = savedata.botcolor; - botingame = (botskin != 0); + if ((botingame = ((botskin = savedata.botskin) != 0))) + botcolor = skins[botskin-1].prefcolor; } else if (splitscreen != SSSG) { @@ -3791,8 +3722,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 pickedchar, b SplitScreen_OnChange(); } - if (!color) - color = skins[pickedchar].prefcolor; + color = skins[pickedchar].prefcolor; SetPlayerSkinByNum(consoleplayer, pickedchar); CV_StealthSet(&cv_skin, skins[pickedchar].name); CV_StealthSetValue(&cv_playercolor, color); diff --git a/src/m_menu.c b/src/m_menu.c index 36b0bc54e..471012b9b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -172,7 +172,8 @@ static char joystickInfo[8][25]; static UINT32 serverlistpage; #endif -static saveinfo_t savegameinfo[MAXSAVEGAMES]; // Extra info about the save games. +static UINT8 numsaves = 0; +static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. INT16 startmap; // Mario, NiGHTS, or just a plain old normal game? @@ -4406,12 +4407,12 @@ static void M_DrawLevelPlatterMenu(void) V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_CACHE)); // handle movement of cursor box - if (abs(lsoffs[0]) > 1) + if (lsoffs[0] > 1 || lsoffs[0] < -1) lsoffs[0] = 2*lsoffs[0]/3; else lsoffs[0] = 0; - if (abs(lsoffs[1]) > 1) + if (lsoffs[1] > 1 || lsoffs[1] < -1) lsoffs[1] = 2*lsoffs[1]/3; else lsoffs[1] = 0; @@ -5395,7 +5396,7 @@ static void M_LevelSelectWarp(INT32 choice) G_LoadGame((UINT32)cursaveslot, startmap); else { - cursaveslot = -1; + cursaveslot = 0; M_SetupChoosePlayer(0); } } @@ -5970,7 +5971,7 @@ static void M_CustomWarp(INT32 choice) static void M_Credits(INT32 choice) { (void)choice; - cursaveslot = -2; + cursaveslot = -1; M_ClearMenus(true); F_StartCredits(); } @@ -6028,152 +6029,264 @@ static void M_LoadGameLevelSelect(INT32 choice) // LOAD GAME MENU // ============== -static INT32 saveSlotSelected = 0; -static short menumovedir = 0; +static INT32 saveSlotSelected = 1; +static INT32 loadgamescroll = 0; +static UINT8 loadgameoffset = 0; static void M_DrawLoadGameData(void) { - INT32 ecks; - INT32 i; + INT32 i, savetodraw, x, y; + skin_t *charskin = NULL; - ecks = SP_LoadDef.x + 24; - M_DrawTextBox(SP_LoadDef.x-12,144, 24, 4); - - if (saveSlotSelected == NOSAVESLOT) // last slot is play without saving + for (i = -2; i <= 2; i++) { - if (ultimate_selectable) + savetodraw = (saveSlotSelected + i + numsaves)%numsaves; + x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*90); + y = 33 + 9; + { - V_DrawCenteredString(ecks + 68, 144, V_ORANGEMAP, "ULTIMATE MODE"); - V_DrawCenteredString(ecks + 68, 156, 0, "NO RINGS, NO ONE-UPS,"); - V_DrawCenteredString(ecks + 68, 164, 0, "NO CONTINUES, ONE LIFE,"); - V_DrawCenteredString(ecks + 68, 172, 0, "FINAL DESTINATION."); + INT32 diff = x - (BASEVIDWIDTH/2 - 42); + if (diff < 0) + diff = -diff; + diff = (42 - diff)/3 - loadgameoffset; + if (diff < 0) + diff = 0; + y -= diff; } - else - { - V_DrawCenteredString(ecks + 68, 144, V_ORANGEMAP, "PLAY WITHOUT SAVING"); - V_DrawCenteredString(ecks + 68, 156, 0, "THIS GAME WILL NOT BE"); - V_DrawCenteredString(ecks + 68, 164, 0, "SAVED, BUT YOU CAN STILL"); - V_DrawCenteredString(ecks + 68, 172, 0, "GET EMBLEMS AND SECRETS."); - } - return; - } - - if (savegameinfo[saveSlotSelected].lives == -42) // Empty - { - V_DrawCenteredString(ecks + 68, 160, 0, "NO DATA"); - return; - } - - if (savegameinfo[saveSlotSelected].lives == -666) // savegame is bad - { - V_DrawCenteredString(ecks + 68, 144, V_REDMAP, "CORRUPT SAVE FILE"); - V_DrawCenteredString(ecks + 68, 156, 0, "THIS SAVE FILE"); - V_DrawCenteredString(ecks + 68, 164, 0, "CAN NOT BE LOADED."); - V_DrawCenteredString(ecks + 68, 172, 0, "DELETE USING BACKSPACE."); - return; - } - - // Draw the back sprite, it looks ugly if we don't - V_DrawScaledPatch(SP_LoadDef.x, 144+8, 0, livesback); - if (savegameinfo[saveSlotSelected].skincolor == 0) - V_DrawScaledPatch(SP_LoadDef.x,144+8,0,W_CachePatchName(skins[savegameinfo[saveSlotSelected].skinnum].face, PU_CACHE)); - else - { - UINT8 *colormap = R_GetTranslationColormap(savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor, 0); - V_DrawMappedPatch(SP_LoadDef.x,144+8,0,W_CachePatchName(skins[savegameinfo[saveSlotSelected].skinnum].face, PU_CACHE), colormap); - } - - V_DrawString(ecks + 12, 152, 0, savegameinfo[saveSlotSelected].playername); - -#ifdef SAVEGAMES_OTHERVERSIONS - if (savegameinfo[saveSlotSelected].gamemap & 16384) - V_DrawCenteredString(ecks + 68, 144, V_REDMAP, "OUTDATED SAVE FILE!"); -#endif - - if (savegameinfo[saveSlotSelected].gamemap & 8192) - V_DrawString(ecks + 12, 160, V_GREENMAP, "CLEAR!"); - else - V_DrawString(ecks + 12, 160, 0, va("%s", savegameinfo[saveSlotSelected].levelname)); - - // Use the big face pic for lives, duh. :3 - V_DrawScaledPatch(ecks + 12, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - if (savegameinfo[saveSlotSelected].lives == 0x7F) - V_DrawScaledPatch(ecks + 40 - 17, 172, 0, tallinfin); - else - V_DrawTallNum(ecks + 40, 172, 0, savegameinfo[saveSlotSelected].lives); - - // Absolute ridiculousness, condensed into another function. - V_DrawContinueIcon(ecks + 58, 182, 0, savegameinfo[saveSlotSelected].skinnum, savegameinfo[saveSlotSelected].skincolor); - V_DrawScaledPatch(ecks + 68, 175, 0, W_CachePatchName("STLIVEX", PU_HUDGFX)); - V_DrawTallNum(ecks + 96, 172, 0, savegameinfo[saveSlotSelected].continues); - - for (i = 0; i < 7; ++i) - { - if (savegameinfo[saveSlotSelected].numemeralds & (1 << i)) - V_DrawScaledPatch(ecks + 104 + (i * 8), 172, 0, tinyemeraldpics[i]); - } -} - -#define LOADBARHEIGHT SP_LoadDef.y + (LINEHEIGHT * (j+1)) + ymod -#define CURSORHEIGHT SP_LoadDef.y + (LINEHEIGHT*3) - 1 -static void M_DrawLoad(void) -{ - INT32 i, j; - INT32 ymod = 0, offset = 0; - - M_DrawMenuTitle(); - - if (menumovedir != 0) //movement illusion - { - ymod = (-(LINEHEIGHT/4))*menumovedir; - offset = ((menumovedir > 0) ? -1 : 1); - } - - V_DrawCenteredString(BASEVIDWIDTH/2, 40, 0, "Press backspace to delete a save."); - - for (i = MAXSAVEGAMES + saveSlotSelected - 2 + offset, j = 0;i <= MAXSAVEGAMES + saveSlotSelected + 2 + offset; i++, j++) - { - if ((menumovedir < 0 && j == 4) || (menumovedir > 0 && j == 0)) - continue; //this helps give the illusion of movement - - M_DrawSaveLoadBorder(SP_LoadDef.x, LOADBARHEIGHT); - - if ((i%MAXSAVEGAMES) == NOSAVESLOT) // play without saving + + if (savetodraw == 0) { + V_DrawSmallScaledPatch(x, y, 0, + W_CachePatchName("SAVENONE", PU_CACHE)); + x += 2; + y += 1; + V_DrawString(x, y, + ((savetodraw == saveSlotSelected) ? V_YELLOWMAP : 0), + "NO FILE"); + if (savetodraw == saveSlotSelected) + V_DrawFill(x, y+9, 80, 1, yellowmap[3]); + y += 11; + V_DrawSmallScaledPatch(x, y, V_STATIC, + W_CachePatchName("BLACKLVL", PU_CACHE)); + y += 41; if (ultimate_selectable) - V_DrawCenteredString(SP_LoadDef.x+92, LOADBARHEIGHT - 1, V_ORANGEMAP, "ULTIMATE MODE"); + V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ULTIMATE."); else - V_DrawCenteredString(SP_LoadDef.x+92, LOADBARHEIGHT - 1, V_ORANGEMAP, "PLAY WITHOUT SAVING"); + V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "DON'T SAVE!"); continue; } - if (savegameinfo[i%MAXSAVEGAMES].lives == -42) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, V_TRANSLUCENT, "NO DATA"); - else if (savegameinfo[i%MAXSAVEGAMES].lives == -666) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, V_REDMAP, "CORRUPT SAVE FILE"); - else if (savegameinfo[i%MAXSAVEGAMES].gamemap & 8192) - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, V_GREENMAP, "CLEAR!"); - else - V_DrawString(SP_LoadDef.x-6, LOADBARHEIGHT - 1, 0, va("%s", savegameinfo[i%MAXSAVEGAMES].levelname)); + savetodraw--; - //Draw the save slot number on the right side - V_DrawRightAlignedString(SP_LoadDef.x+192, LOADBARHEIGHT - 1, 0, va("%d",(i%MAXSAVEGAMES) + 1)); + // signpost background + { + UINT8 col; + if (savegameinfo[savetodraw].botskin == 3) // & knuckles + col = 105; + else if (savegameinfo[savetodraw].botskin) // tailsbot or custom + col = 134; + else if (savegameinfo[savetodraw].lives == -42) + col = 26; + else if (savegameinfo[savetodraw].lives == -666) + col = 47; + else + { + charskin = &skins[savegameinfo[savetodraw].skinnum]; + col = (charskin->prefcolor - 1)*2; + col = Color_Index[Color_Opposite[col]-1][Color_Opposite[col+1]]; + } + + V_DrawFill(x+6, y+64, 72, 50, col); + } + + V_DrawSmallScaledPatch(x, y, 0, + W_CachePatchName("SAVEBACK", PU_CACHE)); + x += 2; + y += 1; + V_DrawString(x, y, + ((savetodraw == saveSlotSelected-1) ? V_YELLOWMAP : 0), + va("FILE %d", savetodraw+1)); + if (savetodraw == saveSlotSelected-1) + V_DrawFill(x, y+9, 80, 1, yellowmap[3]); + y += 11; + + // level image area + { + patch_t *patch; + INT32 flags = 0; + + if ((savegameinfo[savetodraw].lives == -42) + || (savegameinfo[savetodraw].lives == -666)) + { + patch = W_CachePatchName("BLACKLVL", PU_CACHE); + flags = V_STATIC; + } + else if (savegameinfo[savetodraw].gamemap & 8192) + patch = W_CachePatchName("GAMEDONE", PU_CACHE); + else + { + lumpnum_t lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName((savegameinfo[savetodraw].gamemap) & 8191))); + if (lumpnum != LUMPERROR) + patch = W_CachePatchNum(lumpnum, PU_CACHE); + else + patch = W_CachePatchName("BLANKLVL", PU_CACHE); + } + + V_DrawSmallScaledPatch(x, y, flags, patch); + + y += 41; + + if (savegameinfo[savetodraw].lives == -42) + V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME"); + else if (savegameinfo[savetodraw].lives == -666) + V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "CAN'T LOAD!"); + else if (savegameinfo[savetodraw].gamemap & 8192) + V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!"); + else + V_DrawRightAlignedThinString(x + 79, y, V_YELLOWMAP, savegameinfo[savetodraw].levelname); + } + + if ((savegameinfo[savetodraw].lives == -42) + || (savegameinfo[savetodraw].lives == -666)) + continue; + + y += 51; + + // character heads, lives, and continues + { + spritedef_t *sprdef; + spriteframe_t *sprframe; + patch_t *patch; + UINT8 *colormap = NULL; + + INT32 tempx = (x+40)<sprites[SPR2_SIGN]; + if (!sprdef->numframes) + goto skipbot; + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin, charbotskin->prefcolor, 0); + sprframe = &sprdef->spriteframes[0]; + patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + + V_DrawFixedPatch( + tempx + (18<highresscale, + 0, patch, colormap); + + Z_Free(colormap); + + tempx -= (15<sprites[SPR2_SIGN]; + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].skinnum, charskin->prefcolor, 0); + if (!sprdef->numframes) + goto skipsign; + sprframe = &sprdef->spriteframes[0]; + patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + + V_DrawFixedPatch( + tempx, + tempy, + charskin->highresscale, + flip, patch, colormap); + +skipsign: + y += 25; + + tempx = x + 10; + if (savegameinfo[savetodraw].lives != 0x7f + && savegameinfo[savetodraw].lives > 9) + tempx -= 4; + + if (!charskin) // shut up compiler + goto skiplife; + + // lives + sprdef = &charskin->sprites[SPR2_LIFE]; + if (!sprdef->numframes) + goto skiplife; + sprframe = &sprdef->spriteframes[0]; + patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + + V_DrawFixedPatch( + (tempx + 4)<highresscale/2, + 0, patch, colormap); +skiplife: + if (colormap) + Z_Free(colormap); + + patch = W_CachePatchName("STLIVEX", PU_CACHE); + + V_DrawScaledPatch(tempx + 9, y + 2, 0, patch); + tempx += 16; + if (savegameinfo[savetodraw].lives == 0x7f) + V_DrawCharacter(tempx, y + 1, '\x16', false); + else + V_DrawString(tempx, y, 0, va("%d", savegameinfo[savetodraw].lives)); + + tempx = x + 47; + if (savegameinfo[savetodraw].continues > 9) + tempx -= 4; + + // continues + if (savegameinfo[savetodraw].continues > 0) + { + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTSAVE", PU_CACHE)); + V_DrawScaledPatch(tempx + 9, y + 2, 0, patch); + V_DrawString(tempx + 16, y, 0, va("%d", savegameinfo[savetodraw].continues)); + } + else + { + V_DrawSmallScaledPatch(tempx, y, 0, W_CachePatchName("CONTNONE", PU_CACHE)); + V_DrawScaledPatch(tempx + 9, y + 2, 0, W_CachePatchName("STNONEX", PU_CACHE)); + V_DrawString(tempx + 16, y, V_GRAYMAP, "0"); + } + } + + x += 6; + y -= 12; + + // tiny emeralds + { + INT32 j; + for (j = 0; j < 7; ++j) + { + if (savegameinfo[savetodraw].numemeralds & (1 << j)) + V_DrawScaledPatch(x, y, 0, tinyemeraldpics[j]); + x += 10; + } + } } +} - //Draw cursors on both sides. - V_DrawScaledPatch( 32, CURSORHEIGHT, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); - V_DrawScaledPatch(274, CURSORHEIGHT, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); +static void M_DrawLoad(void) +{ + M_DrawMenuTitle(); + + if (loadgamescroll > 1 || loadgamescroll < -1) + loadgamescroll = 2*loadgamescroll/3; + else + loadgamescroll = 0; + + if (loadgameoffset > 1) + loadgameoffset = 2*loadgameoffset/3; + else + loadgameoffset = 0; M_DrawLoadGameData(); - - //finishing the movement illusion - if (menumovedir) - menumovedir += ((menumovedir > 0) ? 1 : -1); - if (abs(menumovedir) > 3) - menumovedir = 0; } -#undef LOADBARHEIGHT -#undef CURSORHEIGHT // // User wants to load this game @@ -6185,7 +6298,7 @@ static void M_LoadSelect(INT32 choice) if (saveSlotSelected == NOSAVESLOT) //last slot is play without saving { M_NewGame(); - cursaveslot = -1; + cursaveslot = 0; return; } @@ -6194,8 +6307,8 @@ static void M_LoadSelect(INT32 choice) // This slot is empty, so start a new game here. M_NewGame(); } - else if (savegameinfo[saveSlotSelected].gamemap & 8192) // Completed - M_LoadGameLevelSelect(saveSlotSelected + 1); + else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed + M_LoadGameLevelSelect(0); else G_LoadGame((UINT32)saveSlotSelected, 0); @@ -6217,12 +6330,11 @@ static void M_ReadSavegameInfo(UINT32 slot) INT32 fake; // Dummy variable char temp[sizeof(timeattackfolder)]; char vcheck[VERSIONSIZE]; -#ifdef SAVEGAMES_OTHERVERSIONS - boolean oldversion = false; -#endif sprintf(savename, savegamename, slot); + slot--; + length = FIL_ReadFile(savename, &savebuffer); if (length == 0) { @@ -6238,14 +6350,7 @@ static void M_ReadSavegameInfo(UINT32 slot) // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, "version %d", VERSION); - if (strcmp((const char *)save_p, (const char *)vcheck)) - { -#ifdef SAVEGAMES_OTHERVERSIONS - oldversion = true; -#else - BADSAVE // Incompatible versions? -#endif - } + if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE save_p += VERSIONSIZE; // dearchive all the modifications @@ -6267,20 +6372,10 @@ static void M_ReadSavegameInfo(UINT32 slot) savegameinfo[slot].actnum = mapheaderinfo[(fake-1) & 8191]->actnum; } -#ifdef SAVEGAMES_OTHERVERSIONS - if (oldversion) - { - if (fake == 24) //meh, let's count old Clear! saves too - fake |= 8192; - fake |= 16384; // marker for outdated version - } -#endif savegameinfo[slot].gamemap = fake; CHECKPOS - fake = READUINT16(save_p)-357; // emeralds - - savegameinfo[slot].numemeralds = (UINT8)fake; + savegameinfo[slot].numemeralds = READUINT16(save_p)-357; // emeralds CHECKPOS READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to @@ -6289,11 +6384,15 @@ static void M_ReadSavegameInfo(UINT32 slot) // P_UnArchivePlayer() CHECKPOS - savegameinfo[slot].skincolor = READUINT8(save_p); - - CHECKPOS - savegameinfo[slot].skinnum = READUINT8(save_p); - if (savegameinfo[slot].skinnum >= numskins) BADSAVE + fake = READUINT16(save_p); + savegameinfo[slot].skinnum = fake & ((1<<5) - 1); + if (savegameinfo[slot].skinnum >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) + BADSAVE + savegameinfo[slot].botskin = fake >> 5; + if (savegameinfo[slot].botskin-1 >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) + savegameinfo[slot].botskin = 0; CHECKPOS (void)READUINT8(save_p); // numgameovers @@ -6304,27 +6403,6 @@ static void M_ReadSavegameInfo(UINT32 slot) CHECKPOS savegameinfo[slot].continues = READINT32(save_p); // continues - if (fake & (1<<10)) - { - CHECKPOS - savegameinfo[slot].botskin = READUINT8(save_p); - if (savegameinfo[slot].botskin-1 >= numskins) - savegameinfo[slot].botskin = 0; - CHECKPOS - savegameinfo[slot].botcolor = READUINT8(save_p); // because why not. - } - else - savegameinfo[slot].botskin = 0; - - if (savegameinfo[slot].botskin) - snprintf(savegameinfo[slot].playername, 32, "%s & %s", - skins[savegameinfo[slot].skinnum].realname, - skins[savegameinfo[slot].botskin-1].realname); - else - strcpy(savegameinfo[slot].playername, skins[savegameinfo[slot].skinnum].realname); - - savegameinfo[slot].playername[31] = 0; - // File end marker check CHECKPOS if (READUINT8(save_p) != 0x1d) BADSAVE; @@ -6343,21 +6421,45 @@ static void M_ReadSavegameInfo(UINT32 slot) static void M_ReadSaveStrings(void) { FILE *handle; - UINT32 i; + SINT8 i; char name[256]; + boolean nofile[MAXSAVEGAMES-1]; + UINT8 tolerance = 0; - for (i = 0; i < MAXSAVEGAMES; i++) + loadgamescroll = 0; + loadgameoffset = 14; + + for (i = 1; ((i < MAXSAVEGAMES) && ((i <= saveSlotSelected) || (tolerance < 3))); i++) // slot 0 is no save { snprintf(name, sizeof name, savegamename, i); name[sizeof name - 1] = '\0'; handle = fopen(name, "rb"); - if (handle == NULL) + if ((nofile[i-1] = (handle == NULL))) { - savegameinfo[i].lives = -42; + tolerance++; continue; } fclose(handle); + tolerance = 0; + } + + if (savegameinfo) + Z_Free(savegameinfo); + savegameinfo = NULL; + + numsaves = i; + savegameinfo = Z_Realloc(savegameinfo, numsaves*sizeof(saveinfo_t), PU_STATIC, NULL); + if (!savegameinfo) + I_Error("Insufficient memory to prepare save platter"); + + for (; i > 0; i--) + { + if (nofile[i-1] == true) + { + savegameinfo[i-1].lives = -42; + continue; + } M_ReadSavegameInfo(i); } } @@ -6377,8 +6479,8 @@ static void M_SaveGameDeleteResponse(INT32 ch) name[sizeof name - 1] = '\0'; remove(name); - // Refresh savegame menu info - M_ReadSaveStrings(); + S_StartSound(NULL, sfx_bewar1+M_RandomKey(4)); // Bweh heh he + M_ReadSaveStrings(); // reload the menu } static void M_HandleLoadSave(INT32 choice) @@ -6387,26 +6489,33 @@ static void M_HandleLoadSave(INT32 choice) switch (choice) { - case KEY_DOWNARROW: - S_StartSound(NULL, sfx_menu1); + case KEY_RIGHTARROW: + S_StartSound(NULL, sfx_s3kb7); ++saveSlotSelected; - if (saveSlotSelected >= MAXSAVEGAMES) - saveSlotSelected -= MAXSAVEGAMES; - menumovedir = 1; + if (saveSlotSelected >= numsaves) + saveSlotSelected -= numsaves; + loadgamescroll = 90; break; - case KEY_UPARROW: - S_StartSound(NULL, sfx_menu1); + case KEY_LEFTARROW: + S_StartSound(NULL, sfx_s3kb7); --saveSlotSelected; if (saveSlotSelected < 0) - saveSlotSelected += MAXSAVEGAMES; - menumovedir = -1; + saveSlotSelected += numsaves; + loadgamescroll = -90; break; case KEY_ENTER: - S_StartSound(NULL, sfx_menu1); - if (savegameinfo[saveSlotSelected].lives != -666) // don't allow loading of "bad saves" + if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + { + S_StartSound(NULL, sfx_menu1); M_LoadSelect(saveSlotSelected); + } + else if (!loadgameoffset) + { + S_StartSound(NULL, sfx_s3kb2); + loadgameoffset = 14; + } break; case KEY_ESCAPE: @@ -6414,11 +6523,19 @@ static void M_HandleLoadSave(INT32 choice) break; case KEY_BACKSPACE: - S_StartSound(NULL, sfx_menu1); // Don't allow people to 'delete' "Play without Saving." // Nor allow people to 'delete' slots with no saves in them. - if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected].lives != -42) + if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected-1].lives != -42) + { + loadgamescroll = 0; + S_StartSound(NULL, sfx_skid); M_StartMessage(M_GetText("Are you sure you want to delete\nthis save game?\n\n(Press 'Y' to confirm)\n"),M_SaveGameDeleteResponse,MM_YESNO); + } + else if (!loadgameoffset) + { + S_StartSound(NULL, sfx_s3kb2); + loadgameoffset = 14; + } break; } if (exitmenu) @@ -6427,6 +6544,8 @@ static void M_HandleLoadSave(INT32 choice) M_SetupNextMenu(currentMenu->prevMenu); else M_ClearMenus(true); + Z_Free(savegameinfo); + savegameinfo = NULL; } } @@ -6451,9 +6570,9 @@ void M_ForceSaveSlotSelected(INT32 sslot) return; // Figure out whether to display up movement or down movement - menumovedir = (saveSlotSelected - sslot) > 0 ? -1 : 1; + /*menumovedir = (saveSlotSelected - sslot) > 0 ? -1 : 1; if (abs(saveSlotSelected - sslot) > (MAXSAVEGAMES>>1)) - menumovedir *= -1; + menumovedir *= -1;*/ saveSlotSelected = sslot; } @@ -6724,7 +6843,7 @@ static void M_ChoosePlayer(INT32 choice) } if (startmap != spstage_start) - cursaveslot = -1; + cursaveslot = 0; //lastmapsaved = 0; gamecomplete = false; @@ -6735,6 +6854,10 @@ static void M_ChoosePlayer(INT32 choice) if (levelselect.rows) Z_Free(levelselect.rows); levelselect.rows = NULL; + + if (savegameinfo) + Z_Free(savegameinfo); + savegameinfo = NULL; } // =============== diff --git a/src/m_menu.h b/src/m_menu.h index 2d2d3378b..e30724041 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -215,13 +215,10 @@ typedef struct // savegame struct for save game menu typedef struct { - char playername[32]; char levelname[32]; UINT8 actnum; - UINT8 skincolor; UINT8 skinnum; UINT8 botskin; - UINT8 botcolor; UINT8 numemeralds; INT32 lives; INT32 continues; @@ -237,7 +234,7 @@ extern INT16 startmap; extern INT32 ultimate_selectable; #define MAXSAVEGAMES 31 //note: last save game is "no save" -#define NOSAVESLOT MAXSAVEGAMES-1 //slot where Play Without Saving appears +#define NOSAVESLOT 0 //slot where Play Without Saving appears void M_ForceSaveSlotSelected(INT32 sslot); diff --git a/src/p_inter.c b/src/p_inter.c index f356c642c..5eee6a18e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2293,7 +2293,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking) && numgameovers < maxgameovers) { numgameovers++; - if ((!modifiedgame || savemoddata) && cursaveslot >= 0) + if ((!modifiedgame || savemoddata) && cursaveslot > 0) G_SaveGameOver((UINT32)cursaveslot, (target->player->continues <= 0)); } } diff --git a/src/p_saveg.c b/src/p_saveg.c index 9e1206c49..840f546af 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -64,23 +64,16 @@ typedef enum static inline void P_ArchivePlayer(void) { const player_t *player = &players[consoleplayer]; + INT16 skininfo = player->skin + (botskin<<5); SINT8 pllives = player->lives; if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player pllives = startinglivesbalance[numgameovers]; // has less than that. - WRITEUINT8(save_p, player->skincolor); - WRITEUINT8(save_p, player->skin); - + WRITEUINT16(save_p, skininfo); WRITEUINT8(save_p, numgameovers); WRITESINT8(save_p, pllives); WRITEUINT32(save_p, player->score); WRITEINT32(save_p, player->continues); - - if (botskin) - { - WRITEUINT8(save_p, botskin); - WRITEUINT8(save_p, botcolor); - } } // @@ -88,23 +81,14 @@ static inline void P_ArchivePlayer(void) // static inline void P_UnArchivePlayer(void) { - savedata.skincolor = READUINT8(save_p); - savedata.skin = READUINT8(save_p); + INT16 skininfo = READUINT16(save_p); + savedata.skin = skininfo & ((1<<5) - 1); + savedata.botskin = skininfo >> 5; savedata.numgameovers = READUINT8(save_p); savedata.lives = READSINT8(save_p); savedata.score = READUINT32(save_p); savedata.continues = READINT32(save_p); - - if (savedata.botcolor) - { - savedata.botskin = READUINT8(save_p); - if (savedata.botskin-1 >= numskins) - savedata.botskin = 0; - savedata.botcolor = READUINT8(save_p); - } - else - savedata.botskin = 0; } // @@ -3164,7 +3148,7 @@ static inline void P_ArchiveMisc(void) //lastmapsaved = gamemap; lastmaploaded = gamemap; - WRITEUINT16(save_p, (botskin ? (emeralds|(1<<10)) : emeralds)+357); + WRITEUINT16(save_p, emeralds+357); WRITESTRINGN(save_p, timeattackfolder, sizeof(timeattackfolder)); } @@ -3194,9 +3178,6 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) token = 0; savedata.emeralds = READUINT16(save_p)-357; - if (savedata.emeralds & (1<<10)) - savedata.botcolor = 0xFF; - savedata.emeralds &= 0xff; READSTRINGN(save_p, testname, sizeof(testname)); diff --git a/src/p_saveg.h b/src/p_saveg.h index 376552c95..5960660ab 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -30,10 +30,8 @@ mobj_t *P_FindNewPosition(UINT32 oldposition); typedef struct { - UINT8 skincolor; UINT8 skin; UINT8 botskin; - UINT8 botcolor; INT32 score; INT32 lives; INT32 continues; diff --git a/src/p_setup.c b/src/p_setup.c index c131f6677..1a8c3e5ba 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3019,7 +3019,7 @@ boolean P_SetupLevel(boolean skipprecip) P_RunCachedActions(); if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || players[consoleplayer].lives <= 0) - && (!modifiedgame || savemoddata) && cursaveslot >= 0 && CanSaveLevel(gamemap)) + && (!modifiedgame || savemoddata) && cursaveslot > 0 && CanSaveLevel(gamemap)) G_SaveGame((UINT32)cursaveslot); lastmaploaded = gamemap; // HAS to be set after saving!! @@ -3030,9 +3030,8 @@ boolean P_SetupLevel(boolean skipprecip) players[consoleplayer].continues = savedata.continues; players[consoleplayer].lives = savedata.lives; players[consoleplayer].score = savedata.score; - botskin = savedata.botskin; - botcolor = savedata.botcolor; - botingame = (savedata.botskin != 0); + if ((botingame = ((botskin = savedata.botskin) != 0))) + botcolor = skins[botskin-1].prefcolor; emeralds = savedata.emeralds; savedata.lives = 0; } @@ -3201,8 +3200,8 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) ST_Start(); // Prevent savefile cheating - if (cursaveslot >= 0) - cursaveslot = -1; + if (cursaveslot > 0) + cursaveslot = 0; if (replacedcurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) { diff --git a/src/v_video.c b/src/v_video.c index 6ac101f2d..b07237d74 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1422,9 +1422,9 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if (cx + w > scrwidth) + if (cx > scrwidth) break; - if (cx < 0) //left boundary check + if (cx + w < 0) //left boundary check { cx += w; continue; @@ -1628,9 +1628,9 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) else w = (SHORT(tny_font[c]->width) * dupx); - if (cx + w > scrwidth) + if (cx > scrwidth) break; - if (cx < 0) //left boundary check + if (cx + w < 0) //left boundary check { cx += w; continue; From 6e7605e4f3a16d35dceccaa1b73af545e8702fe5 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 21 Aug 2017 16:02:13 +0100 Subject: [PATCH 42/61] * Add new graphics for the no save and ultimate slots, and make the invalid files look a little different. * Push big endsign images downwards. * Add a way to disable the ultimate slot. * BwehHehHe() --- src/m_menu.c | 111 +++++++++++++++++++++++++++++++++------------------ src/m_menu.h | 2 + 2 files changed, 74 insertions(+), 39 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 471012b9b..480ec7ca2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4094,6 +4094,24 @@ static boolean M_PrepareLevelPlatter(INT32 gt) mapnum++; } +#ifdef SYMMETRICAL_PLATTER + // horizontally space out rows with missing right sides + for (; row >= 0; row--) + { + if (!levelselect.rows[row].maplist[2] // no right side + && levelselect.rows[row].maplist[0] && levelselect.rows[row].maplist[1]) // all the left filled in + { + levelselect.rows[row].maplist[2] = levelselect.rows[row].maplist[1]; + STRBUFCPY(levelselect.rows[row].mapnames[2], levelselect.rows[row].mapnames[1]); + levelselect.rows[row].mapavailable[2] = levelselect.rows[row].mapavailable[1]; + + levelselect.rows[row].maplist[1] = -1; // diamond + levelselect.rows[row].mapnames[1][0] = '\0'; + levelselect.rows[row].mapavailable[1] = false; + } + } +#endif + if (levselp[0][0]) // never going to have some provided but not all, saves individually checking { W_UnlockCachedPatch(levselp[0][0]); @@ -4231,7 +4249,7 @@ static void M_HandleLevelPlatter(INT32 choice) else if (!lsoffs[0]) // prevent sound spam { lsoffs[0] = -8; - S_StartSound(NULL,sfx_s3kb2); + S_StartSound(NULL,sfx_lose); } break; @@ -4277,7 +4295,7 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo patch_t *patch; INT32 map = levelselect.rows[row].maplist[col]; - if (!map) + if (map <= 0) return; // A 564x100 image of the level as entry MAPxxW @@ -4318,7 +4336,7 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea patch_t *patch; INT32 map = levelselect.rows[row].maplist[col]; - if (!map) + if (map <= 0) return; // A 160x100 image of the level as entry MAPxxP @@ -4403,7 +4421,7 @@ static void M_DrawLevelPlatterMenu(void) // draw cursor box V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey, 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)])); - if (levelselect.rows[lsrow].maplist[lscol]) + if (levelselect.rows[lsrow].maplist[lscol] > 0) V_DrawScaledPatch(lsbasex + cursorx-17, lsbasey+50+lsoffs[0], 0, W_CachePatchName("M_CURSOR", PU_CACHE)); // handle movement of cursor box @@ -6057,7 +6075,7 @@ static void M_DrawLoadGameData(void) if (savetodraw == 0) { V_DrawSmallScaledPatch(x, y, 0, - W_CachePatchName("SAVENONE", PU_CACHE)); + W_CachePatchName(((ultimate_selectable) ? "ULTIMATE" : "SAVENONE"), PU_CACHE)); x += 2; y += 1; V_DrawString(x, y, @@ -6067,7 +6085,7 @@ static void M_DrawLoadGameData(void) V_DrawFill(x, y+9, 80, 1, yellowmap[3]); y += 11; V_DrawSmallScaledPatch(x, y, V_STATIC, - W_CachePatchName("BLACKLVL", PU_CACHE)); + W_CachePatchName("BLACXLVL", PU_CACHE)); y += 41; if (ultimate_selectable) V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ULTIMATE."); @@ -6078,25 +6096,33 @@ static void M_DrawLoadGameData(void) savetodraw--; + if (savegameinfo[savetodraw].lives > 0) + charskin = &skins[savegameinfo[savetodraw].skinnum]; + // signpost background { UINT8 col; - if (savegameinfo[savetodraw].botskin == 3) // & knuckles - col = 105; - else if (savegameinfo[savetodraw].botskin) // tailsbot or custom - col = 134; - else if (savegameinfo[savetodraw].lives == -42) - col = 26; - else if (savegameinfo[savetodraw].lives == -666) - col = 47; + if (savegameinfo[savetodraw].lives == -666) + { + V_DrawSmallScaledPatch(x+2, y+64, 0, + W_CachePatchName("BLANKLVL", PU_CACHE)); + } else { - charskin = &skins[savegameinfo[savetodraw].skinnum]; - col = (charskin->prefcolor - 1)*2; - col = Color_Index[Color_Opposite[col]-1][Color_Opposite[col+1]]; - } + if (savegameinfo[savetodraw].lives == -42) + col = 26; + else if (savegameinfo[savetodraw].botskin == 3) // & knuckles + col = 105; + else if (savegameinfo[savetodraw].botskin) // tailsbot or custom + col = 134; + else + { + col = (charskin->prefcolor - 1)*2; + col = Color_Index[Color_Opposite[col]-1][Color_Opposite[col+1]]; + } - V_DrawFill(x+6, y+64, 72, 50, col); + V_DrawFill(x+6, y+64, 72, 50, col); + } } V_DrawSmallScaledPatch(x, y, 0, @@ -6150,7 +6176,20 @@ static void M_DrawLoadGameData(void) || (savegameinfo[savetodraw].lives == -666)) continue; - y += 51; + y += 64; + + // tiny emeralds + { + INT32 j, workx = x + 6; + for (j = 0; j < 7; ++j) + { + if (savegameinfo[savetodraw].numemeralds & (1 << j)) + V_DrawScaledPatch(workx, y, 0, tinyemeraldpics[j]); + workx += 10; + } + } + + y -= 13; // character heads, lives, and continues { @@ -6159,7 +6198,7 @@ static void M_DrawLoadGameData(void) patch_t *patch; UINT8 *colormap = NULL; - INT32 tempx = (x+40)<spriteframes[0]; patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + if ((calc = SHORT(patch->topoffset) - 42) > 0) + tempy += ((4+calc)< Date: Tue, 22 Aug 2017 21:02:33 +0100 Subject: [PATCH 43/61] * Fix an issue where valid savefiles would be hidden because there were at least three unused slots between that and the last visible save. In the process, made sure there were at least three slots visible at all times, but never show extras not needed to show all the saves. * Optimisations in a bunch of places, including to static * Fix some visual errors with text and patches near the edges of the screen in non-standard resolutions. --- src/m_menu.c | 120 ++++++++++++++++++++++++++------------------------ src/v_video.c | 92 ++++++++++++++++++++++++-------------- 2 files changed, 121 insertions(+), 91 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 480ec7ca2..214755651 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -174,6 +174,7 @@ static UINT32 serverlistpage; static UINT8 numsaves = 0; static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. +static patch_t *savselp[7]; INT16 startmap; // Mario, NiGHTS, or just a plain old normal game? @@ -223,7 +224,7 @@ static INT32 lsoffs[2]; #define lshli levelselectselect[2] #define lshseperation 101 -#define lsbasevseperation 62 +#define lsbasevseperation (62*vid.height)/(BASEVIDHEIGHT*vid.dupy) //62 #define lsheadingheight 16 #define getheadingoffset(row) (levelselect.rows[row].header[0] ? lsheadingheight : 0) #define lsvseperation(row) lsbasevseperation + getheadingoffset(row) @@ -4280,14 +4281,10 @@ void M_DrawLevelPlatterHeader(INT32 y, const char *header, boolean headerhighlig y += lsheadingheight - 12; V_DrawString(19, y, (headerhighlight ? V_YELLOWMAP : 0)|(allowlowercase ? V_ALLOWLOWERCASE : 0), header); y += 9; - if ((y >= 0) && (y < 200)) - { - V_DrawFill(19, y, 281, 1, (headerhighlight ? yellowmap[3] : 3)); - V_DrawFill(300, y, 1, 1, 26); - } + V_DrawFill(19, y, 281, 1, (headerhighlight ? yellowmap[3] : 3)); + V_DrawFill(300, y, 1, 1, 26); y++; - if ((y >= 0) && (y < 200)) - V_DrawFill(19, y, 282, 1, 26); + V_DrawFill(19, y, 282, 1, 26); } static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolean highlight) @@ -4311,22 +4308,9 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo V_DrawSmallScaledPatch(x, y, 0, patch); } - if ((y+50) < 200) - { - INT32 topy = (y+50), h = 8; - - if (topy < 0) - { - h += topy; - topy = 0; - } - else if (topy + h >= 200) - h = 200 - y; - if (h > 0) - V_DrawFill(x, topy, 282, h, - ((mapheaderinfo[map-1]->unlockrequired < 0) - ? 159 : 63)); - } + V_DrawFill(x, y+50, 282, 8, + ((mapheaderinfo[map-1]->unlockrequired < 0) + ? 159 : 63)); V_DrawString(x, y+50, (highlight ? V_YELLOWMAP : 0), levelselect.rows[row].mapnames[col]); } @@ -4352,22 +4336,9 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea V_DrawSmallScaledPatch(x, y, 0, patch); } - if ((y+50) < 200) - { - INT32 topy = (y+50), h = 8; - - if (topy < 0) - { - h += topy; - topy = 0; - } - else if (topy + h >= 200) - h = 200 - y; - if (h > 0) - V_DrawFill(x, topy, 80, h, - ((mapheaderinfo[map-1]->unlockrequired < 0) - ? 159 : 63)); - } + V_DrawFill(x, y+50, 80, 8, + ((mapheaderinfo[map-1]->unlockrequired < 0) + ? 159 : 63)); if (strlen(levelselect.rows[row].mapnames[col]) > 6) // "AERIAL GARDEN" vs "ACT 18" - "THE ACT" intentionally compressed V_DrawThinString(x, y+50, (highlight ? V_YELLOWMAP : 0), levelselect.rows[row].mapnames[col]); @@ -6053,13 +6024,16 @@ static UINT8 loadgameoffset = 0; static void M_DrawLoadGameData(void) { - INT32 i, savetodraw, x, y; + INT32 i, savetodraw, x, y, hsep = 90; skin_t *charskin = NULL; + if (vid.width != BASEVIDWIDTH*vid.dupx) + hsep = (hsep*vid.width)/(BASEVIDWIDTH*vid.dupx); + for (i = -2; i <= 2; i++) { savetodraw = (saveSlotSelected + i + numsaves)%numsaves; - x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*90); + x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*hsep); y = 33 + 9; { @@ -6075,7 +6049,7 @@ static void M_DrawLoadGameData(void) if (savetodraw == 0) { V_DrawSmallScaledPatch(x, y, 0, - W_CachePatchName(((ultimate_selectable) ? "ULTIMATE" : "SAVENONE"), PU_CACHE)); + savselp[((ultimate_selectable) ? 2 : 1)]); x += 2; y += 1; V_DrawString(x, y, @@ -6084,8 +6058,7 @@ static void M_DrawLoadGameData(void) if (savetodraw == saveSlotSelected) V_DrawFill(x, y+9, 80, 1, yellowmap[3]); y += 11; - V_DrawSmallScaledPatch(x, y, V_STATIC, - W_CachePatchName("BLACXLVL", PU_CACHE)); + V_DrawSmallScaledPatch(x, y, V_STATIC, savselp[4]); y += 41; if (ultimate_selectable) V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "ULTIMATE."); @@ -6104,8 +6077,7 @@ static void M_DrawLoadGameData(void) UINT8 col; if (savegameinfo[savetodraw].lives == -666) { - V_DrawSmallScaledPatch(x+2, y+64, 0, - W_CachePatchName("BLANKLVL", PU_CACHE)); + V_DrawSmallScaledPatch(x+2, y+64, 0, savselp[5]); } else { @@ -6125,8 +6097,7 @@ static void M_DrawLoadGameData(void) } } - V_DrawSmallScaledPatch(x, y, 0, - W_CachePatchName("SAVEBACK", PU_CACHE)); + V_DrawSmallScaledPatch(x, y, 0, savselp[0]); x += 2; y += 1; V_DrawString(x, y, @@ -6144,18 +6115,18 @@ static void M_DrawLoadGameData(void) if ((savegameinfo[savetodraw].lives == -42) || (savegameinfo[savetodraw].lives == -666)) { - patch = W_CachePatchName("BLACKLVL", PU_CACHE); + patch = savselp[3]; flags = V_STATIC; } else if (savegameinfo[savetodraw].gamemap & 8192) - patch = W_CachePatchName("GAMEDONE", PU_CACHE); + patch = savselp[6]; else { lumpnum_t lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName((savegameinfo[savetodraw].gamemap) & 8191))); if (lumpnum != LUMPERROR) patch = W_CachePatchNum(lumpnum, PU_CACHE); else - patch = W_CachePatchName("BLANKLVL", PU_CACHE); + patch = savselp[5]; } V_DrawSmallScaledPatch(x, y, flags, patch); @@ -6451,30 +6422,42 @@ static void M_ReadSaveStrings(void) SINT8 i; char name[256]; boolean nofile[MAXSAVEGAMES-1]; - UINT8 tolerance = 0; + SINT8 tolerance = 3; // empty slots at any time + UINT8 lastseen = 0; loadgamescroll = 0; loadgameoffset = 14; - for (i = 1; ((i < MAXSAVEGAMES) && ((i <= saveSlotSelected) || (tolerance < 3))); i++) // slot 0 is no save + for (i = 1; (i < MAXSAVEGAMES); i++) // slot 0 is no save { snprintf(name, sizeof name, savegamename, i); name[sizeof name - 1] = '\0'; handle = fopen(name, "rb"); if ((nofile[i-1] = (handle == NULL))) - { - tolerance++; continue; - } fclose(handle); - tolerance = 0; + lastseen = i; } if (savegameinfo) Z_Free(savegameinfo); savegameinfo = NULL; + if (lastseen < saveSlotSelected) + lastseen = saveSlotSelected; + + i = lastseen; + + for (; (lastseen > 0 && tolerance); lastseen--) + { + if (nofile[lastseen-1]) + tolerance--; + } + + if ((i += tolerance+1) > MAXSAVEGAMES) // show 3 empty slots at minimum + i = MAXSAVEGAMES; + numsaves = i; savegameinfo = Z_Realloc(savegameinfo, numsaves*sizeof(saveinfo_t), PU_STATIC, NULL); if (!savegameinfo) @@ -6489,6 +6472,27 @@ static void M_ReadSaveStrings(void) } M_ReadSavegameInfo(i); } + + if (savselp[0]) // never going to have some provided but not all, saves individually checking + { + W_UnlockCachedPatch(savselp[0]); + W_UnlockCachedPatch(savselp[1]); + W_UnlockCachedPatch(savselp[2]); + + W_UnlockCachedPatch(savselp[3]); + W_UnlockCachedPatch(savselp[4]); + W_UnlockCachedPatch(savselp[5]); + W_UnlockCachedPatch(savselp[6]); + } + + savselp[0] = W_CachePatchName("SAVEBACK", PU_STATIC); + savselp[1] = W_CachePatchName("SAVENONE", PU_STATIC); + savselp[2] = W_CachePatchName("ULTIMATE", PU_STATIC); + + savselp[3] = W_CachePatchName("BLACKLVL", PU_STATIC); + savselp[4] = W_CachePatchName("BLACXLVL", PU_STATIC); + savselp[5] = W_CachePatchName("BLANKLVW", PU_STATIC); + savselp[6] = W_CachePatchName("GAMEDONE", PU_STATIC); } // diff --git a/src/v_video.c b/src/v_video.c index b07237d74..d965a0939 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -524,12 +524,20 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix { return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); } + +static UINT8 staticstep[2] = {0, 0}; + static inline UINT8 staticpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { UINT8 val = source[ofs>>FRACBITS]; (void)dest; + if ((++staticstep[1]) >= 4) + { + staticstep[1] = 0; + staticstep[0] = M_RandomFixed(); + } if (val < 7) return val; - return M_RandomKey(7+1)+(val-7);//M_RandomByte(); + return ((staticstep[0]>>staticstep[1])&7)+(val-7); } // Draws a patch scaled to arbitrary size. @@ -660,30 +668,10 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t y = FixedMul(y,dupy<>= FRACBITS; y >>= FRACBITS; - desttop += (y*vid.width) + x; // Center it if necessary if (!(scrn & V_SCALEPATCHMASK)) { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) - desttop += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)) * vid.width; - else if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } // if it's meant to cover the whole screen, black out the rest if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) { @@ -691,7 +679,29 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t source = (const UINT8 *)(column) + 3; V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } + + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (scrn & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(scrn & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); + else if (scrn & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(scrn & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } } + + desttop += (y*vid.width) + x; } if (pscale != FRACUNIT) // scale width properly @@ -1346,7 +1356,7 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string) // void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0; + INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0; const char *ch = string; INT32 charflags = 0; const UINT8 *colormap = NULL; @@ -1362,7 +1372,11 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } charflags = (option & V_CHARCOLORMASK); @@ -1422,9 +1436,9 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if (cx > scrwidth) + if (cx+left > scrwidth) break; - if (cx + w < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w; continue; @@ -1455,7 +1469,7 @@ void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string // void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0; + INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, center = 0, left = 0; const char *ch = string; INT32 charflags = 0; const UINT8 *colormap = NULL; @@ -1471,7 +1485,11 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } charflags = (option & V_CHARCOLORMASK); @@ -1529,9 +1547,9 @@ void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string) } else w = SHORT(hu_font[c]->width) * dupx / 2; - if (cx + w > scrwidth) + if (cx+left > scrwidth) break; - if (cx < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w; continue; @@ -1556,7 +1574,7 @@ void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *s // void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) { - INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH; + INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth, left = 0; const char *ch = string; INT32 charflags = 0; const UINT8 *colormap = NULL; @@ -1572,7 +1590,11 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } charflags = (option & V_CHARCOLORMASK); @@ -1628,9 +1650,9 @@ void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string) else w = (SHORT(tny_font[c]->width) * dupx); - if (cx > scrwidth) + if (cx+left > scrwidth) break; - if (cx + w < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w; continue; @@ -1653,7 +1675,7 @@ void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *st void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) { fixed_t cx = x, cy = y; - INT32 w, c, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0; + INT32 w, c, dupx, dupy, scrwidth, center = 0, left = 0; const char *ch = string; INT32 spacewidth = 4, charwidth = 0; @@ -1667,7 +1689,11 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) scrwidth = vid.width; } else + { dupx = dupy = 1; + scrwidth = vid.width/vid.dupx; + left = (scrwidth - BASEVIDWIDTH)/2; + } switch (option & V_SPACINGMASK) { @@ -1720,9 +1746,9 @@ void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string) else w = SHORT(hu_font[c]->width) * dupx; - if ((cx>>FRACBITS) + w > scrwidth) + if ((cx>>FRACBITS)+left > scrwidth) break; - if (cx < 0) //left boundary check + if (cx+left + w < 0) //left boundary check { cx += w< Date: Tue, 22 Aug 2017 21:12:02 +0100 Subject: [PATCH 44/61] woops lmao --- src/v_video.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index d965a0939..9858e118f 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -525,19 +525,20 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix return *(v_translevel + (((*(v_colormap + source[ofs>>FRACBITS]))<<8)&0xff00) + (*dest&0xff)); } -static UINT8 staticstep[2] = {0, 0}; +static UINT8 staticstep = 0; +static fixed_t staticval = 0; static inline UINT8 staticpdraw(const UINT8 *dest, const UINT8 *source, fixed_t ofs) { UINT8 val = source[ofs>>FRACBITS]; (void)dest; - if ((++staticstep[1]) >= 4) + if ((++staticstep) >= 4) { - staticstep[1] = 0; - staticstep[0] = M_RandomFixed(); + staticstep = 0; + staticval = M_RandomFixed(); } if (val < 7) return val; - return ((staticstep[0]>>staticstep[1])&7)+(val-7); + return ((staticval>>staticstep)&7)+(val-7); } // Draws a patch scaled to arbitrary size. From 673fbc3ec275c87caced266880c2d46a3a6fd514 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Tue, 22 Aug 2017 23:47:25 +0100 Subject: [PATCH 45/61] * Make the delete save message include the save number. * Update/improve ultimate mode interaction experience a little. https://cdn.discordapp.com/attachments/293238104096112641/349685399200727041/srb20027.png --- src/m_cheat.c | 2 +- src/m_menu.c | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index f988c0fd5..7650e0742 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -61,7 +61,7 @@ static UINT8 cheatf_ultimate(void) if (menuactive && (currentMenu != &MainDef && currentMenu != &SP_LoadDef)) return 0; // Only on the main menu, or the save select! - S_StartSound(0, sfx_itemup); + BwehHehHe(); ultimate_selectable = (!ultimate_selectable); // If on the save select, move to what is now Ultimate Mode! diff --git a/src/m_menu.c b/src/m_menu.c index 214755651..c338a6185 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6514,6 +6514,17 @@ static void M_SaveGameDeleteResponse(INT32 ch) M_ReadSaveStrings(); // reload the menu } +static void M_SaveGameUltimateResponse(INT32 ch) +{ + if (ch != 'y' && ch != KEY_ENTER) + return; + + S_StartSound(NULL, sfx_menu1); + M_LoadSelect(saveSlotSelected); + SP_PlayerDef.prevMenu = MessageDef.prevMenu; + MessageDef.prevMenu = &SP_PlayerDef; +} + static void M_HandleLoadSave(INT32 choice) { boolean exitmenu = false; // exit to previous menu @@ -6537,8 +6548,15 @@ static void M_HandleLoadSave(INT32 choice) break; case KEY_ENTER: - if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + if (ultimate_selectable && saveSlotSelected == NOSAVESLOT) { + loadgamescroll = 0; + S_StartSound(NULL, sfx_skid); + M_StartMessage("Are you sure you want to play\n\x85ultimate mode\x80? It isn't remotely fair,\nand you don't even get an emblem for it.\n\n(Press 'Y' to confirm)\n",M_SaveGameUltimateResponse,MM_YESNO); + } + else if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + { + loadgamescroll = 0; S_StartSound(NULL, sfx_menu1); M_LoadSelect(saveSlotSelected); } @@ -6560,14 +6578,14 @@ static void M_HandleLoadSave(INT32 choice) { loadgamescroll = 0; S_StartSound(NULL, sfx_skid); - M_StartMessage(M_GetText("Are you sure you want to delete\nthis save game?\n\n(Press 'Y' to confirm)\n"),M_SaveGameDeleteResponse,MM_YESNO); + M_StartMessage(va("Are you sure you want to delete\nsave file %d?\n\n(Press 'Y' to confirm)\n", saveSlotSelected),M_SaveGameDeleteResponse,MM_YESNO); } else if (!loadgameoffset) { if (saveSlotSelected == NOSAVESLOT && ultimate_selectable) { ultimate_selectable = false; - BwehHehHe(); + S_StartSound(NULL, sfx_strpst); } else S_StartSound(NULL, sfx_lose); @@ -6602,14 +6620,15 @@ static void M_LoadGame(INT32 choice) // void M_ForceSaveSlotSelected(INT32 sslot) { - // Already there? Out of bounds? Whatever, then! - if (sslot == saveSlotSelected || sslot >= MAXSAVEGAMES) + loadgameoffset = 14; + + // Already there? Whatever, then! + if (sslot == saveSlotSelected) return; - // Figure out whether to display up movement or down movement - /*menumovedir = (saveSlotSelected - sslot) > 0 ? -1 : 1; - if (abs(saveSlotSelected - sslot) > (MAXSAVEGAMES>>1)) - menumovedir *= -1;*/ + loadgamescroll = 90; + if (saveSlotSelected <= numsaves/2) + loadgamescroll = -loadgamescroll; saveSlotSelected = sslot; } From a81c3ca115b6cbc2158caed6d98d27616057804c Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 23 Aug 2017 17:41:16 +0100 Subject: [PATCH 46/61] Update V_DrawCroppedPatch to match V_DrawFixedPatch's fixes. --- src/v_video.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index 9858e118f..b0d8fc52b 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -808,28 +808,10 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ y = FixedMul(y,dupy<>= FRACBITS; y >>= FRACBITS; - desttop += (y*vid.width) + x; // Center it if necessary if (!(scrn & V_SCALEPATCHMASK)) { - if (vid.width != BASEVIDWIDTH * dupx) - { - // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, - // so center this imaginary screen - if (scrn & V_SNAPTORIGHT) - desttop += (vid.width - (BASEVIDWIDTH * dupx)); - else if (!(scrn & V_SNAPTOLEFT)) - desttop += (vid.width - (BASEVIDWIDTH * dupx)) / 2; - } - if (vid.height != BASEVIDHEIGHT * dupy) - { - // same thing here - if (scrn & V_SNAPTOBOTTOM) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width; - else if (!(scrn & V_SNAPTOTOP)) - desttop += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2; - } // if it's meant to cover the whole screen, black out the rest if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) { @@ -837,7 +819,29 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ source = (const UINT8 *)(column) + 3; V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } + + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (scrn & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(scrn & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if ((scrn & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) + y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); + else if (scrn & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(scrn & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } } + + desttop += (y*vid.width) + x; } for (col = sx<>FRACBITS) < SHORT(patch->width) && (col>>FRACBITS) < w; col += colfrac, ++x, desttop++) From 00c62e6d882d553ce724eef045e0a3fe2f8602a9 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 23 Aug 2017 22:05:11 +0100 Subject: [PATCH 47/61] * Removed unused info from struct as part of clean up. * Made botskin being invalid make the entire save invalid. --- src/m_menu.c | 22 ++++++++++++++-------- src/m_menu.h | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index c338a6185..06c235b97 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6079,6 +6079,18 @@ static void M_DrawLoadGameData(void) { V_DrawSmallScaledPatch(x+2, y+64, 0, savselp[5]); } +#ifndef PERFECTSAVE // disabled, don't touch + else if ((savegameinfo[savetodraw].skinnum == 1) + && (savegameinfo[savetodraw].lives == 99) + && (savegameinfo[savetodraw].gamemap & 8192) + && (savegameinfo[savetodraw].numgameovers == 0) + && (savegameinfo[savetodraw].numemeralds == (1<<7 - 1)) // perfect save + { + V_DrawFill(x+6, y+64, 72, 50, 134); + V_DrawFill(x+6, y+74, 72, 30, 201); + V_DrawFill(x+6, y+84, 72, 10, 1); + } +#endif else { if (savegameinfo[savetodraw].lives == -42) @@ -6360,15 +6372,9 @@ static void M_ReadSavegameInfo(UINT32 slot) if (((fake-1) & 8191) >= NUMMAPS) BADSAVE if(!mapheaderinfo[(fake-1) & 8191]) - { savegameinfo[slot].levelname[0] = '\0'; - savegameinfo[slot].actnum = 0; - } else - { strcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl); - savegameinfo[slot].actnum = mapheaderinfo[(fake-1) & 8191]->actnum; - } savegameinfo[slot].gamemap = fake; @@ -6390,10 +6396,10 @@ static void M_ReadSavegameInfo(UINT32 slot) savegameinfo[slot].botskin = fake >> 5; if (savegameinfo[slot].botskin-1 >= numskins || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) - savegameinfo[slot].botskin = 0; + BADSAVE CHECKPOS - (void)READUINT8(save_p); // numgameovers + savegameinfo[slot].numgameovers = READUINT8(save_p); // numgameovers CHECKPOS savegameinfo[slot].lives = READSINT8(save_p); // lives CHECKPOS diff --git a/src/m_menu.h b/src/m_menu.h index 6646aa4af..8040b63e6 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -216,10 +216,10 @@ typedef struct typedef struct { char levelname[32]; - UINT8 actnum; UINT8 skinnum; UINT8 botskin; UINT8 numemeralds; + UINT8 numgameovers; INT32 lives; INT32 continues; INT32 gamemap; From 16395f4dd2be44bbff79f10aa42530efabfc02e7 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 24 Aug 2017 21:29:29 +0100 Subject: [PATCH 48/61] Final corrections. Branch should be ready to merge now. --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 06c235b97..3f0b981e6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6084,7 +6084,7 @@ static void M_DrawLoadGameData(void) && (savegameinfo[savetodraw].lives == 99) && (savegameinfo[savetodraw].gamemap & 8192) && (savegameinfo[savetodraw].numgameovers == 0) - && (savegameinfo[savetodraw].numemeralds == (1<<7 - 1)) // perfect save + && (savegameinfo[savetodraw].numemeralds == ((1<<7) - 1))) // perfect save { V_DrawFill(x+6, y+64, 72, 50, 134); V_DrawFill(x+6, y+74, 72, 30, 201); From 9641196374b9b0a0724a7e1e3b83dc8e52d5a170 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 25 Aug 2017 00:40:45 +0100 Subject: [PATCH 49/61] * Fixed bug with wide blank select pic being used instead of the normal one. * Added length cap to savegame's zone name. * Refactor to level select's zone name length cap code. --- src/m_menu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 3f0b981e6..a158cd955 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4063,10 +4063,10 @@ static boolean M_PrepareLevelPlatter(INT32 gt) if (actnum) sprintf(mapname, "%s %d", mapheaderinfo[mapnum]->lvlttl, actnum); else - sprintf(mapname, "%s", mapheaderinfo[mapnum]->lvlttl); + strcpy(mapname, mapheaderinfo[mapnum]->lvlttl); if (strlen(mapname) >= 17) - sprintf(mapname+17-3, "..."); + strcpy(mapname+17-3, "..."); strcpy(levelselect.rows[row].mapnames[col], (const char *)mapname); } @@ -6374,7 +6374,12 @@ static void M_ReadSavegameInfo(UINT32 slot) if(!mapheaderinfo[(fake-1) & 8191]) savegameinfo[slot].levelname[0] = '\0'; else - strcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl); + { + strlcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl, 17+1); + + if (strlen(mapheaderinfo[(fake-1) & 8191]->lvlttl) >= 17) + strcpy(savegameinfo[slot].levelname+17-3, "..."); + } savegameinfo[slot].gamemap = fake; @@ -6497,7 +6502,7 @@ static void M_ReadSaveStrings(void) savselp[3] = W_CachePatchName("BLACKLVL", PU_STATIC); savselp[4] = W_CachePatchName("BLACXLVL", PU_STATIC); - savselp[5] = W_CachePatchName("BLANKLVW", PU_STATIC); + savselp[5] = W_CachePatchName("BLANKLVL", PU_STATIC); savselp[6] = W_CachePatchName("GAMEDONE", PU_STATIC); } From 4da6169892eabdaa5b3b69410fe142d057da7165 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 25 Aug 2017 18:00:20 +0100 Subject: [PATCH 50/61] Add spr2defaults[] array to make sprite2 defaulting system much, much simpler to manage. This is in preparation for a seperate project which still involves sprite2s. --- src/dehacked.c | 80 +++++++++++++++++++++++++-- src/info.c | 83 +++++++++++++++++++++++++++- src/info.h | 7 ++- src/lua_baselib.c | 2 + src/lua_infolib.c | 81 +++++++++++++++++++++++++++ src/r_things.c | 136 +++------------------------------------------- 6 files changed, 251 insertions(+), 138 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 719476543..cdfbc5e22 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -64,6 +64,7 @@ memset(used_spr,0,sizeof(UINT8) * ((NUMSPRITEFREESLOTS / 8) + 1));\ static mobjtype_t get_mobjtype(const char *word); static statenum_t get_state(const char *word); static spritenum_t get_sprite(const char *word); +static playersprite_t get_sprite2(const char *word); static sfxenum_t get_sfx(const char *word); #ifdef MUSICSLOT_COMPATIBILITY static UINT16 get_mus(const char *word, UINT8 dehacked_mode); @@ -769,6 +770,49 @@ static void readspritelight(MYFILE *f, INT32 num) } #endif // HWRENDER +static void readsprite2(MYFILE *f, INT32 num) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word, *word2; + char *tmp; + + do + { + if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + word = strtok(s, " "); + if (word) + strupr(word); + else + break; + + word2 = strtok(NULL, " = "); + if (word2) + strupr(word2); + else + break; + if (word2[strlen(word2)-1] == '\n') + word2[strlen(word2)-1] = '\0'; + + if (fastcmp(word, "DEFAULT")) + spr2defaults[num] = get_number(word2); + else + deh_warning("Sprite2 %s: unknown word '%s'", spr2names[num], word); + } + } while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + static const struct { const char *name; const UINT16 flag; @@ -3020,9 +3064,21 @@ static void DEH_LoadDehackedFile(MYFILE *f) ignorelines(f); } } + else if (fastcmp(word, "SPRITE2")) + { + if (i == 0 && word2[0] != '0') // If word2 isn't a number + i = get_sprite2(word2); // find a sprite by name + if (i < (INT32)free_spr2 && i >= (INT32)SPR2_FIRSTFREESLOT) + readsprite2(f, i); + else + { + deh_warning("Sprite2 number %d out of range (%d - %d)", i, SPR2_FIRSTFREESLOT, free_spr2-1); + ignorelines(f); + } + } +#ifdef HWRENDER else if (fastcmp(word, "LIGHT")) { -#ifdef HWRENDER // TODO: Read lights by name if (i > 0 && i < NUMLIGHTS) readlight(f, i); @@ -3031,22 +3087,20 @@ static void DEH_LoadDehackedFile(MYFILE *f) deh_warning("Light number %d out of range (1 - %d)", i, NUMLIGHTS-1); ignorelines(f); } -#endif } else if (fastcmp(word, "SPRITE")) { -#ifdef HWRENDER if (i == 0 && word2[0] != '0') // If word2 isn't a number i = get_sprite(word2); // find a sprite by name - if (i < NUMSPRITES && i >= 0) + if (i < NUMSPRITES && i > 0) readspritelight(f, i); else { deh_warning("Sprite number %d out of range (0 - %d)", i, NUMSPRITES-1); ignorelines(f); } -#endif } +#endif else if (fastcmp(word, "LEVEL")) { // Support using the actual map name, @@ -7290,6 +7344,20 @@ static spritenum_t get_sprite(const char *word) return SPR_NULL; } +static playersprite_t get_sprite2(const char *word) +{ // Returns the value of SPR2_ enumerations + playersprite_t i; + if (*word >= '0' && *word <= '9') + return atoi(word); + if (fastncmp("SPR2_",word,5)) + word += 5; // take off the SPR2_ + for (i = 0; i < NUMPLAYERSPRITES; i++) + if (!spr2names[i][4] && memcmp(word,spr2names[i],4)==0) + return i; + deh_warning("Couldn't find sprite named 'SPR2_%s'",word); + return SPR2_STND; +} + static sfxenum_t get_sfx(const char *word) { // Returns the value of SFX_ enumerations sfxenum_t i; @@ -7735,7 +7803,7 @@ static inline int lib_freeslot(lua_State *L) else if (fastcmp(type, "SPR2")) { // Search if we already have an SPR2 by that name... - enum playersprite i; + playersprite_t i; for (i = SPR2_FIRSTFREESLOT; i < free_spr2; i++) if (memcmp(spr2names[i],word,4) == 0) break; diff --git a/src/info.c b/src/info.c index 2d6c9a3d1..dc774bb9c 100644 --- a/src/info.c +++ b/src/info.c @@ -481,7 +481,88 @@ char spr2names[NUMPLAYERSPRITES][5] = "SIGN", "LIFE" }; -enum playersprite free_spr2 = SPR2_FIRSTFREESLOT; +playersprite_t free_spr2 = SPR2_FIRSTFREESLOT; + +playersprite_t spr2defaults[NUMPLAYERSPRITES] = { + 0, // SPR2_STND, + 0, // SPR2_WAIT, + 0, // SPR2_WALK, + SPR2_WALK, // SPR2_RUN , + SPR2_FRUN, // SPR2_DASH, + 0, // SPR2_PAIN, + SPR2_PAIN, // SPR2_STUN, + 0, // SPR2_DEAD, + SPR2_DEAD, // SPR2_DRWN, + 0, // SPR2_ROLL, + SPR2_SPNG, // SPR2_GASP, + 0, // SPR2_JUMP, (conditional) + SPR2_FALL, // SPR2_SPNG, + SPR2_WALK, // SPR2_FALL, + 0, // SPR2_EDGE, + SPR2_FALL, // SPR2_RIDE, + + SPR2_ROLL, // SPR2_SPIN, + + SPR2_SPNG, // SPR2_FLY , + SPR2_FLY , // SPR2_SWIM, + 0, // SPR2_TIRE, (conditional) + + SPR2_FLY , // SPR2_GLID, + SPR2_CLMB, // SPR2_CLNG, + SPR2_ROLL, // SPR2_CLMB, + + SPR2_WALK, // SPR2_FLT , + SPR2_RUN , // SPR2_FRUN, + + SPR2_FALL, // SPR2_BNCE, + SPR2_ROLL, // SPR2_BLND, + + 0, // SPR2_FIRE, + + SPR2_ROLL, // SPR2_TWIN, + + SPR2_TWIN, // SPR2_MLEE, + 0, // SPR2_MLEL, + + 0, // SPR2_TRNS, + + 0, // SPR2_NSTD, + 0, // SPR2_NFLT, + 0, // SPR2_NSTN, + SPR2_NSTN, // SPR2_NPUL, + 0, // SPR2_NATK, + + 0, // SPR2_NGT0, (should never be referenced) + SPR2_NGT0, // SPR2_NGT1, + SPR2_NGT1, // SPR2_NGT2, + SPR2_NGT2, // SPR2_NGT3, + SPR2_NGT3, // SPR2_NGT4, + SPR2_NGT4, // SPR2_NGT5, + SPR2_NGT5, // SPR2_NGT6, + SPR2_NGT0, // SPR2_NGT7, + SPR2_NGT7, // SPR2_NGT8, + SPR2_NGT8, // SPR2_NGT9, + SPR2_NGT9, // SPR2_NGTA, + SPR2_NGTA, // SPR2_NGTB, + SPR2_NGTB, // SPR2_NGTC, + + SPR2_NGT0, // SPR2_DRL0, + SPR2_NGT1, // SPR2_DRL1, + SPR2_NGT2, // SPR2_DRL2, + SPR2_NGT3, // SPR2_DRL3, + SPR2_NGT4, // SPR2_DRL4, + SPR2_NGT5, // SPR2_DRL5, + SPR2_NGT6, // SPR2_DRL6, + SPR2_NGT7, // SPR2_DRL7, + SPR2_NGT8, // SPR2_DRL8, + SPR2_NGT9, // SPR2_DRL9, + SPR2_NGTA, // SPR2_DRLA, + SPR2_NGTB, // SPR2_DRLB, + SPR2_NGTC, // SPR2_DRLC, + + 0, // SPR2_SIGN, + 0, // SPR2_LIFE +}; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) state_t states[NUMSTATES] = diff --git a/src/info.h b/src/info.h index cd79b12a9..4ae5fcf63 100644 --- a/src/info.h +++ b/src/info.h @@ -604,7 +604,7 @@ typedef enum sprite // Make sure to be conscious of FF_FRAMEMASK and the fact sprite2 is stored as a UINT8 whenever you change this table. // Currently, FF_FRAMEMASK is 0xff, or 255 - but the second half is used by FF_SPR2SUPER, so the limitation is 0x7f. // Since this is zero-based, there can be at most 128 different SPR2_'s without changing that. -enum playersprite +typedef enum playersprite { SPR2_STND = 0, SPR2_WAIT, @@ -690,7 +690,7 @@ enum playersprite SPR2_FIRSTFREESLOT, SPR2_LASTFREESLOT = 0x7f, NUMPLAYERSPRITES -}; +} playersprite_t; typedef enum state { @@ -3193,8 +3193,9 @@ typedef struct extern state_t states[NUMSTATES]; extern char sprnames[NUMSPRITES + 1][5]; extern char spr2names[NUMPLAYERSPRITES][5]; +extern playersprite_t spr2defaults[NUMPLAYERSPRITES]; extern state_t *astate; -extern enum playersprite free_spr2; +extern playersprite_t free_spr2; typedef enum mobj_type { diff --git a/src/lua_baselib.c b/src/lua_baselib.c index be1455415..b88a9712e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -462,6 +462,8 @@ static int lib_pSpawnLockOn(lua_State *L) return LUA_ErrInvalid(L, "mobj_t"); if (!player) return LUA_ErrInvalid(L, "player_t"); + if (state >= NUMSTATES) + return luaL_error(L, "state %d out of range (0 - %d)", state, NUMSTATES-1); if (P_IsLocalPlayer(player)) // Only display it on your own view. { mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 9361abe94..c3803f7e2 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -127,6 +127,74 @@ static int lib_getSpr2name(lua_State *L) return 0; } +static int lib_getSpr2default(lua_State *L) +{ + UINT32 i; + + lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata. + + if (lua_isnumber(L, 1)) + i = lua_tonumber(L, 1); + else if (lua_isstring(L, 1)) + { + const char *name = lua_tostring(L, 1); + for (i = 0; i < free_spr2; i++) + if (fastcmp(name, spr2names[i])) + break; + } + else + return luaL_error(L, "spr2defaults[] invalid index"); + + if (i >= free_spr2) + return 0; + + lua_pushinteger(L, spr2defaults[i]); + return 1; +} + +static int lib_setSpr2default(lua_State *L) +{ + UINT32 i; + UINT8 j = 0; + + lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata. + + if (lua_isnumber(L, 1)) + i = lua_tonumber(L, 1); + else if (lua_isstring(L, 1)) + { + const char *name = lua_tostring(L, 1); + for (i = 0; i < free_spr2; i++) + if (fastcmp(name, spr2names[i])) + break; + if (i == free_spr2) + return luaL_error(L, "spr2defaults[] invalid index"); + } + else + return luaL_error(L, "spr2defaults[] invalid index"); + + if (i < SPR2_FIRSTFREESLOT || i >= free_spr2) + return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, SPR2_FIRSTFREESLOT, free_spr2-1); + + if (lua_isnumber(L, 2)) + j = lua_tonumber(L, 2); + else if (lua_isstring(L, 2)) + { + const char *name = lua_tostring(L, 2); + for (j = 0; j < free_spr2; j++) + if (fastcmp(name, spr2names[j])) + break; + if (j == free_spr2) + return luaL_error(L, "spr2defaults[] invalid index"); + } + + if (j >= free_spr2) + j = 0; // return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1); + + spr2defaults[i] = j; + return 0; +} + static int lib_spr2namelen(lua_State *L) { lua_pushinteger(L, free_spr2); @@ -984,6 +1052,19 @@ int LUA_InfoLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "spr2names"); + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, lib_getSpr2default); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_setSpr2default); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, lib_spr2namelen); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "spr2defaults"); + lua_newuserdata(L, 0); lua_createtable(L, 0, 2); lua_pushcfunction(L, lib_getState); diff --git a/src/r_things.c b/src/r_things.c index b2437d4ac..ebec4a14a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2431,13 +2431,14 @@ CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) { - UINT8 super = (spr2 & FF_SPR2SUPER); + UINT8 super = (spr2 & FF_SPR2SUPER), i = 0; if (!skin) return 0; while (!(skin->sprites[spr2].numframes) - && spr2 != SPR2_STND) + && spr2 != SPR2_STND + && ++i != 32) // recursion limiter { if (spr2 & FF_SPR2SUPER) { @@ -2447,83 +2448,18 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) switch(spr2) { - case SPR2_RUN: - spr2 = SPR2_WALK; - break; - case SPR2_STUN: - spr2 = SPR2_PAIN; - break; - case SPR2_DRWN: - spr2 = SPR2_DEAD; - break; - case SPR2_SPIN: - spr2 = SPR2_ROLL; - break; - case SPR2_GASP: - spr2 = SPR2_SPNG; - break; + + // Normal special cases. case SPR2_JUMP: spr2 = ((player ? player->charflags : skin->flags) & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; break; - case SPR2_SPNG: // spring - spr2 = SPR2_FALL; - break; - case SPR2_FALL: - spr2 = SPR2_WALK; - break; - case SPR2_RIDE: - spr2 = SPR2_FALL; - break; - - case SPR2_FLY : - spr2 = SPR2_SPNG; - break; - case SPR2_SWIM: - spr2 = SPR2_FLY ; - break; case SPR2_TIRE: spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; break; - case SPR2_GLID: - spr2 = SPR2_FLY; - break; - case SPR2_CLMB: - spr2 = SPR2_ROLL; - break; - case SPR2_CLNG: - spr2 = SPR2_CLMB; - break; - - case SPR2_FLT : - spr2 = SPR2_WALK; - break; - case SPR2_FRUN: - spr2 = SPR2_RUN ; - break; - - case SPR2_DASH: - spr2 = SPR2_FRUN; - break; - - case SPR2_BNCE: - spr2 = SPR2_FALL; - break; - case SPR2_BLND: - spr2 = SPR2_ROLL; - break; - - case SPR2_TWIN: - spr2 = SPR2_ROLL; - break; - - case SPR2_MLEE: - spr2 = SPR2_TWIN; - break; - // NiGHTS sprites. case SPR2_NSTD: spr2 = SPR2_STND; @@ -2535,72 +2471,16 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) break; case SPR2_NSTN: spr2 = SPR2_STUN; - break; - case SPR2_NPUL: - spr2 = SPR2_NSTN; + super = FF_SPR2SUPER; break; case SPR2_NATK: spr2 = SPR2_ROLL; super = FF_SPR2SUPER; break; - /*case SPR2_NGT0: - spr2 = SPR2_NFLT; - break;*/ - case SPR2_NGT1: - case SPR2_NGT7: - case SPR2_DRL0: - spr2 = SPR2_NGT0; - break; - case SPR2_NGT2: - case SPR2_DRL1: - spr2 = SPR2_NGT1; - break; - case SPR2_NGT3: - case SPR2_DRL2: - spr2 = SPR2_NGT2; - break; - case SPR2_NGT4: - case SPR2_DRL3: - spr2 = SPR2_NGT3; - break; - case SPR2_NGT5: - case SPR2_DRL4: - spr2 = SPR2_NGT4; - break; - case SPR2_NGT6: - case SPR2_DRL5: - spr2 = SPR2_NGT5; - break; - case SPR2_DRL6: - spr2 = SPR2_NGT6; - break; - case SPR2_NGT8: - case SPR2_DRL7: - spr2 = SPR2_NGT7; - break; - case SPR2_NGT9: - case SPR2_DRL8: - spr2 = SPR2_NGT8; - break; - case SPR2_NGTA: - case SPR2_DRL9: - spr2 = SPR2_NGT9; - break; - case SPR2_NGTB: - case SPR2_DRLA: - spr2 = SPR2_NGTA; - break; - case SPR2_NGTC: - case SPR2_DRLB: - spr2 = SPR2_NGTB; - break; - case SPR2_DRLC: - spr2 = SPR2_NGTC; - break; - // Dunno? Just go to standing then. + // Use the handy list, that's what it's there for! default: - spr2 = SPR2_STND; + spr2 = spr2defaults[spr2]; break; } From 76300026f823291ac1d5f1457c7a8c739d4373a1 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 26 Aug 2017 18:56:23 +0100 Subject: [PATCH 51/61] * Added support for sprite2s to MD2s! - Name each frame either SPR2_**** or SUPER**** (where **** is the 4-character name) - If the name is 3 characters, '.' is accepted as a substitute for the '_', but a space/absent isn't (for tool-related reasons). - Adds a big sprite2 index array to all models, even non-player ones. Sorry! * Made MD2 frame interpoleration only work across the same spriteset (and sprite2set). * Made MD2 frame interpoleration happen when there's less than a quarter of a second between frames, as opposed to the hardcoded specific animation disabling. * Fixed sprite2-related typo in dehacked.c. --- src/dehacked.c | 2 +- src/hardware/hw_md2.c | 141 ++++++++++++++++++++++++++++++++++++------ src/hardware/hw_md2.h | 4 +- src/info.c | 8 +-- src/r_things.c | 21 +------ 5 files changed, 133 insertions(+), 43 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index cdfbc5e22..385411748 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7982,7 +7982,7 @@ static inline int lib_getenum(lua_State *L) if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word); return 0; } - else if (fastncmp("SPR2_",word,4)) { + else if (fastncmp("SPR2_",word,5)) { p = word+5; for (i = 0; i < (fixed_t)free_spr2; i++) if (!spr2names[i][4]) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index df2c9f59a..14879b2b7 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -28,6 +28,7 @@ #include "../doomdef.h" #include "../doomstat.h" +#include "../fastcmp.h" #ifdef HWRENDER #include "hw_drv.h" @@ -395,6 +396,29 @@ static md2_model_t *md2_readModel(const char *filename) } strcpy(model->frames[i].name, frame->name); + if (frame->name[0] == 'S') + { + boolean super; + if ((super = (fastncmp("UPER", frame->name+1, 4))) // SUPER + || fastncmp("PR2_", frame->name+1, 4)) // SPR2_ + { + UINT8 spr2; + for (spr2 = 0; spr2 < free_spr2; spr2++) + if (fastncmp(frame->name+5,spr2names[spr2],3) + && ((frame->name[8] == spr2names[spr2][3]) + || (frame->name[8] == '.' && spr2names[spr2][3] == '_'))) + break; + + if (spr2 < free_spr2) + { + if (super) + spr2 |= FF_SPR2SUPER; + if (model->spr2frames[spr2][1]++ == 0) // numspr2frames + model->spr2frames[spr2][0] = i; // starting frame + CONS_Debug(DBG_RENDER, "frame %s, sprite2 %s - starting frame %d, number of frames %d\n", frame->name, spr2names[spr2 & ~FF_SPR2SUPER], model->spr2frames[spr2][0], model->spr2frames[spr2][1]); + } + } + } for (j = 0; j < model->header.numVertices; j++) { model->frames[i].vertices[j].vertex[0] = (float) ((INT32) frame->alias_vertices[j].vertex[0]) * frame->scale[0] + frame->translate[0]; @@ -1078,6 +1102,51 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, con res? run? */ + +static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *player) +{ + UINT8 super = 0, i = 0; + + if (!md2 || !skin) + return 0; + + while (!(md2->model->spr2frames[spr2][1]) + && spr2 != SPR2_STND + && ++i != 32) // recursion limiter + { + if (spr2 & FF_SPR2SUPER) + { + super = FF_SPR2SUPER; + spr2 &= ~FF_SPR2SUPER; + continue; + } + + switch(spr2) + { + + // Normal special cases. + case SPR2_JUMP: + spr2 = ((player + ? player->charflags + : skin->flags) + & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; + break; + case SPR2_TIRE: + spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; + break; + + // Use the handy list, that's what it's there for! + default: + spr2 = spr2defaults[spr2]; + break; + } + + spr2 |= super; + } + + return spr2; +} + #define NORMALFOG 0x00000000 #define FADEFOG 0x19000000 void HWR_DrawMD2(gr_vissprite_t *spr) @@ -1225,31 +1294,67 @@ void HWR_DrawMD2(gr_vissprite_t *spr) tics = spr->mobj->anim_duration; } - //FIXME: this is not yet correct - frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->header.numFrames; - buff = md2->model->glCommandBuffer; - curr = &md2->model->frames[frame]; - if (cv_grmd2.value == 1) +#define INTERPOLERATION_LIMIT TICRATE/4 + + if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) { - // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation - if (spr->mobj->frame & FF_ANIMATE) + UINT8 spr2 = P_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); + UINT8 mod = md2->model->spr2frames[spr2][1] ? md2->model->spr2frames[spr2][1] : md2->model->header.numFrames; + //FIXME: this is not yet correct + frame = md2->model->spr2frames[spr2][0] + ((spr->mobj->frame & FF_FRAMEMASK) % mod); + buff = md2->model->glCommandBuffer; + curr = &md2->model->frames[frame]; + if (cv_grmd2.value == 1 && tics <= INTERPOLERATION_LIMIT) { - UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; - if (nextframe >= (UINT32)spr->mobj->state->var1) - nextframe = (spr->mobj->state->frame & FF_FRAMEMASK); - nextframe %= md2->model->header.numFrames; - next = &md2->model->frames[nextframe]; - } - else - { - if (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL - && !(spr->mobj->player && spr->mobj->state->nextstate == S_PLAY_WAIT && spr->mobj->state == &states[S_PLAY_STND])) + if (durs > INTERPOLERATION_LIMIT) + durs = INTERPOLERATION_LIMIT; + + if (spr->mobj->frame & FF_ANIMATE + || (spr->mobj->state->nextstate != S_NULL + && states[spr->mobj->state->nextstate].sprite == spr->mobj->sprite + && (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) == spr->mobj->sprite2)) { - const UINT32 nextframe = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->header.numFrames; + UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; + if (nextframe >= (UINT32)((skin_t*)spr->mobj->skin)->sprites[spr->mobj->sprite2].numframes) + nextframe = 0; + nextframe = md2->model->spr2frames[spr2][0] + (nextframe % md2->model->spr2frames[spr2][1]); next = &md2->model->frames[nextframe]; } } } + else + { + //FIXME: this is not yet correct + frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->header.numFrames; + buff = md2->model->glCommandBuffer; + curr = &md2->model->frames[frame]; + if (cv_grmd2.value == 1 && tics <= INTERPOLERATION_LIMIT) + { + if (durs > INTERPOLERATION_LIMIT) + durs = INTERPOLERATION_LIMIT; + + // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation + if (spr->mobj->frame & FF_ANIMATE) + { + UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; + if (nextframe >= (UINT32)spr->mobj->state->var1) + nextframe = (spr->mobj->state->frame & FF_FRAMEMASK); + nextframe %= md2->model->header.numFrames; + next = &md2->model->frames[nextframe]; + } + else + { + if (spr->mobj->state->nextstate != S_NULL + && states[spr->mobj->state->nextstate].sprite == spr->mobj->sprite) + { + const UINT32 nextframe = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->header.numFrames; + next = &md2->model->frames[nextframe]; + } + } + } + } + +#undef INTERPOLERATION_LIMIT //Hurdler: it seems there is still a small problem with mobj angle p.x = FIXED_TO_FLOAT(spr->mobj->x); diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 299d12400..b183e4367 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -22,6 +22,7 @@ #define _HW_MD2_H_ #include "hw_glob.h" +#include "../info.h" // magic number "IDP2" or 844121161 #define MD2_IDENT (INT32)(('2' << 24) + ('P' << 16) + ('D' << 8) + 'I') @@ -111,7 +112,8 @@ typedef struct md2_textureCoordinate_t *texCoords; md2_triangle_t *triangles; md2_frame_t *frames; - INT32 *glCommandBuffer; + size_t spr2frames[2*NUMPLAYERSPRITES][2]; + INT32 *glCommandBuffer; } ATTRPACK md2_model_t; #if defined(_MSC_VER) diff --git a/src/info.c b/src/info.c index dc774bb9c..c8bea7803 100644 --- a/src/info.c +++ b/src/info.c @@ -526,11 +526,11 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { 0, // SPR2_TRNS, - 0, // SPR2_NSTD, - 0, // SPR2_NFLT, - 0, // SPR2_NSTN, + FF_SPR2SUPER|SPR2_STND, // SPR2_NSTD, + FF_SPR2SUPER|SPR2_FLT , // SPR2_NFLT, + FF_SPR2SUPER|SPR2_STUN, // SPR2_NSTN, SPR2_NSTN, // SPR2_NPUL, - 0, // SPR2_NATK, + FF_SPR2SUPER|SPR2_ROLL, // SPR2_NATK, 0, // SPR2_NGT0, (should never be referenced) SPR2_NGT0, // SPR2_NGT1, diff --git a/src/r_things.c b/src/r_things.c index ebec4a14a..67aa4e585 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2431,7 +2431,7 @@ CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) { - UINT8 super = (spr2 & FF_SPR2SUPER), i = 0; + UINT8 super = 0, i = 0; if (!skin) return 0; @@ -2442,6 +2442,7 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) { if (spr2 & FF_SPR2SUPER) { + super = FF_SPR2SUPER; spr2 &= ~FF_SPR2SUPER; continue; } @@ -2460,24 +2461,6 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; break; - // NiGHTS sprites. - case SPR2_NSTD: - spr2 = SPR2_STND; - super = FF_SPR2SUPER; - break; - case SPR2_NFLT: - spr2 = SPR2_FLT ; - super = FF_SPR2SUPER; - break; - case SPR2_NSTN: - spr2 = SPR2_STUN; - super = FF_SPR2SUPER; - break; - case SPR2_NATK: - spr2 = SPR2_ROLL; - super = FF_SPR2SUPER; - break; - // Use the handy list, that's what it's there for! default: spr2 = spr2defaults[spr2]; From 973f700dcf27dfa769e613de52e1d2fae74e7968 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 27 Aug 2017 14:56:07 +0100 Subject: [PATCH 52/61] * Make the model->spr2frames dynamically allocated. (There's only two settings - on and off - but that's better than it perpetually being on...) * Fix up defaulting for DEAD to go to PAIN. --- src/hardware/hw_md2.c | 29 +++++++++++++++++++++-------- src/hardware/hw_md2.h | 2 +- src/info.c | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 14879b2b7..967dfa03f 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -266,6 +266,9 @@ static void md2_freeModel (md2_model_t *model) free(model->frames); } + if (model->spr2frames) + free(model->spr2frames); + if (model->glCommandBuffer) free(model->glCommandBuffer); @@ -411,11 +414,21 @@ static md2_model_t *md2_readModel(const char *filename) if (spr2 < free_spr2) { + if (!model->spr2frames) + { + model->spr2frames = calloc(sizeof (size_t), 2*NUMPLAYERSPRITES*2); + if (!model->spr2frames) + { + md2_freeModel (model); + fclose(file); + return 0; + } + } if (super) spr2 |= FF_SPR2SUPER; - if (model->spr2frames[spr2][1]++ == 0) // numspr2frames - model->spr2frames[spr2][0] = i; // starting frame - CONS_Debug(DBG_RENDER, "frame %s, sprite2 %s - starting frame %d, number of frames %d\n", frame->name, spr2names[spr2 & ~FF_SPR2SUPER], model->spr2frames[spr2][0], model->spr2frames[spr2][1]); + if (model->spr2frames[spr2*2 + 1]++ == 0) // numspr2frames + model->spr2frames[spr2*2] = i; // starting frame + CONS_Debug(DBG_RENDER, "frame %s, sprite2 %s - starting frame %d, number of frames %d\n", frame->name, spr2names[spr2 & ~FF_SPR2SUPER], model->spr2frames[spr2*2], model->spr2frames[spr2*2 + 1]); } } } @@ -1110,7 +1123,7 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p if (!md2 || !skin) return 0; - while (!(md2->model->spr2frames[spr2][1]) + while (!(md2->model->spr2frames[spr2*2 + 1]) && spr2 != SPR2_STND && ++i != 32) // recursion limiter { @@ -1296,12 +1309,12 @@ void HWR_DrawMD2(gr_vissprite_t *spr) #define INTERPOLERATION_LIMIT TICRATE/4 - if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) + if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY && md2->model->spr2frames) { UINT8 spr2 = P_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); - UINT8 mod = md2->model->spr2frames[spr2][1] ? md2->model->spr2frames[spr2][1] : md2->model->header.numFrames; + UINT8 mod = md2->model->spr2frames[spr2*2 + 1] ? md2->model->spr2frames[spr2*2 + 1] : md2->model->header.numFrames; //FIXME: this is not yet correct - frame = md2->model->spr2frames[spr2][0] + ((spr->mobj->frame & FF_FRAMEMASK) % mod); + frame = md2->model->spr2frames[spr2*2] + ((spr->mobj->frame & FF_FRAMEMASK) % mod); buff = md2->model->glCommandBuffer; curr = &md2->model->frames[frame]; if (cv_grmd2.value == 1 && tics <= INTERPOLERATION_LIMIT) @@ -1317,7 +1330,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; if (nextframe >= (UINT32)((skin_t*)spr->mobj->skin)->sprites[spr->mobj->sprite2].numframes) nextframe = 0; - nextframe = md2->model->spr2frames[spr2][0] + (nextframe % md2->model->spr2frames[spr2][1]); + nextframe = md2->model->spr2frames[spr2*2] + (nextframe % mod); next = &md2->model->frames[nextframe]; } } diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index b183e4367..c7cda35af 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -112,7 +112,7 @@ typedef struct md2_textureCoordinate_t *texCoords; md2_triangle_t *triangles; md2_frame_t *frames; - size_t spr2frames[2*NUMPLAYERSPRITES][2]; + size_t *spr2frames; // size_t spr2frames[2*NUMPLAYERSPRITES][2]; INT32 *glCommandBuffer; } ATTRPACK md2_model_t; diff --git a/src/info.c b/src/info.c index c8bea7803..99f17884c 100644 --- a/src/info.c +++ b/src/info.c @@ -491,7 +491,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_FRUN, // SPR2_DASH, 0, // SPR2_PAIN, SPR2_PAIN, // SPR2_STUN, - 0, // SPR2_DEAD, + SPR2_PAIN, // SPR2_DEAD, SPR2_DEAD, // SPR2_DRWN, 0, // SPR2_ROLL, SPR2_SPNG, // SPR2_GASP, From 79dab78fd33170e4ba907a6b8fa46c5ad8bdfccf Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 27 Aug 2017 16:35:19 +0100 Subject: [PATCH 53/61] * Support FF_SPR2ENDSTATE in interpoleration. * Fix skidding interpoleration bug. --- src/hardware/hw_md2.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 967dfa03f..f89a7dc4d 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1322,16 +1322,20 @@ void HWR_DrawMD2(gr_vissprite_t *spr) if (durs > INTERPOLERATION_LIMIT) durs = INTERPOLERATION_LIMIT; - if (spr->mobj->frame & FF_ANIMATE + if (spr->mobj->player && spr->mobj->player->skidtime && spr->mobj->state-states == S_PLAY_WALK) // temporary hack + ; + else if (spr->mobj->frame & FF_ANIMATE || (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite == spr->mobj->sprite && (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) == spr->mobj->sprite2)) { UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; - if (nextframe >= (UINT32)((skin_t*)spr->mobj->skin)->sprites[spr->mobj->sprite2].numframes) - nextframe = 0; - nextframe = md2->model->spr2frames[spr2*2] + (nextframe % mod); - next = &md2->model->frames[nextframe]; + nextframe %= mod; + if (nextframe || !(spr->mobj->state->frame & FF_SPR2ENDSTATE)) + { + nextframe += md2->model->spr2frames[spr2*2]; + next = &md2->model->frames[nextframe]; + } } } } From d6701edcb6922f8d84cc4b2390f0dc233851b87e Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sun, 27 Aug 2017 18:46:53 +0100 Subject: [PATCH 54/61] Don't allow creating a new save when it wouldn't end up making a save file (ie, modified game without savemoddata). --- src/m_menu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index a158cd955..b983546cc 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2582,7 +2582,7 @@ boolean M_Responder(event_t *ev) { if (((currentMenu->menuitems[itemOn].status & IT_CALLTYPE) & IT_CALL_NOTMODIFIED) && modifiedgame && !savemoddata) { - S_StartSound(NULL, sfx_menu1); + S_StartSound(NULL, sfx_skid); M_StartMessage(M_GetText("This cannot be done in a modified game.\n\n(Press a key)\n"), NULL, MM_NOTHING); return true; } @@ -6565,7 +6565,13 @@ static void M_HandleLoadSave(INT32 choice) S_StartSound(NULL, sfx_skid); M_StartMessage("Are you sure you want to play\n\x85ultimate mode\x80? It isn't remotely fair,\nand you don't even get an emblem for it.\n\n(Press 'Y' to confirm)\n",M_SaveGameUltimateResponse,MM_YESNO); } - else if (savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" + else if (saveSlotSelected != NOSAVESLOT && savegameinfo[saveSlotSelected-1].lives == -42 && !(!modifiedgame || savemoddata)) + { + loadgamescroll = 0; + S_StartSound(NULL, sfx_skid); + M_StartMessage(M_GetText("This cannot be done in a modified game.\n\n(Press a key)\n"), NULL, MM_NOTHING); + } + else if (saveSlotSelected == NOSAVESLOT || savegameinfo[saveSlotSelected-1].lives != -666) // don't allow loading of "bad saves" { loadgamescroll = 0; S_StartSound(NULL, sfx_menu1); From 3c785cbe94359a742c305bd890fcb953fe2051f8 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Sat, 9 Sep 2017 22:12:23 +0100 Subject: [PATCH 55/61] * Add Skid SPR2/state in preperation for directionchar. * Clean up spr2 md2 code. * Experimented but then commented out some stuff for homing attack. --- src/dehacked.c | 1 + src/hardware/hw_md2.c | 23 +++++++++++------------ src/info.c | 3 +++ src/info.h | 2 ++ src/p_mobj.c | 1 + src/p_user.c | 7 +++++-- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 385411748..c17bf2f8a 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3356,6 +3356,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PLAY_STND", "S_PLAY_WAIT", "S_PLAY_WALK", + "S_PLAY_SKID", "S_PLAY_RUN", "S_PLAY_DASH", "S_PLAY_PAIN", diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index f89a7dc4d..708da2c15 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1313,29 +1313,28 @@ void HWR_DrawMD2(gr_vissprite_t *spr) { UINT8 spr2 = P_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); UINT8 mod = md2->model->spr2frames[spr2*2 + 1] ? md2->model->spr2frames[spr2*2 + 1] : md2->model->header.numFrames; + if (mod > ((skin_t *)spr->mobj->skin)->sprites[spr2].numframes) + mod = ((skin_t *)spr->mobj->skin)->sprites[spr2].numframes; //FIXME: this is not yet correct - frame = md2->model->spr2frames[spr2*2] + ((spr->mobj->frame & FF_FRAMEMASK) % mod); + frame = (spr->mobj->frame & FF_FRAMEMASK); + if (frame >= mod) + frame = 0; buff = md2->model->glCommandBuffer; - curr = &md2->model->frames[frame]; + curr = &md2->model->frames[md2->model->spr2frames[spr2*2] + frame]; if (cv_grmd2.value == 1 && tics <= INTERPOLERATION_LIMIT) { if (durs > INTERPOLERATION_LIMIT) durs = INTERPOLERATION_LIMIT; - if (spr->mobj->player && spr->mobj->player->skidtime && spr->mobj->state-states == S_PLAY_WALK) // temporary hack - ; - else if (spr->mobj->frame & FF_ANIMATE + if (spr->mobj->frame & FF_ANIMATE || (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite == spr->mobj->sprite && (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) == spr->mobj->sprite2)) { - UINT32 nextframe = (spr->mobj->frame & FF_FRAMEMASK) + 1; - nextframe %= mod; - if (nextframe || !(spr->mobj->state->frame & FF_SPR2ENDSTATE)) - { - nextframe += md2->model->spr2frames[spr2*2]; - next = &md2->model->frames[nextframe]; - } + if (++frame >= mod) + frame = 0; + if (frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE)) + next = &md2->model->frames[md2->model->spr2frames[spr2*2] + frame]; } } } diff --git a/src/info.c b/src/info.c index 99f17884c..d62111640 100644 --- a/src/info.c +++ b/src/info.c @@ -405,6 +405,7 @@ char spr2names[NUMPLAYERSPRITES][5] = "STND", "WAIT", "WALK", + "SKID", "RUN_", "DASH", "PAIN", @@ -487,6 +488,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { 0, // SPR2_STND, 0, // SPR2_WAIT, 0, // SPR2_WALK, + SPR2_WALK, // SPR2_SKID, SPR2_WALK, // SPR2_RUN , SPR2_FRUN, // SPR2_DASH, 0, // SPR2_PAIN, @@ -593,6 +595,7 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_STND|FF_ANIMATE, 105, {NULL}, 0, 7, S_PLAY_WAIT}, // S_PLAY_STND {SPR_PLAY, SPR2_WAIT|FF_ANIMATE, -1, {NULL}, 0, 16, S_NULL}, // S_PLAY_WAIT {SPR_PLAY, SPR2_WALK, 4, {NULL}, 0, 0, S_PLAY_WALK}, // S_PLAY_WALK + {SPR_PLAY, SPR2_SKID, 1, {NULL}, 0, 0, S_PLAY_WALK}, // S_PLAY_SKID {SPR_PLAY, SPR2_RUN , 2, {NULL}, 0, 0, S_PLAY_RUN}, // S_PLAY_RUN {SPR_PLAY, SPR2_DASH, 2, {NULL}, 0, 0, S_PLAY_DASH}, // S_PLAY_DASH {SPR_PLAY, SPR2_PAIN|FF_ANIMATE, 350, {NULL}, 0, 4, S_PLAY_FALL}, // S_PLAY_PAIN diff --git a/src/info.h b/src/info.h index 4ae5fcf63..7bc7e673a 100644 --- a/src/info.h +++ b/src/info.h @@ -609,6 +609,7 @@ typedef enum playersprite SPR2_STND = 0, SPR2_WAIT, SPR2_WALK, + SPR2_SKID, SPR2_RUN , SPR2_DASH, SPR2_PAIN, @@ -713,6 +714,7 @@ typedef enum state S_PLAY_STND, S_PLAY_WAIT, S_PLAY_WALK, + S_PLAY_SKID, S_PLAY_RUN, S_PLAY_DASH, S_PLAY_PAIN, diff --git a/src/p_mobj.c b/src/p_mobj.c index 8f9c44fdb..1834901ed 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -250,6 +250,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) player->panim = PA_EDGE; break; case S_PLAY_WALK: + case S_PLAY_SKID: case S_PLAY_FLOAT: player->panim = PA_WALK; break; diff --git a/src/p_user.c b/src/p_user.c index 09cafa0b3..6f364ebc8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4370,6 +4370,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) P_SetTarget(&player->mo->target, P_SetTarget(&player->mo->tracer, lockon)); if (lockon) { + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y); player->homing = 3*TICRATE; } @@ -6674,8 +6675,8 @@ static void P_SkidStuff(player_t *player) // If your push angle is more than this close to a full 180 degrees, trigger a skid. if (dang > ANGLE_157h) { - if (player->panim != PA_WALK) - P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + if (player->mo->state-states != S_PLAY_SKID) + P_SetPlayerMobjState(player->mo, S_PLAY_SKID); player->mo->tics = player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; S_StartSound(player->mo, sfx_skid); } @@ -7418,6 +7419,8 @@ static void P_MovePlayer(player_t *player) if (!(player->mo->tracer->flags & MF_BOSS)) player->pflags &= ~PF_THOKKED; + + // P_SetPlayerMobjState(player->mo, S_PLAY_SPRING); -- Speed didn't like it, RIP } } From f90d595332574cc7708752020ca94232cff13e3c Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 15 Sep 2017 20:34:46 +0100 Subject: [PATCH 56/61] * cv_directionchar and cv_autobrake, and their secondplayer versions (both on by default) now exist. * cv_useranalog is now hidden from the menu. * Directionchar now attempts to face the camera direction when you're standing still, and handles a few other states with more decorum. * Tailsbot is now slightly more capable of keeping up with Sonic. * pflags rearranged/adjusted, combining a few non-simulstaneous ones and turning PF_NIGHTSFALL into CR_NIGHTSFALL. * [unrelated to branch] all ground-impact based abilities now happen more consistently with quicksand. --- src/b_bot.c | 6 + src/d_clisrv.c | 12 +- src/d_netcmd.c | 24 +++- src/d_player.h | 79 ++++++------- src/dehacked.c | 34 +++--- src/g_game.c | 56 ++++++++- src/g_game.h | 2 + src/m_menu.c | 8 +- src/p_inter.c | 22 ++-- src/p_local.h | 1 + src/p_mobj.c | 105 +---------------- src/p_setup.c | 2 +- src/p_spec.c | 6 +- src/p_tick.c | 2 +- src/p_user.c | 301 +++++++++++++++++++++++++++++++++++++++---------- src/y_inter.c | 6 +- 16 files changed, 415 insertions(+), 251 deletions(-) diff --git a/src/b_bot.c b/src/b_bot.c index dc65c9c16..543bcb183 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -271,6 +271,12 @@ void B_RespawnBot(INT32 playernum) player->powers[pw_spacetime] = sonic->player->powers[pw_spacetime]; player->powers[pw_gravityboots] = sonic->player->powers[pw_gravityboots]; player->powers[pw_nocontrol] = sonic->player->powers[pw_nocontrol]; + player->acceleration = sonic->player->acceleration; + player->accelstart = sonic->player->accelstart; + player->thrustfactor = sonic->player->thrustfactor; + player->normalspeed = sonic->player->normalspeed; + player->pflags |= PF_AUTOBRAKE; + player->pflags &= ~PF_DIRECTIONCHAR; P_TeleportMove(tails, x, y, z); if (player->charability == CA_FLY) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3878d8795..2bc738dea 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3097,11 +3097,15 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) secondarydisplayplayer = newplayernum; DEBFILE("spawning me\n"); // Apply player flags as soon as possible! - players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE); + players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE); if (cv_flipcam.value) players[newplayernum].pflags |= PF_FLIPCAM; if (cv_analog.value) players[newplayernum].pflags |= PF_ANALOGMODE; + if (cv_directionchar.value) + players[newplayernum].pflags |= PF_DIRECTIONCHAR; + if (cv_autobrake.value) + players[newplayernum].pflags |= PF_AUTOBRAKE; } else { @@ -3110,11 +3114,15 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (botingame) players[newplayernum].bot = 1; // Same goes for player 2 when relevant - players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE); + players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE); if (cv_flipcam2.value) players[newplayernum].pflags |= PF_FLIPCAM; if (cv_analog2.value) players[newplayernum].pflags |= PF_ANALOGMODE; + if (cv_directionchar2.value) + players[newplayernum].pflags |= PF_DIRECTIONCHAR; + if (cv_autobrake2.value) + players[newplayernum].pflags |= PF_AUTOBRAKE; } D_SendPlayerConfig(); addedtogame = true; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7f408a2b5..4f9623900 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -771,6 +771,12 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_useranalog); CV_RegisterVar(&cv_useranalog2); + // deez New User eXperiences + CV_RegisterVar(&cv_directionchar); + CV_RegisterVar(&cv_directionchar2); + CV_RegisterVar(&cv_autobrake); + CV_RegisterVar(&cv_autobrake2); + // s_sound.c CV_RegisterVar(&cv_soundvolume); CV_RegisterVar(&cv_closedcaptioning); @@ -1433,6 +1439,10 @@ void SendWeaponPref(void) buf[0] |= 1; if (players[consoleplayer].pflags & PF_ANALOGMODE) buf[0] |= 2; + if (players[consoleplayer].pflags & PF_DIRECTIONCHAR) + buf[0] |= 4; + if (players[consoleplayer].pflags & PF_AUTOBRAKE) + buf[0] |= 8; SendNetXCmd(XD_WEAPONPREF, buf, 1); } @@ -1445,6 +1455,10 @@ void SendWeaponPref2(void) buf[0] |= 1; if (players[secondarydisplayplayer].pflags & PF_ANALOGMODE) buf[0] |= 2; + if (players[secondarydisplayplayer].pflags & PF_DIRECTIONCHAR) + buf[0] |= 4; + if (players[secondarydisplayplayer].pflags & PF_AUTOBRAKE) + buf[0] |= 8; SendNetXCmd2(XD_WEAPONPREF, buf, 1); } @@ -1452,11 +1466,15 @@ static void Got_WeaponPref(UINT8 **cp,INT32 playernum) { UINT8 prefs = READUINT8(*cp); - players[playernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE); + players[playernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE); if (prefs & 1) players[playernum].pflags |= PF_FLIPCAM; if (prefs & 2) players[playernum].pflags |= PF_ANALOGMODE; + if (prefs & 4) + players[playernum].pflags |= PF_DIRECTIONCHAR; + if (prefs & 8) + players[playernum].pflags |= PF_AUTOBRAKE; } void D_SendPlayerConfig(void) @@ -2578,12 +2596,12 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) { players[playernum].spectator = true; players[playernum].pflags &= ~PF_TAGIT; - players[playernum].pflags &= ~PF_TAGGED; + players[playernum].pflags &= ~PF_GAMETYPEOVER; } else if (NetPacket.packet.newteam != 3) // .newteam == 1 or 2. { players[playernum].spectator = false; - players[playernum].pflags &= ~PF_TAGGED;//Just in case. + players[playernum].pflags &= ~PF_GAMETYPEOVER; //Just in case. if (NetPacket.packet.newteam == 1) //Make the player IT. players[playernum].pflags |= PF_TAGIT; diff --git a/src/d_player.h b/src/d_player.h index c10e59405..bf0b303b8 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -98,66 +98,58 @@ typedef enum // typedef enum { - // Flip camera angle with gravity flip prefrence. - PF_FLIPCAM = 1, + // Cvars + PF_FLIPCAM = 1, // Flip camera angle with gravity flip prefrence. + PF_ANALOGMODE = 1<<1, // Analog mode? + PF_DIRECTIONCHAR = 1<<2, // Directional character sprites? + PF_AUTOBRAKE = 1<<3, // Autobrake? // Cheats - PF_GODMODE = 1<<1, - PF_NOCLIP = 1<<2, - PF_INVIS = 1<<3, + PF_GODMODE = 1<<4, + PF_NOCLIP = 1<<5, + PF_INVIS = 1<<6, // True if button down last tic. - PF_ATTACKDOWN = 1<<4, - PF_USEDOWN = 1<<5, - PF_JUMPDOWN = 1<<6, - PF_WPNDOWN = 1<<7, + PF_ATTACKDOWN = 1<<7, + PF_USEDOWN = 1<<8, + PF_JUMPDOWN = 1<<9, + PF_WPNDOWN = 1<<10, // Unmoving states - PF_STASIS = 1<<8, // Player is not allowed to move - PF_JUMPSTASIS = 1<<9, // and that includes jumping. + PF_STASIS = 1<<11, // Player is not allowed to move + PF_JUMPSTASIS = 1<<12, // and that includes jumping. PF_FULLSTASIS = PF_STASIS|PF_JUMPSTASIS, - // Did you get a time-over? - PF_TIMEOVER = 1<<10, + // Applying autobrake? + PF_APPLYAUTOBRAKE = 1<<13, // Character action status - PF_STARTJUMP = 1<<11, - PF_JUMPED = 1<<12, - PF_SPINNING = 1<<13, - PF_STARTDASH = 1<<14, - PF_THOKKED = 1<<15, + PF_STARTJUMP = 1<<14, + PF_JUMPED = 1<<15, + PF_NOJUMPDAMAGE = 1<<16, - // Are you gliding? - PF_GLIDING = 1<<16, + PF_SPINNING = 1<<17, + PF_STARTDASH = 1<<18, + + PF_THOKKED = 1<<19, + PF_SHIELDABILITY = 1<<20, + PF_GLIDING = 1<<21, + PF_BOUNCING = 1<<22, // Sliding (usually in water) like Labyrinth/Oil Ocean - PF_SLIDING = 1<<17, + PF_SLIDING = 1<<23, - // Bouncing - PF_BOUNCING = 1<<18, + // NiGHTS stuff + PF_TRANSFERTOCLOSEST = 1<<24, + PF_DRILLING = 1<<25, - /*** NIGHTS STUFF ***/ - PF_TRANSFERTOCLOSEST = 1<<19, - PF_NIGHTSFALL = 1<<20, - PF_DRILLING = 1<<21, - PF_SKIDDOWN = 1<<22, - - /*** TAG STUFF ***/ - PF_TAGGED = 1<<23, // Player has been tagged and awaits the next round in hide and seek. - PF_TAGIT = 1<<24, // The player is it! For Tag Mode + // Gametype-specific stuff + PF_GAMETYPEOVER = 1<<26, // Race time over, or H&S out-of-game + PF_TAGIT = 1<<27, // The player is it! For Tag Mode /*** misc ***/ - PF_FORCESTRAFE = 1<<25, // Turning inputs are translated into strafing inputs - PF_ANALOGMODE = 1<<26, // Analog mode? - - // Can carry another player? - PF_CANCARRY = 1<<27, - - // Used shield ability - PF_SHIELDABILITY = 1<<28, - - // Jump damage? - PF_NOJUMPDAMAGE = 1<<29, + PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs + PF_CANCARRY = 1<<29, // Can carry another player? // up to 1<<31 is free } pflags_t; @@ -234,6 +226,7 @@ typedef enum CR_PLAYER, // NiGHTS mode. Not technically a CARRYING, but doesn't stack with any of the others, so might as well go here. CR_NIGHTSMODE, + CR_NIGHTSFALL, // Old Brak sucks hard, but this gimmick could be used for something better, so we might as well continue supporting it. CR_BRAKGOOP, // Specific level gimmicks. diff --git a/src/dehacked.c b/src/dehacked.c index 5867eb90a..db559632c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -6422,8 +6422,12 @@ static const char *const MAPTHINGFLAG_LIST[4] = { #endif static const char *const PLAYERFLAG_LIST[] = { - // Flip camera angle with gravity flip prefrence. - "FLIPCAM", + + // Cvars + "FLIPCAM", // Flip camera angle with gravity flip prefrence. + "ANALOGMODE", // Analog mode? + "DIRECTIONCHAR", // Directional character sprites? + "AUTOBRAKE", // Autobrake? // Cheats "GODMODE", @@ -6441,41 +6445,36 @@ static const char *const PLAYERFLAG_LIST[] = { "JUMPSTASIS", // and that includes jumping. // (we don't include FULLSTASIS here I guess because it's just those two together...?) - // Did you get a time-over? - "TIMEOVER", + // Applying autobrake? + "APPLYAUTOBRAKE", // Character action status "STARTJUMP", "JUMPED", + "NOJUMPDAMAGE", + "SPINNING", "STARTDASH", - "THOKKED", - // Are you gliding? + "THOKKED", + "SHIELDABILITY", "GLIDING", + "BOUNCING", // Sliding (usually in water) like Labyrinth/Oil Ocean "SLIDING", - // Bouncing - "BOUNCING", - - /*** NIGHTS STUFF ***/ + // NiGHTS stuff "TRANSFERTOCLOSEST", - "NIGHTSFALL", "DRILLING", - "SKIDDOWN", - /*** TAG STUFF ***/ - "TAGGED", // Player has been tagged and awaits the next round in hide and seek. + // Gametype-specific stuff + "GAMETYPEOVER", // Race time over, or H&S out-of-game "TAGIT", // The player is it! For Tag Mode /*** misc ***/ "FORCESTRAFE", // Translate turn inputs into strafe inputs - "ANALOGMODE", // Analog mode? "CANCARRY", // Can carry? - "SHIELDABILITY", // Thokked with shield ability - "NOJUMPDAMAGE", // No jump damage NULL // stop loop here. }; @@ -6892,6 +6891,7 @@ struct { {"CR_GENERIC",CR_GENERIC}, {"CR_PLAYER",CR_PLAYER}, {"CR_NIGHTSMODE",CR_NIGHTSMODE}, + {"CR_NIGHTSFALL",CR_NIGHTSFALL}, {"CR_BRAKGOOP",CR_BRAKGOOP}, {"CR_ZOOMTUBE",CR_ZOOMTUBE}, {"CR_ROPEHANG",CR_ROPEHANG}, diff --git a/src/g_game.c b/src/g_game.c index e996938ab..be53744b9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -286,6 +286,10 @@ static void UserAnalog_OnChange(void); static void UserAnalog2_OnChange(void); static void Analog_OnChange(void); static void Analog2_OnChange(void); +static void DirectionChar_OnChange(void); +static void DirectionChar2_OnChange(void); +static void AutoBrake_OnChange(void); +static void AutoBrake2_OnChange(void); void SendWeaponPref(void); void SendWeaponPref2(void); @@ -368,6 +372,14 @@ consvar_t cv_useranalog = {"useranalog", "Off", CV_SAVE|CV_CALL, CV_OnOff, UserA consvar_t cv_useranalog2 = {"useranalog2", "Off", CV_SAVE|CV_CALL, CV_OnOff, UserAnalog2_OnChange, 0, NULL, NULL, 0, 0, NULL}; #endif +static CV_PossibleValue_t directionchar_cons_t[] = {{0, "Camera"}, {1, "Movement"}, {0, NULL}}; + +// deez New User eXperiences +consvar_t cv_directionchar = {"directionchar", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_directionchar2 = {"directionchar2", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar2_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_autobrake = {"autobrake", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_autobrake2 = {"autobrake2", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake2_OnChange, 0, NULL, NULL, 0, 0, NULL}; + typedef enum { AXISNONE = 0, @@ -1615,6 +1627,46 @@ static void Analog2_OnChange(void) SendWeaponPref2(); } +static void DirectionChar_OnChange(void) +{ + if (cv_directionchar.value) + players[consoleplayer].pflags |= PF_DIRECTIONCHAR; + else + players[consoleplayer].pflags &= ~PF_DIRECTIONCHAR; + + SendWeaponPref(); +} + +static void DirectionChar2_OnChange(void) +{ + if (cv_directionchar2.value) + players[secondarydisplayplayer].pflags |= PF_DIRECTIONCHAR; + else + players[secondarydisplayplayer].pflags &= ~PF_DIRECTIONCHAR; + + SendWeaponPref2(); +} + +static void AutoBrake_OnChange(void) +{ + if (cv_autobrake.value) + players[consoleplayer].pflags |= PF_AUTOBRAKE; + else + players[consoleplayer].pflags &= ~PF_AUTOBRAKE; + + SendWeaponPref(); +} + +static void AutoBrake2_OnChange(void) +{ + if (cv_autobrake2.value) + players[secondarydisplayplayer].pflags |= PF_AUTOBRAKE; + else + players[secondarydisplayplayer].pflags &= ~PF_AUTOBRAKE; + + SendWeaponPref2(); +} + // // G_DoLoadLevel // @@ -2103,7 +2155,7 @@ void G_PlayerReborn(INT32 player) jointime = players[player].jointime; spectator = players[player].spectator; outofcoop = players[player].outofcoop; - pflags = (players[player].pflags & (PF_TIMEOVER|PF_FLIPCAM|PF_TAGIT|PF_TAGGED|PF_ANALOGMODE)); + pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); // As long as we're not in multiplayer, carry over cheatcodes from map to map if (!(netgame || multiplayer)) @@ -3752,7 +3804,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean players[i].score = 0; // The latter two should clear by themselves, but just in case - players[i].pflags &= ~(PF_TAGIT|PF_TAGGED|PF_FULLSTASIS); + players[i].pflags &= ~(PF_TAGIT|PF_GAMETYPEOVER|PF_FULLSTASIS); // Clear cheatcodes too, just in case. players[i].pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS); diff --git a/src/g_game.h b/src/g_game.h index 72a6f3d6e..cd079e844 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -59,6 +59,8 @@ extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_mousemove; extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_mousemove2; extern consvar_t cv_useranalog, cv_useranalog2; extern consvar_t cv_analog, cv_analog2; +extern consvar_t cv_directionchar, cv_directionchar2; +extern consvar_t cv_autobrake, cv_autobrake2; extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_fireaxis,cv_firenaxis; extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_fireaxis2,cv_firenaxis2; extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest; diff --git a/src/m_menu.c b/src/m_menu.c index 64255e71a..84edcbfe3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1061,7 +1061,9 @@ static menuitem_t OP_P1ControlsMenu[] = {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam , 60}, {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 70}, - {IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog, 90}, + //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog, 90}, + {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar, 90}, + {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake, 100}, }; static menuitem_t OP_P2ControlsMenu[] = @@ -1074,7 +1076,9 @@ static menuitem_t OP_P2ControlsMenu[] = {IT_STRING | IT_CVAR, NULL, "Flip Camera with Gravity" , &cv_flipcam2 , 60}, {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 70}, - {IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog2, 90}, + //{IT_STRING | IT_CVAR, NULL, "Analog Control", &cv_useranalog2, 90}, + {IT_STRING | IT_CVAR, NULL, "Character angle", &cv_directionchar2, 90}, + {IT_STRING | IT_CVAR, NULL, "Automatic braking", &cv_autobrake2, 100}, }; static menuitem_t OP_ChangeControlsMenu[] = diff --git a/src/p_inter.c b/src/p_inter.c index d2101ca57..c843838b6 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1871,7 +1871,7 @@ void P_CheckTimeLimit(void) for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator - || (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT)) + || (players[i].pflags & PF_GAMETYPEOVER) || (players[i].pflags & PF_TAGIT)) continue; CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]); @@ -2018,7 +2018,7 @@ void P_CheckSurvivors(void) spectators++; else if (players[i].pflags & PF_TAGIT) taggers++; - else if (!(players[i].pflags & PF_TAGGED)) + else if (!(players[i].pflags & PF_GAMETYPEOVER)) { survivorarray[survivors] = i; survivors++; @@ -2325,7 +2325,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } else { - if (!(target->player->pflags & PF_TAGGED)) + if (!(target->player->pflags & PF_GAMETYPEOVER)) { //otherwise, increment the tagger's score. //in hide and seek, suiciding players are counted as found. @@ -2337,7 +2337,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_AddPlayerScore(&players[w], 100); } - target->player->pflags |= PF_TAGGED; + target->player->pflags |= PF_GAMETYPEOVER; CONS_Printf(M_GetText("%s was found!\n"), player_names[target->player-players]); P_CheckSurvivors(); } @@ -2793,7 +2793,7 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou } else { - player->pflags |= PF_TAGGED; //in hide and seek, the player is tagged and stays stationary. + player->pflags |= PF_GAMETYPEOVER; //in hide and seek, the player is tagged and stays stationary. CONS_Printf(M_GetText("%s was found!\n"), player_names[player-players]); // Tell everyone who is it! } @@ -3208,7 +3208,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player->pflags & PF_GODMODE) return false; - if (!(target->player->powers[pw_carry] == CR_NIGHTSMODE || target->player->pflags & PF_NIGHTSFALL) && (maptol & TOL_NIGHTS)) + if ((maptol & TOL_NIGHTS) && target->player->powers[pw_carry] != CR_NIGHTSMODE && target->player->powers[pw_carry] != CR_NIGHTSFALL) return false; switch (damagetype) @@ -3409,7 +3409,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) if (player->rings <= 0) num_rings = 0; - if (num_rings > 32 && !(player->pflags & PF_NIGHTSFALL)) + if (num_rings > 32 && player->powers[pw_carry] != CR_NIGHTSFALL) num_rings = 32; if (player->powers[pw_emeralds]) @@ -3441,7 +3441,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) // Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2. // Technically a non-SA way of spilling rings. They just so happen to be a little similar. - if (player->pflags & PF_NIGHTSFALL) + if (player->powers[pw_carry] == CR_NIGHTSFALL) { ns = FixedMul(((i*FRACUNIT)/16)+2*FRACUNIT, mo->scale); mo->momx = FixedMul(FINECOSINE(fa),ns); @@ -3481,13 +3481,13 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) } if (player->mo->eflags & MFE_VERTICALFLIP) mo->momz *= -1; + + if (P_IsObjectOnGround(player->mo)) + player->powers[pw_carry] = CR_NONE; } player->losstime += 10*TICRATE; - if (P_IsObjectOnGround(player->mo)) - player->pflags &= ~PF_NIGHTSFALL; - return; } diff --git a/src/p_local.h b/src/p_local.h index b1bfc6456..6fc218d36 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -140,6 +140,7 @@ boolean P_IsObjectOnGround(mobj_t *mo); boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec); boolean P_InSpaceSector(mobj_t *mo); boolean P_InQuicksand(mobj_t *mo); +boolean P_PlayerHitFloor(player_t *player); void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index 31262ff16..c5f67d685 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3042,110 +3042,9 @@ static void P_PlayerZMovement(mobj_t *mo) } } - if (mo->health && !mo->player->spectator && !P_CheckDeathPitCollide(mo)) - { - if ((mo->player->charability2 == CA2_SPINDASH) && !(mo->player->pflags & PF_THOKKED) && (mo->player->cmd.buttons & BT_USE) && (FixedHypot(mo->momx, mo->momy) > (5*mo->scale))) - { - mo->player->pflags |= PF_SPINNING; - P_SetPlayerMobjState(mo, S_PLAY_ROLL); - S_StartSound(mo, sfx_spin); - } - else - mo->player->pflags &= ~PF_SPINNING; - - if (mo->player->pflags & PF_GLIDING) // ground gliding - { - mo->player->skidtime = TICRATE; - mo->tics = -1; - } - else if (mo->player->charability2 == CA2_MELEE && (mo->player->panim == PA_ABILITY2 && mo->state-states != S_PLAY_MELEE_LANDING)) - { - P_SetPlayerMobjState(mo, S_PLAY_MELEE_LANDING); - mo->tics = (mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(mo->movefactor)))>>FRACBITS; - S_StartSound(mo, sfx_s3k8b); - mo->player->pflags |= PF_FULLSTASIS; - } - else if (mo->player->pflags & PF_JUMPED || !(mo->player->pflags & PF_SPINNING) - || mo->player->powers[pw_tailsfly] || mo->state-states == S_PLAY_FLY_TIRED) - { - if (mo->player->cmomx || mo->player->cmomy) - { - if (mo->player->charflags & SF_DASHMODE && mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_DASH) - P_SetPlayerMobjState(mo, S_PLAY_DASH); - else if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) - && (mo->player->panim != PA_RUN || mo->state-states == S_PLAY_FLOAT_RUN)) - P_SetPlayerMobjState(mo, S_PLAY_RUN); - else if ((mo->player->rmomx || mo->player->rmomy) - && (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_FLOAT)) - P_SetPlayerMobjState(mo, S_PLAY_WALK); - else if (!mo->player->rmomx && !mo->player->rmomy && mo->player->panim != PA_IDLE) - P_SetPlayerMobjState(mo, S_PLAY_STND); - } - else - { - if (mo->player->charflags & SF_DASHMODE && mo->player->dashmode >= 3*TICRATE && mo->player->panim != PA_DASH) - P_SetPlayerMobjState(mo, S_PLAY_DASH); - else if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) - && (mo->player->panim != PA_RUN || mo->state-states == S_PLAY_FLOAT_RUN)) - P_SetPlayerMobjState(mo, S_PLAY_RUN); - else if ((mo->momx || mo->momy) - && (mo->player->panim != PA_WALK || mo->state-states == S_PLAY_FLOAT)) - P_SetPlayerMobjState(mo, S_PLAY_WALK); - else if (!mo->momx && !mo->momy && mo->player->panim != PA_IDLE) - P_SetPlayerMobjState(mo, S_PLAY_STND); - } - } - - if (!(mo->player->pflags & PF_GLIDING)) - mo->player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); - - mo->player->pflags &= ~(PF_STARTJUMP|PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/); - mo->player->secondjump = 0; - mo->player->glidetime = 0; - mo->player->climbing = 0; - mo->player->powers[pw_tailsfly] = 0; - - if (mo->player->pflags & PF_SHIELDABILITY) - { - mo->player->pflags &= ~PF_SHIELDABILITY; - - if ((mo->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) // Elemental shield's stomp attack. - { - if (mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) // play a blunt sound - S_StartSound(mo, sfx_s3k4c); - else // create a fire pattern on the ground - { - S_StartSound(mo, sfx_s3k47); - P_ElementalFire(mo->player, true); - } - P_SetObjectMomZ(mo, - (mo->eflags & MFE_UNDERWATER) - ? 6*FRACUNIT/5 - : 5*FRACUNIT/2, - false); - P_SetPlayerMobjState(mo, S_PLAY_FALL); - mo->momx = mo->momy = 0; - clipmomz = false; - } - else if ((mo->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) // Bubble shield's bounce attack. - { - P_DoBubbleBounce(mo->player); - clipmomz = false; - } - } - - if (mo->player->pflags & PF_BOUNCING) - { - P_MobjCheckWater(mo); - mo->momz *= -1; - P_DoAbilityBounce(mo->player, true); - if (mo->player->scoreadd) - mo->player->scoreadd--; - clipmomz = false; - } - } + clipmomz = P_PlayerHitFloor(mo->player); } - if (!(mo->player->pflags & PF_SPINNING)) + if (!(mo->player->pflags & PF_SPINNING) && mo->player->powers[pw_carry] != CR_NIGHTSMODE) mo->player->pflags &= ~PF_STARTDASH; if (clipmomz) diff --git a/src/p_setup.c b/src/p_setup.c index 9c4bede74..dd5ef2d30 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2244,7 +2244,7 @@ static void P_LevelInitStuff(void) players[i].xtralife = players[i].deadtimer = players[i].numboxes = players[i].totalring = players[i].laps = 0; players[i].rings = 0; players[i].aiming = 0; - players[i].pflags &= ~PF_TIMEOVER; + players[i].pflags &= ~PF_GAMETYPEOVER; players[i].losstime = 0; players[i].timeshit = 0; diff --git a/src/p_spec.c b/src/p_spec.c index 2cad4fc90..035bb9d78 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3985,7 +3985,7 @@ DoneSection2: player->powers[pw_carry] = CR_ZOOMTUBE; player->speed = speed; player->pflags |= PF_SPINNING; - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_SLIDING|PF_CANCARRY); + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); player->climbing = 0; if (player->mo->state-states != S_PLAY_ROLL) @@ -4065,7 +4065,7 @@ DoneSection2: player->powers[pw_carry] = CR_ZOOMTUBE; player->speed = speed; player->pflags |= PF_SPINNING; - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_SLIDING|PF_CANCARRY); + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); player->climbing = 0; if (player->mo->state-states != S_PLAY_ROLL) @@ -4373,7 +4373,7 @@ DoneSection2: S_StartSound(player->mo, sfx_s3k4a); - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_SLIDING|PF_CANCARRY); + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); player->climbing = 0; P_SetThingPosition(player->mo); P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); diff --git a/src/p_tick.c b/src/p_tick.c index a79d71ef4..658b1e4ea 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -533,7 +533,7 @@ static inline void P_DoTagStuff(void) for (i=0; i < MAXPLAYERS; i++) { if (playeringame[i] && !players[i].spectator && players[i].playerstate == PST_LIVE - && !(players[i].pflags & (PF_TAGIT|PF_TAGGED))) + && !(players[i].pflags & (PF_TAGIT|PF_GAMETYPEOVER))) //points given is the number of participating players divided by two. P_AddPlayerScore(&players[i], participants/2); } diff --git a/src/p_user.c b/src/p_user.c index 9bd38c1cb..2be03a6f4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -576,7 +576,7 @@ static void P_DeNightserizePlayer(player_t *player) thinker_t *th; mobj_t *mo2; - player->powers[pw_carry] = CR_NONE; + player->powers[pw_carry] = CR_NIGHTSFALL; player->powers[pw_underwater] = 0; player->pflags &= ~(PF_USEDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST); @@ -603,7 +603,6 @@ static void P_DeNightserizePlayer(player_t *player) player->marescore = 0; P_SetPlayerMobjState(player->mo, S_PLAY_FALL); - player->pflags |= PF_NIGHTSFALL; // If in a special stage, add some preliminary exit time. if (G_IsSpecialStage(gamemap)) @@ -863,7 +862,7 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) // Point penalty for hitting a hazard during tag. // Discourages players from intentionally hurting themselves to avoid being tagged. - if (gametype == GT_TAG && (!(player->pflags & PF_TAGGED) && !(player->pflags & PF_TAGIT))) + if (gametype == GT_TAG && (!(player->pflags & PF_GAMETYPEOVER) && !(player->pflags & PF_TAGIT))) { if (player->score >= 50) player->score -= 50; @@ -885,7 +884,7 @@ void P_ResetPlayer(player_t *player) { player->pflags &= ~(PF_SPINNING|PF_STARTDASH|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_THOKKED|PF_CANCARRY|PF_SHIELDABILITY|PF_BOUNCING); - if (!(player->powers[pw_carry] == CR_NIGHTSMODE || player->powers[pw_carry] == CR_BRAKGOOP)) + if (!(player->powers[pw_carry] == CR_NIGHTSMODE || player->powers[pw_carry] == CR_NIGHTSFALL || player->powers[pw_carry] == CR_BRAKGOOP)) player->powers[pw_carry] = CR_NONE; player->secondjump = 0; @@ -1778,6 +1777,122 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space return false; // No vacuum here, Captain! } +// +// P_PlayerHitFloor +// +// Handles player hitting floor surface. +// Returns whether to clip momz. +boolean P_PlayerHitFloor(player_t *player) +{ + boolean clipmomz; + + I_Assert(player->mo != NULL); + + if ((clipmomz = !(P_CheckDeathPitCollide(player->mo))) && player->mo->health && !player->spectator) + { + if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_THOKKED) && (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale))) + { + player->pflags |= PF_SPINNING; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_spin); + } + else + player->pflags &= ~PF_SPINNING; + + if (player->pflags & PF_GLIDING) // ground gliding + { + player->skidtime = TICRATE; + player->mo->tics = -1; + } + else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING)) + { + P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); + player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; + S_StartSound(player->mo, sfx_s3k8b); + player->pflags |= PF_FULLSTASIS; + } + else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING) + || player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED) + { + if (player->cmomx || player->cmomy) + { + if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) + && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN); + else if ((player->rmomx || player->rmomy) + && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE) + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + } + else + { + if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH) + P_SetPlayerMobjState(player->mo, S_PLAY_DASH); + else if (player->speed >= FixedMul(player->runspeed, player->mo->scale) + && (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN)) + P_SetPlayerMobjState(player->mo, S_PLAY_RUN); + else if ((player->mo->momx || player->mo->momy) + && (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT)) + P_SetPlayerMobjState(player->mo, S_PLAY_WALK); + else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE) + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + } + } + + if (!(player->pflags & PF_GLIDING)) + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE); + player->pflags &= ~(PF_STARTJUMP|PF_THOKKED|PF_CANCARRY/*|PF_GLIDING*/); + player->secondjump = 0; + player->glidetime = 0; + player->climbing = 0; + player->powers[pw_tailsfly] = 0; + + if (player->pflags & PF_SHIELDABILITY) + { + player->pflags &= ~PF_SHIELDABILITY; + + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) // Elemental shield's stomp attack. + { + if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) // play a blunt sound + S_StartSound(player->mo, sfx_s3k4c); + else // create a fire pattern on the ground + { + S_StartSound(player->mo, sfx_s3k47); + P_ElementalFire(player, true); + } + P_SetObjectMomZ(player->mo, + (player->mo->eflags & MFE_UNDERWATER) + ? 6*FRACUNIT/5 + : 5*FRACUNIT/2, + false); + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + player->mo->momx = player->mo->momy = 0; + clipmomz = false; + } + else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) // Bubble shield's bounce attack. + { + P_DoBubbleBounce(player); + clipmomz = false; + } + } + + if (player->pflags & PF_BOUNCING) + { + P_MobjCheckWater(player->mo); + player->mo->momz *= -1; + P_DoAbilityBounce(player, true); + if (player->scoreadd) + player->scoreadd--; + clipmomz = false; + } + } + + return clipmomz; +} + boolean P_InQuicksand(mobj_t *mo) // Returns true if you are in quicksand { sector_t *sector = mo->subsector->sector; @@ -2153,6 +2268,9 @@ static void P_CheckQuicksand(player_t *player) if (player->mo->z + player->mo->height >= ceilingheight) player->mo->z = ceilingheight - player->mo->height; + + if (player->mo->momz <= 0) + P_PlayerHitFloor(player); } else { @@ -2162,6 +2280,9 @@ static void P_CheckQuicksand(player_t *player) if (player->mo->z <= floorheight) player->mo->z = floorheight; + + if (player->mo->momz >= 0) + P_PlayerHitFloor(player); } friction = abs(rover->master->v1->y - rover->master->v2->y)>>6; @@ -6282,7 +6403,7 @@ static void P_NiGHTSMovement(player_t *player) && ((cmd->buttons & (BT_CAMLEFT|BT_CAMRIGHT)) == (BT_CAMLEFT|BT_CAMRIGHT) || (cmd->buttons & BT_USE))) { - if (!(player->pflags & PF_SKIDDOWN)) + if (!(player->pflags & PF_STARTDASH)) S_StartSound(player->mo, sfx_ngskid); // You can tap the button to only slow down a bit, @@ -6300,10 +6421,10 @@ static void P_NiGHTSMovement(player_t *player) } } - player->pflags |= PF_SKIDDOWN; + player->pflags |= PF_STARTDASH; } else - player->pflags &= ~PF_SKIDDOWN; + player->pflags &= ~PF_STARTDASH; { const angle_t fa = (FixedAngle(player->flyangle*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; @@ -6749,7 +6870,7 @@ static void P_MovePlayer(player_t *player) if (!(player->pflags & PF_TAGIT)) { forcestasis = true; - if (player->pflags & PF_TAGGED) // Already hit. + if (player->pflags & PF_GAMETYPEOVER) // Already hit. player->powers[pw_flashing] = 5; } } @@ -6819,8 +6940,7 @@ static void P_MovePlayer(player_t *player) P_CheckQuicksand(player); return; } - - if (player->pflags & PF_NIGHTSFALL && P_IsObjectOnGround(player->mo)) + else if (player->powers[pw_carry] == CR_NIGHTSFALL && P_IsObjectOnGround(player->mo)) { if (G_IsSpecialStage(gamemap)) { @@ -6832,7 +6952,7 @@ static void P_MovePlayer(player_t *player) } else if (player->rings > 0) P_DamageMobj(player->mo, NULL, NULL, 1, 0); - player->pflags &= ~PF_NIGHTSFALL; + player->powers[pw_carry] = CR_NONE; } } @@ -7192,7 +7312,7 @@ static void P_MovePlayer(player_t *player) //////////////////////////// // If the player isn't on the ground, make sure they aren't in a "starting dash" position. - if (!onground) + if (!onground && player->powers[pw_carry] != CR_NIGHTSMODE) { player->pflags &= ~PF_STARTDASH; player->dashspeed = 0; @@ -7209,7 +7329,7 @@ static void P_MovePlayer(player_t *player) P_DoJumpStuff(player, cmd); // If you're not spinning, you'd better not be spindashing! - if (!(player->pflags & PF_SPINNING)) + if (!(player->pflags & PF_SPINNING) && player->powers[pw_carry] != CR_NIGHTSMODE) player->pflags &= ~PF_STARTDASH; ////////////////// @@ -8390,7 +8510,7 @@ static void P_DeathThink(player_t *player) if (gametype == GT_RACE || gametype == GT_COMPETITION || (gametype == GT_COOP && (multiplayer || netgame))) { // Keep time rolling in race mode - if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_TIMEOVER)) + if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER)) { if (gametype == GT_RACE || gametype == GT_COMPETITION) { @@ -9415,7 +9535,7 @@ void P_PlayerThink(player_t *player) if (netgame && player->mo->health > 0) CONS_Printf(M_GetText("%s ran out of time.\n"), player_names[player-players]); - player->pflags |= PF_TIMEOVER; + player->pflags |= PF_GAMETYPEOVER; if (player->powers[pw_carry] == CR_NIGHTSMODE) { @@ -9614,55 +9734,116 @@ void P_PlayerThink(player_t *player) if (!player->mo) return; // P_MovePlayer removed player->mo. - if ((player->climbing // stuff where the direction is forced at all times - || (player->pflags & (PF_GLIDING|PF_SLIDING))) - || (player->powers[pw_carry] == CR_NIGHTSMODE) - || P_AnalogMove(player) // keep things synchronised up there, since the camera IS seperate from player motion when that happens - || G_RingSlingerGametype()) // no firing rings in directions your player isn't aiming - player->drawangle = player->mo->angle; - else if (player->pflags & PF_STARTDASH) // fun spindash experiment + // deez New User eXperiences. { - angle_t diff = (player->mo->angle - player->drawangle); - if (diff > ANGLE_180) - diff = InvAngle(InvAngle(diff)/4); - else - diff /= 4; - player->drawangle += diff; - } - else if (P_PlayerInPain(player)) - ; - else if (player->powers[pw_carry] && player->mo->tracer) // carry - { - switch (player->powers[pw_carry]) + // Directionchar! + // Camera angle stuff. + if (player->exiting) // no control, no modification + ; + else if (!(player->pflags & PF_DIRECTIONCHAR) + || (player->climbing // stuff where the direction is forced at all times + || (player->pflags & PF_GLIDING)) + || (player->powers[pw_carry] == CR_NIGHTSMODE) + || (P_AnalogMove(player) || twodlevel || player->mo->flags2 & MF2_TWOD) // keep things synchronised up there, since the camera IS seperate from player motion when that happens + || G_RingSlingerGametype()) // no firing rings in directions your player isn't aiming + player->drawangle = player->mo->angle; + else if (P_PlayerInPain(player)) + ; + else if (player->powers[pw_carry] && player->mo->tracer) // carry { - case CR_PLAYER: - player->drawangle = (player->mo->tracer->player ? player->mo->tracer->player->drawangle : player->mo->tracer->angle); - break; - /* -- in case we wanted to have the camera freely movable during zoom tube style stuff - case CR_ZOOMTUBE: - case CR_ROPEHANG: - player->drawangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - break; - */ - default: - player->drawangle = player->mo->angle; - break; + switch (player->powers[pw_carry]) + { + case CR_PLAYER: + player->drawangle = (player->mo->tracer->player ? player->mo->tracer->player->drawangle : player->mo->tracer->angle); + break; + /* -- in case we wanted to have the camera freely movable during zoom tube style stuff + case CR_ZOOMTUBE: + case CR_ROPEHANG: + player->drawangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + break; + */ + default: + player->drawangle = player->mo->angle; + break; + } + } + else if ((player->skidtime > (TICRATE/2 - 2) || ((player->pflags & (PF_SPINNING|PF_STARTDASH)) == PF_SPINNING)) && (abs(player->rmomx) > 5*player->mo->scale || abs(player->rmomy) > 5*player->mo->scale)) // spin/skid force + player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); + else if (((player->charability2 == CA2_GUNSLINGER || player->charability2 == CA2_MELEE) && player->panim == PA_ABILITY2) || player->pflags & PF_STASIS || player->skidtime) + ; + else + { + angle_t diff; + UINT8 factor; + + if (player->pflags & PF_SLIDING) + { +#if 0 // fun hydrocity style horizontal spin + if (player->mo->eflags & MFE_TOUCHWATER || player->powers[pw_flashing] > (flashingtics/4)*3) + { + diff = (player->mo->angle - player->drawangle); + factor = 4; + } + else + { + diff = factor = 0; + player->drawangle += ANGLE_22h; + } +#else + diff = (player->mo->angle - player->drawangle); + factor = 4; +#endif + } + else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys + { + diff = ((player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<drawangle); + factor = 4; + } + else if (player->rmomx || player->rmomy) + diff = factor = 0; + else + { + diff = (player->mo->angle - player->drawangle); + factor = ((player->pflags & PF_STARTDASH) ? 4 : 8); + } + + if (diff) + { + if (diff > ANGLE_180) + diff = InvAngle(InvAngle(diff)/factor); + else + diff /= factor; + player->drawangle += diff; + } + } + + // Autobrake! + { + boolean currentlyonground = P_IsObjectOnGround(player->mo); + + if (((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) + && !(cmd->forwardmove || cmd->sidemove) + && (player->rmomx || player->rmomy)) + { + fixed_t acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration * player->thrustfactor * 20; + angle_t moveAngle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); + + if (!currentlyonground) + acceleration /= 2; + + P_Thrust(player->mo, moveAngle, -acceleration); + } + + if (!(player->pflags & PF_AUTOBRAKE) + || player->panim == PA_SPRING + || player->panim == PA_PAIN + || !player->mo->health + || player->pflags & PF_SPINNING) + player->pflags &= ~PF_APPLYAUTOBRAKE; + else if (currentlyonground) + player->pflags |= PF_APPLYAUTOBRAKE; } } - else if ((player->pflags & PF_SPINNING) && (abs(player->rmomx) > 5*player->mo->scale || abs(player->rmomy) > 5*player->mo->scale)) // spin force - player->drawangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); - else if (((player->charability2 == CA2_GUNSLINGER || player->charability2 == CA2_MELEE) && player->panim == PA_ABILITY2) || player->pflags & PF_STASIS || player->skidtime) - ; - else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys - { - angle_t diff = ((player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<drawangle); - if (diff > ANGLE_180) - diff = InvAngle(InvAngle(diff)/4); - else - diff /= 4; - player->drawangle += diff; - } - if (player->powers[pw_pushing]) player->powers[pw_pushing]--; diff --git a/src/y_inter.c b/src/y_inter.c index a102aa99f..3b7f082f9 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -475,7 +475,7 @@ void Y_IntermissionDrawer(void) V_DrawRightAlignedString(x+152, y, 0, va("%i", data.match.scores[i])); else if (intertype == int_race) { - if (players[data.match.num[i]].pflags & PF_TIMEOVER) + if (players[data.match.num[i]].pflags & PF_GAMETYPEOVER) snprintf(strtime, sizeof strtime, "DNF"); else snprintf(strtime, sizeof strtime, @@ -493,7 +493,7 @@ void Y_IntermissionDrawer(void) V_DrawRightAlignedString(x+152+BASEVIDWIDTH/2, y, 0, va("%u", data.match.scores[i])); else if (intertype == int_race) { - if (players[data.match.num[i]].pflags & PF_TIMEOVER) + if (players[data.match.num[i]].pflags & PF_GAMETYPEOVER) snprintf(strtime, sizeof strtime, "DNF"); else snprintf(strtime, sizeof strtime, "%i:%02i.%02i", G_TicsToMinutes(data.match.scores[i], true), @@ -643,7 +643,7 @@ void Y_IntermissionDrawer(void) // already constrained to 8 characters V_DrawString(x+36, y, V_ALLOWLOWERCASE, data.competition.name[i]); - if (players[data.competition.num[i]].pflags & PF_TIMEOVER) + if (players[data.competition.num[i]].pflags & PF_GAMETYPEOVER) snprintf(sstrtime, sizeof sstrtime, "Time Over"); else if (players[data.competition.num[i]].lives <= 0) snprintf(sstrtime, sizeof sstrtime, "Game Over"); From 725e015a19a8c369f28b0725a2970e37923fcaa7 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 15 Sep 2017 20:34:46 +0100 Subject: [PATCH 57/61] Fix the bracketing on the autobrake calculation. --- src/p_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 2be03a6f4..67e47d295 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9825,7 +9825,7 @@ void P_PlayerThink(player_t *player) && !(cmd->forwardmove || cmd->sidemove) && (player->rmomx || player->rmomy)) { - fixed_t acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration * player->thrustfactor * 20; + fixed_t acceleration = (player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration) * player->thrustfactor * 20; angle_t moveAngle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy); if (!currentlyonground) From d44a36c8fe30f19d67a639ec4c8a764bf6f84d41 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 15 Sep 2017 20:34:46 +0100 Subject: [PATCH 58/61] * Make autobrake scaled to low-friction surfaces. * Make rope hangs change how they handle the player's angle a little more organically. --- src/p_user.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 67e47d295..80d16e30b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9756,12 +9756,14 @@ void P_PlayerThink(player_t *player) case CR_PLAYER: player->drawangle = (player->mo->tracer->player ? player->mo->tracer->player->drawangle : player->mo->tracer->angle); break; - /* -- in case we wanted to have the camera freely movable during zoom tube style stuff - case CR_ZOOMTUBE: + /* -- in case we wanted to have the camera freely movable during zoom tubes + case CR_ZOOMTUBE:*/ case CR_ROPEHANG: - player->drawangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - break; - */ + if (player->mo->momx || player->mo->momy) + { + player->drawangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); + break; + } default: player->drawangle = player->mo->angle; break; @@ -9831,6 +9833,9 @@ void P_PlayerThink(player_t *player) if (!currentlyonground) acceleration /= 2; + if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... + acceleration = FixedMul(acceleration<mo->movefactor)>>FRACBITS; + P_Thrust(player->mo, moveAngle, -acceleration); } @@ -9847,6 +9852,7 @@ void P_PlayerThink(player_t *player) if (player->powers[pw_pushing]) player->powers[pw_pushing]--; + player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame. // Unset statis flags after moving. From 148f2cc607e6f641e2fd72bc7b8ce4105056640c Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 15 Sep 2017 20:34:46 +0100 Subject: [PATCH 59/61] * Updated the circumstances under which autobrake is applied. * Made drawangle updated when jumping off a wall as Knuckles. --- src/p_user.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 80d16e30b..54ec1af55 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3789,7 +3789,7 @@ void P_DoJump(player_t *player, boolean soundandstate) else player->mo->momz = 15*(FRACUNIT/4); - player->mo->angle = player->mo->angle - ANGLE_180; // Turn around from the wall you were climbing. + player->drawangle = player->mo->angle = player->mo->angle - ANGLE_180; // Turn around from the wall you were climbing. if (!demoplayback || P_AnalogMove(player)) { @@ -9823,7 +9823,8 @@ void P_PlayerThink(player_t *player) { boolean currentlyonground = P_IsObjectOnGround(player->mo); - if (((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) + if (!player->powers[pw_carry] + && ((player->pflags & (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) == (PF_AUTOBRAKE|PF_APPLYAUTOBRAKE)) && !(cmd->forwardmove || cmd->sidemove) && (player->rmomx || player->rmomy)) { @@ -9840,10 +9841,12 @@ void P_PlayerThink(player_t *player) } if (!(player->pflags & PF_AUTOBRAKE) + || player->powers[pw_carry] || player->panim == PA_SPRING || player->panim == PA_PAIN || !player->mo->health - || player->pflags & PF_SPINNING) + || player->climbing + || player->pflags & (PF_SPINNING|PF_SLIDING)) player->pflags &= ~PF_APPLYAUTOBRAKE; else if (currentlyonground) player->pflags |= PF_APPLYAUTOBRAKE; From 48c0ef2362cc5f136e6995cf4653d00327747aeb Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Fri, 15 Sep 2017 20:34:46 +0100 Subject: [PATCH 60/61] Remove extraneous DEH_WriteUndoline's. --- src/dehacked.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 4ac23b2e8..d1d21b340 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2731,13 +2731,11 @@ static void readmaincfg(MYFILE *f) else value = get_number(word2); - DEH_WriteUndoline(word, va("%d", titlemap), UNDO_NONE); titlemap = (INT16)value; titlechanged = true; } else if (fastcmp(word, "HIDETITLEPICS")) { - DEH_WriteUndoline(word, va("%d", hidetitlepics), UNDO_NONE); hidetitlepics = (boolean)(value || word2[0] == 'T' || word2[0] == 'Y'); titlechanged = true; } @@ -2827,7 +2825,6 @@ static void readmaincfg(MYFILE *f) else value = get_number(word2); - DEH_WriteUndoline(word, va("%d", bootmap), UNDO_NONE); bootmap = (INT16)value; //titlechanged = true; } From ca42659e037c318d57e70ce34c6af0c9974e90e4 Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Wed, 16 Aug 2017 20:01:24 +0100 Subject: [PATCH 61/61] Made a mistake in the directionchar branch. I'm pushing to master - naughty naughty - but nobody's around to stop me and it's my birthday c: --- src/p_user.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 4b4a542bc..60d4cd5b7 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9805,6 +9805,11 @@ void P_PlayerThink(player_t *player) factor = 4; #endif } + else if (player->pflags & PF_STARTDASH) + { + diff = (player->mo->angle - player->drawangle); + factor = 4; + } else if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys { diff = ((player->mo->angle + R_PointToAngle2(0, 0, cmd->forwardmove<sidemove<drawangle); @@ -9815,7 +9820,7 @@ void P_PlayerThink(player_t *player) else { diff = (player->mo->angle - player->drawangle); - factor = ((player->pflags & PF_STARTDASH) ? 4 : 8); + factor = 8; } if (diff)