From 9c73424b4b6038a90db53a44a5b8d4784b6fa4ea Mon Sep 17 00:00:00 2001 From: sphere Date: Sun, 14 Jul 2019 02:17:44 +0200 Subject: [PATCH 01/47] Add spring flags: float for horizontal & no gravity for diagonal. --- src/p_mobj.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index a57998ea0..0428dd83b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4662,7 +4662,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) } dz /= 9; - + while ((base = base->tracer)) // there are 10 per spoke, remember that { dx = (originx + P_ReturnThrustX(mobj, angle, (9*132)<x)/9; @@ -11964,6 +11964,15 @@ ML_EFFECT5 : Don't stop thinking when too far away if (i == MT_YELLOWDIAG || i == MT_REDDIAG) mobj->angle += ANGLE_22h; + if (i == MT_YELLOWHORIZ || i == MT_REDHORIZ || i == MT_BLUEHORIZ) + { + if (mthing->options & MTF_OBJECTFLIP) + mobj->z -= 16*FRACUNIT; + else + mobj->z += 16*FRACUNIT; + } + + if (mobj->flags & MF_NIGHTSITEM) { // Spawn already displayed @@ -11991,6 +12000,9 @@ ML_EFFECT5 : Don't stop thinking when too far away if (mthing->options & MTF_OBJECTSPECIAL) { + if (i == MT_YELLOWDIAG || i == MT_REDDIAG) + mobj->flags |= MF_NOGRAVITY; + if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) { // flag for strong/weak random boxes @@ -12570,9 +12582,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (mthing->options & MTF_AMBUSH) // Special flag for rings { if (mthing->options & MTF_OBJECTFLIP) - z -= 24*FRACUNIT; + z -= 64*FRACUNIT; else - z += 24*FRACUNIT; + z += 64*FRACUNIT; } mthing->z = (INT16)(z>>FRACBITS); From 911b0262ee77cdae5ac71df98496e3232fc1a4d4 Mon Sep 17 00:00:00 2001 From: sphere Date: Sun, 14 Jul 2019 02:31:33 +0200 Subject: [PATCH 02/47] Whoops, forgot to revert this. --- src/p_mobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 0428dd83b..d13b9a57c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12582,9 +12582,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (mthing->options & MTF_AMBUSH) // Special flag for rings { if (mthing->options & MTF_OBJECTFLIP) - z -= 64*FRACUNIT; + z -= 24*FRACUNIT; else - z += 64*FRACUNIT; + z += 24*FRACUNIT; } mthing->z = (INT16)(z>>FRACBITS); From cfc56c954144275ad94038e8c8462798ad486d5d Mon Sep 17 00:00:00 2001 From: sphere Date: Sun, 14 Jul 2019 15:30:00 +0200 Subject: [PATCH 03/47] Don't upscale the waving flags, make them twice as large instead --- src/info.c | 6 +++--- src/p_mobj.c | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/info.c b/src/info.c index 0cbe8d82e..08b1ab5e9 100644 --- a/src/info.c +++ b/src/info.c @@ -11278,8 +11278,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 4*FRACUNIT, // radius - 104*FRACUNIT, // height + 8*FRACUNIT, // radius + 208*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage @@ -11305,7 +11305,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 4*FRACUNIT, // radius + 8*FRACUNIT, // radius 1, // height -- this is not a typo 0, // display offset 100, // mass diff --git a/src/p_mobj.c b/src/p_mobj.c index a57998ea0..acc995dd0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4662,7 +4662,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) } dz /= 9; - + while ((base = base->tracer)) // there are 10 per spoke, remember that { dx = (originx + P_ReturnThrustX(mobj, angle, (9*132)<x)/9; @@ -9653,8 +9653,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { mobj_t *prev = mobj, *cur; UINT8 i; - mobj->destscale <<= 2; - P_SetScale(mobj, mobj->destscale); for (i = 0; i <= 16; i++) // probably should be < but staying authentic to the Lua version { cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_WAVINGFLAGSEG); From ee937c4df038b60614a248039bc7ed2914368b2c Mon Sep 17 00:00:00 2001 From: sphere Date: Sun, 14 Jul 2019 16:50:45 +0200 Subject: [PATCH 04/47] Add a blue variant of the waving flags. --- src/dehacked.c | 9 +++++--- src/info.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- src/info.h | 9 +++++--- src/p_mobj.c | 8 ++++--- 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 31c17f188..18d0b2243 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5708,7 +5708,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FLAMEHOLDER", "S_FIRETORCH", "S_WAVINGFLAG", - "S_WAVINGFLAGSEG", + "S_WAVINGFLAGSEG1", + "S_WAVINGFLAGSEG2", "S_CRAWLASTATUE", "S_FACESTABBERSTATUE", "S_SUSPICIOUSFACESTABBERSTATUE_WAIT", @@ -7523,8 +7524,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_CANDLEPRICKET", // Candle pricket "MT_FLAMEHOLDER", // Flame holder "MT_FIRETORCH", // Fire torch - "MT_WAVINGFLAG", // Waving flag - "MT_WAVINGFLAGSEG", // Waving flag segment + "MT_WAVINGFLAG1", // Waving flag (red) + "MT_WAVINGFLAG2", // Waving flag (blue) + "MT_WAVINGFLAGSEG1", // Waving flag segment (red) + "MT_WAVINGFLAGSEG2", // Waving flag segment (blue) "MT_CRAWLASTATUE", // Crawla statue "MT_FACESTABBERSTATUE", // Facestabber statue "MT_SUSPICIOUSFACESTABBERSTATUE", // :eggthinking: diff --git a/src/info.c b/src/info.c index 08b1ab5e9..4733329f3 100644 --- a/src/info.c +++ b/src/info.c @@ -2338,7 +2338,8 @@ state_t states[NUMSTATES] = {SPR_CTRC, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_FIRETORCH}, // S_FIRETORCH {SPR_CFLG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAG - {SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG + {SPR_CFLG, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG1 + {SPR_CFLG, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_WAVINGFLAGSEG2 {SPR_CSTA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CRAWLASTATUE @@ -11261,7 +11262,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_WAVINGFLAG + { // MT_WAVINGFLAG1 1118, // doomednum S_WAVINGFLAG, // spawnstate 1000, // spawnhealth @@ -11288,9 +11289,63 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_WAVINGFLAGSEG + { // MT_WAVINGFLAG2 + 1128, // doomednum + S_WAVINGFLAG, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 208*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_WAVINGFLAGSEG1 -1, // doomednum - S_WAVINGFLAGSEG, // spawnstate + S_WAVINGFLAGSEG1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 1, // height -- this is not a typo + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_WAVINGFLAGSEG2 + -1, // doomednum + S_WAVINGFLAGSEG2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound diff --git a/src/info.h b/src/info.h index 44f08a4e9..536034867 100644 --- a/src/info.h +++ b/src/info.h @@ -2467,7 +2467,8 @@ typedef enum state S_FLAMEHOLDER, S_FIRETORCH, S_WAVINGFLAG, - S_WAVINGFLAGSEG, + S_WAVINGFLAGSEG1, + S_WAVINGFLAGSEG2, S_CRAWLASTATUE, S_FACESTABBERSTATUE, S_SUSPICIOUSFACESTABBERSTATUE_WAIT, @@ -4304,8 +4305,10 @@ typedef enum mobj_type MT_CANDLEPRICKET, // Candle pricket MT_FLAMEHOLDER, // Flame holder MT_FIRETORCH, // Fire torch - MT_WAVINGFLAG, // Waving flag - MT_WAVINGFLAGSEG, // Waving flag segment + MT_WAVINGFLAG1, // Waving flag (red) + MT_WAVINGFLAG2, // Waving flag (blue) + MT_WAVINGFLAGSEG1, // Waving flag segment (red) + MT_WAVINGFLAGSEG2, // Waving flag segment (blue) MT_CRAWLASTATUE, // Crawla statue MT_FACESTABBERSTATUE, // Facestabber statue MT_SUSPICIOUSFACESTABBERSTATUE, // :eggthinking: diff --git a/src/p_mobj.c b/src/p_mobj.c index acc995dd0..5e0509a0f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8046,7 +8046,8 @@ void P_MobjThinker(mobj_t *mobj) mobj->tracer->z += mobj->height; } break; - case MT_WAVINGFLAG: + case MT_WAVINGFLAG1: + case MT_WAVINGFLAG2: { fixed_t base = (leveltime<<(FRACBITS+1)); mobj_t *seg = mobj->tracer, *prev = mobj; @@ -9649,13 +9650,14 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BIGMINE: mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; break; - case MT_WAVINGFLAG: + case MT_WAVINGFLAG1: + case MT_WAVINGFLAG2: { mobj_t *prev = mobj, *cur; UINT8 i; for (i = 0; i <= 16; i++) // probably should be < but staying authentic to the Lua version { - cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_WAVINGFLAGSEG); + cur = P_SpawnMobjFromMobj(mobj, 0, 0, 0, ((mobj->type == MT_WAVINGFLAG1) ? MT_WAVINGFLAGSEG1 : MT_WAVINGFLAGSEG2));; P_SetTarget(&prev->tracer, cur); cur->extravalue1 = i; prev = cur; From 79cf8eb08def9d48f770325bd2c3fb217ff1dc63 Mon Sep 17 00:00:00 2001 From: sphere Date: Sun, 14 Jul 2019 17:30:33 +0200 Subject: [PATCH 05/47] Add a blue variant of the pole banner & change some doomednums. --- src/dehacked.c | 9 ++++--- src/info.c | 69 +++++++++++++++++++++++++++++++++++++++++++++----- src/info.h | 9 ++++--- src/p_mobj.c | 5 ++-- 4 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 18d0b2243..01e2b0bde 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -5699,7 +5699,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_CEZFLOWER", "S_CEZPOLE", - "S_CEZBANNER", + "S_CEZBANNER1", + "S_CEZBANNER2", "S_PINETREE", "S_CEZBUSH1", "S_CEZBUSH2", @@ -7515,8 +7516,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SMALLFIREBAR", // Small Firebar "MT_BIGFIREBAR", // Big Firebar "MT_CEZFLOWER", // Flower - "MT_CEZPOLE", // Pole - "MT_CEZBANNER", // Banner + "MT_CEZPOLE1", // Pole (with red banner) + "MT_CEZPOLE2", // Pole (with blue banner) + "MT_CEZBANNER1", // Banner (red) + "MT_CEZBANNER2", // Banner (blue) "MT_PINETREE", // Pine Tree "MT_CEZBUSH1", // Bush 1 "MT_CEZBUSH2", // Bush 2 diff --git a/src/info.c b/src/info.c index 4733329f3..8796eca91 100644 --- a/src/info.c +++ b/src/info.c @@ -2322,9 +2322,10 @@ state_t states[NUMSTATES] = {SPR_BFBR, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_BIGFIREBAR1}, // S_BIGFIREBAR16 {SPR_FWR4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZFLOWER - {SPR_BANR, 1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE + {SPR_BANR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZPOLE - {SPR_BANR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER + {SPR_BANR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER1 + {SPR_BANR, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBANNER2 {SPR_PINE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE {SPR_CEZB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZBUSH1 @@ -11019,7 +11020,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_CEZPOLE + { // MT_CEZPOLE1 1117, // doomednum S_CEZPOLE, // spawnstate 1000, // spawnhealth @@ -11046,9 +11047,63 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_CEZBANNER + { // MT_CEZPOLE2 + 1118, // doomednum + S_CEZPOLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 40*FRACUNIT, // radius + 224*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CEZBANNER1 -1, // doomednum - S_CEZBANNER, // spawnstate + S_CEZBANNER1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 40*FRACUNIT, // radius + 224*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_CEZBANNER2 + -1, // doomednum + S_CEZBANNER2, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -11263,7 +11318,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_WAVINGFLAG1 - 1118, // doomednum + 1128, // doomednum S_WAVINGFLAG, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -11290,7 +11345,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_WAVINGFLAG2 - 1128, // doomednum + 1129, // doomednum S_WAVINGFLAG, // spawnstate 1000, // spawnhealth S_NULL, // seestate diff --git a/src/info.h b/src/info.h index 536034867..a9a0321ec 100644 --- a/src/info.h +++ b/src/info.h @@ -2458,7 +2458,8 @@ typedef enum state S_CEZFLOWER, S_CEZPOLE, - S_CEZBANNER, + S_CEZBANNER1, + S_CEZBANNER2, S_PINETREE, S_CEZBUSH1, S_CEZBUSH2, @@ -4296,8 +4297,10 @@ typedef enum mobj_type MT_SMALLFIREBAR, // Small Firebar MT_BIGFIREBAR, // Big Firebar MT_CEZFLOWER, // Flower - MT_CEZPOLE, // Pole - MT_CEZBANNER, // Banner + MT_CEZPOLE1, // Pole (with red banner) + MT_CEZPOLE2, // Pole (with blue banner) + MT_CEZBANNER1, // Banner (red) + MT_CEZBANNER2, // Banner (blue) MT_PINETREE, // Pine Tree MT_CEZBUSH1, // Bush 1 MT_CEZBUSH2, // Bush 2 diff --git a/src/p_mobj.c b/src/p_mobj.c index 5e0509a0f..396fd3583 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11737,13 +11737,14 @@ ML_EFFECT5 : Don't stop thinking when too far away P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; } break; - case MT_CEZPOLE: + case MT_CEZPOLE1: + case MT_CEZPOLE2: { // Spawn the banner angle_t mobjangle = FixedAngle(mthing->angle<angle = mobjangle + ANGLE_90; + 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90; } break; case MT_HHZTREE_TOP: From 438c4d1d51502c7cc81bb6379ac58988e47422cb Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 17 Jul 2019 21:33:18 +0100 Subject: [PATCH 06/47] Fix spindash being broken in quicksand # Conflicts: # src/p_mobj.c # src/p_user.c --- src/p_local.h | 2 +- src/p_mobj.c | 2 +- src/p_user.c | 160 ++++++++++++++++++++++++++------------------------ 3 files changed, 84 insertions(+), 80 deletions(-) diff --git a/src/p_local.h b/src/p_local.h index cb8f95533..3c62d6277 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -142,7 +142,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); +boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff); 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 9a6e0f2bb..a7ab4e30d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3047,7 +3047,7 @@ static void P_PlayerZMovement(mobj_t *mo) } } - clipmomz = P_PlayerHitFloor(mo->player); + clipmomz = P_PlayerHitFloor(mo->player, true); if (!(mo->player->pflags & PF_SPINNING) && mo->player->powers[pw_carry] != CR_NIGHTSMODE) mo->player->pflags &= ~PF_STARTDASH; diff --git a/src/p_user.c b/src/p_user.c index 6761d567d..3427ed168 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2007,7 +2007,7 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space // // Handles player hitting floor surface. // Returns whether to clip momz. -boolean P_PlayerHitFloor(player_t *player) +boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) { boolean clipmomz; @@ -2015,92 +2015,96 @@ boolean P_PlayerHitFloor(player_t *player) 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))) + if (dorollstuff) { - player->pflags |= PF_SPINNING; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_spin); + 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; } - else + + if (player->pflags & PF_GLIDING) // ground gliding { - player->pflags &= ~PF_SPINNING; - - if (player->pflags & PF_GLIDING) // ground gliding - { + if (!player->skidtime) 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)) + player->mo->tics = -1; + } + else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING)) + { + mobjtype_t type = player->revitem; + 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; + + // hearticles + if (type) { - mobjtype_t type = player->revitem; - 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; - - // hearticles - if (type) + UINT8 i = 0; + angle_t throwang = -(2*ANG30); + fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t zo = 6*player->mo->scale; + fixed_t mu = FixedMul(player->maxdash, player->mo->scale); + fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); + fixed_t ev; + mobj_t *missile; + if (mu2 < mu) + mu2 = mu; + ev = (50*FRACUNIT - (mu/25))/50; + while (i < 5) { - UINT8 i = 0; - angle_t throwang = -(2*ANG30); - fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t zo = 6*player->mo->scale; - fixed_t mu = FixedMul(player->maxdash, player->mo->scale); - fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); - fixed_t ev; - mobj_t *missile; - if (mu2 < mu) - mu2 = mu; - ev = (50*FRACUNIT - (mu/25))/50; - while (i < 5) - { - missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); - P_SetTarget(&missile->target, player->mo); - missile->angle = throwang + player->drawangle; - P_Thrust(missile, player->drawangle + ANGLE_90, - P_ReturnThrustY(missile, throwang, mu)); // side to side component - P_Thrust(missile, player->drawangle, mu2); // forward component - P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); - missile->fuse = TICRATE/2; - missile->extravalue2 = ev; + missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); + P_SetTarget(&missile->target, player->mo); + missile->angle = throwang + player->drawangle; + P_Thrust(missile, player->drawangle + ANGLE_90, + P_ReturnThrustY(missile, throwang, mu)); // side to side component + P_Thrust(missile, player->drawangle, mu2); // forward component + P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); + missile->fuse = TICRATE/2; + missile->extravalue2 = ev; - i++; - throwang += ANG30; - } - if (mobjinfo[type].seesound) - S_StartSound(missile, missile->info->seesound); + i++; + throwang += ANG30; } + if (mobjinfo[type].seesound) + S_StartSound(missile, missile->info->seesound); } - else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING) + } + else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) + ; + 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->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->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); } } @@ -2537,7 +2541,7 @@ static void P_CheckQuicksand(player_t *player) player->mo->z = ceilingheight - player->mo->height; if (player->mo->momz <= 0) - P_PlayerHitFloor(player); + P_PlayerHitFloor(player, false); } else { @@ -2549,7 +2553,7 @@ static void P_CheckQuicksand(player_t *player) player->mo->z = floorheight; if (player->mo->momz >= 0) - P_PlayerHitFloor(player); + P_PlayerHitFloor(player, false); } friction = abs(rover->master->v1->y - rover->master->v2->y)>>6; From 385d34e67ec7780d7fb57d2c7e00a78e4e04f56b Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Mon, 25 Sep 2017 20:35:04 +0100 Subject: [PATCH 07/47] * Make busting a FOF through any in-game means (or not providing a target sector to EV_CrumbleChain) bust all FOFs with the same control sector. * Make CA2_GUNSLINGER not get overridden by being in quicksand. --- src/lua_baselib.c | 4 ++-- src/p_floor.c | 46 +++++++++++++++++++++++++++++++++------------- src/p_mobj.c | 4 ++-- src/p_user.c | 4 ++-- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 1d69b238b..712bc4045 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2051,8 +2051,8 @@ static int lib_evCrumbleChain(lua_State *L) ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); NOHUD INLEVEL - if (!sec) - return LUA_ErrInvalid(L, "sector_t"); + /*if (!sec) + return LUA_ErrInvalid(L, "sector_t");*/ if (!rover) return LUA_ErrInvalid(L, "ffloor_t"); EV_CrumbleChain(sec, rover); diff --git a/src/p_floor.c b/src/p_floor.c index c01e568d0..0b20a3b17 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -3029,20 +3029,40 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) { - size_t i; - size_t leftmostvertex = 0, rightmostvertex = 0; - size_t topmostvertex = 0, bottommostvertex = 0; - fixed_t leftx, rightx; - fixed_t topy, bottomy; - fixed_t topz, bottomz; - fixed_t widthfactor = FRACUNIT, heightfactor = FRACUNIT; - fixed_t a, b, c; - mobjtype_t type = MT_ROCKCRUMBLE1; - fixed_t spacing = (32<master->frontsector + sector_t *controlsec = rover->master->frontsector; + + if (sec == NULL) + { + if (controlsec->numattached) + { + for (i = 0; i < controlsec->numattached; i++) + { + sec = §ors[controlsec->attached[i]]; + if (!sec->ffloors) + continue; + + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (rover->master->frontsector == controlsec) + EV_CrumbleChain(sec, rover); + } + } + } + return; + } + + leftmostvertex = rightmostvertex = topmostvertex = bottommostvertex = 0; + widthfactor = heightfactor = FRACUNIT; + spacing = (32<tag != 0) { diff --git a/src/p_mobj.c b/src/p_mobj.c index a7ab4e30d..6cfad95a0 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1784,7 +1784,7 @@ static void P_PushableCheckBustables(mobj_t *mo) continue; } - EV_CrumbleChain(node->m_sector, rover); + EV_CrumbleChain(NULL, rover); // node->m_sector // Run a linedef executor?? if (rover->master->flags & ML_EFFECT5) @@ -3129,7 +3129,7 @@ nightsdone: { // DO THE MARIO! if (rover->flags & FF_SHATTERBOTTOM) // Brick block! - EV_CrumbleChain(node->m_sector, rover); + EV_CrumbleChain(NULL, rover); // node->m_sector else // Question block! EV_MarioBlock(rover, node->m_sector, mo); } diff --git a/src/p_user.c b/src/p_user.c index 3427ed168..706260a61 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2033,7 +2033,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) 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)) + else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING) { mobjtype_t type = player->revitem; P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING); @@ -2324,7 +2324,7 @@ static void P_CheckBustableBlocks(player_t *player) //if (metalrecording) // G_RecordBustup(rover); - EV_CrumbleChain(node->m_sector, rover); + EV_CrumbleChain(NULL, rover); // node->m_sector // Run a linedef executor?? if (rover->master->flags & ML_EFFECT5) From 82acf2de6b8aa607cf84ce991f53b4386a92568f Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 17 Jul 2019 23:24:44 +0100 Subject: [PATCH 08/47] Fix Knuckles-in-quicksand messup. --- src/p_user.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 706260a61..9c4e5b6b9 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2029,9 +2029,13 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) if (player->pflags & PF_GLIDING) // ground gliding { - if (!player->skidtime) + if (dorollstuff) + { player->skidtime = TICRATE; - player->mo->tics = -1; + player->mo->tics = -1; + } + else + player->pflags &= ~PF_GLIDING; } else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING) { From 1d5e8e249e2195ea4e0c9c6d7a971bd494261aee Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 17 Jul 2019 23:25:49 +0100 Subject: [PATCH 09/47] Successfully cause landing events when the ground moves up to hit you, as opposed to just when you move down to the ground. --- src/p_map.c | 8 +++++++- src/p_user.c | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/p_map.c b/src/p_map.c index e78dd1e84..767370587 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2820,7 +2820,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y) static boolean P_ThingHeightClip(mobj_t *thing) { boolean floormoved; - fixed_t oldfloorz = thing->floorz; + fixed_t oldfloorz = thing->floorz, oldz = thing->z; ffloor_t *oldfloorrover = thing->floorrover; ffloor_t *oldceilingrover = thing->ceilingrover; boolean onfloor = P_IsObjectOnGround(thing);//(thing->z <= thing->floorz); @@ -2879,6 +2879,12 @@ static boolean P_ThingHeightClip(mobj_t *thing) thing->z = thing->ceilingz - thing->height; } + if (thing->z != oldz) + { + if (thing->player) + P_PlayerHitFloor(thing->player, false); + } + // debug: be sure it falls to the floor thing->eflags &= ~MFE_ONGROUND; diff --git a/src/p_user.c b/src/p_user.c index 9c4e5b6b9..1e293d24c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2069,6 +2069,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) P_ReturnThrustY(missile, throwang, mu)); // side to side component P_Thrust(missile, player->drawangle, mu2); // forward component P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); + missile->momz += player->mo->pmomz; missile->fuse = TICRATE/2; missile->extravalue2 = ev; @@ -4418,6 +4419,10 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) { player->mo->z += P_MobjFlip(player->mo); P_SetObjectMomZ(player->mo, player->mindash, false); + if (P_MobjFlip(player->mo)*player->mo->pmomz > 0) + player->mo->momz += player->mo->pmomz; // Add the platform's momentum to your jump. + else + player->mo->pmomz = 0; if (player->mo->eflags & MFE_UNDERWATER) player->mo->momz >>= 1; #if 0 From 64517a136229c251f3e6a94678909a94ff02b1b2 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 18 Jul 2019 00:16:01 +0100 Subject: [PATCH 10/47] Fix !150, too --- src/p_floor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_floor.c b/src/p_floor.c index 0b20a3b17..7887dc530 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -719,6 +719,8 @@ void T_ContinuousFalling(levelspecthink_t *faller) } } + P_CheckSector(faller->sector, false); // you might think this is irrelevant. you would be wrong + faller->sector->floorspeed = faller->speed*faller->direction; faller->sector->ceilspeed = 42; faller->sector->moved = true; From 6c2ef839c1cf3b6aca7797d76a73e09c273b907b Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Thu, 18 Jul 2019 22:42:46 -0400 Subject: [PATCH 11/47] New award rings linedef executor --- src/p_spec.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index 3cd0461e2..48079b9e5 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3916,6 +3916,21 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); } } + case 460: // Award rings + { + INT16 rings = (sides[line->sidenum[0]].textureoffset>>FRACBITS); + INT16 delay = (sides[line->sidenum[0]].rowoffset>>FRACBITS); + if (mo && mo->player) + { + if (delay > 0) + { + if (!(leveltime % (delay*TICRATE))) + P_GivePlayerRings(mo->player, rings); + } + else + P_GivePlayerRings(mo->player, rings); + } + } break; #ifdef POLYOBJECTS From 60ffef9830f82b4ac948e13e504da7d4906cc9c0 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Wed, 24 Jul 2019 21:18:07 -0400 Subject: [PATCH 12/47] More simplified code Also delay is in tics, per MS' request. --- src/p_spec.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 48079b9e5..f712f4b23 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3917,20 +3917,15 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } } case 460: // Award rings - { - INT16 rings = (sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT16 delay = (sides[line->sidenum[0]].rowoffset>>FRACBITS); - if (mo && mo->player) { - if (delay > 0) + INT16 rings = (sides[line->sidenum[0]].textureoffset>>FRACBITS); + tic_t delay = (sides[line->sidenum[0]].rowoffset>>FRACBITS); + if (mo && mo->player) { - if (!(leveltime % (delay*TICRATE))) + if (delay <= 0 || !(leveltime % (delay))) P_GivePlayerRings(mo->player, rings); } - else - P_GivePlayerRings(mo->player, rings); } - } break; #ifdef POLYOBJECTS From 063e350c63b244a97bd0c12ebb017267883bc3ab Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Jul 2019 00:32:57 +0100 Subject: [PATCH 13/47] A good and bad ending cutscene now exist. Also: * SPR2_XTRA - instead of defining lumpnames in S_SKIN, those kinds of assets can just be bundled into the spriteset. Required for ending cutscene stuff, I guess, but also done for HUD life icon and character select image (aside from Sonic&Tails, still SOC'd in). * Minor oversights in SPR2 support corrected. * Better evaluation, featuring ending assets. * Intro has warping-in blackrock, reusing ending assets. * Cutscene text now supports lowercase (intro and custom). * Disable the asset-fucking "gamma correction" I put in over two years ago when implementing colour cube. (This is the only thing I could move into another branch if you MUST, but it's basically invisble in the diff so w/e.) * Don't blank the screen if the top left pixel of a screen-covering patch is transparent. (Checked via nonzero topdelta for first column) Bugs: * OPENGL ONLY: The first ~20 frames of both endings are fucked. A little help here? Might be HWR_DrawFadeFill's fault, which I just created. OR it could be in f_finale, but I doubt it, since it doesn't appear in Software. --- src/console.c | 2 +- src/d_main.c | 6 + src/dehacked.c | 4 + src/f_finale.c | 750 ++++++++++++++++++++++++++++++++++++++--- src/f_finale.h | 10 +- src/f_wipe.c | 2 + src/g_game.c | 21 +- src/g_state.h | 4 +- src/hardware/hw_draw.c | 305 +++++++++++++++-- src/hardware/hw_main.h | 1 + src/hardware/hw_md2.c | 11 +- src/hu_stuff.c | 2 +- src/info.c | 12 +- src/info.h | 1 + src/lua_infolib.c | 25 +- src/lua_skinlib.c | 24 -- src/m_menu.c | 37 +- src/m_menu.h | 1 + src/p_setup.c | 2 +- src/r_things.c | 48 ++- src/r_things.h | 1 - src/s_sound.c | 12 +- src/st_stuff.c | 24 +- src/st_stuff.h | 2 +- src/v_video.c | 336 ++++++++++++++++-- src/v_video.h | 2 + 26 files changed, 1445 insertions(+), 200 deletions(-) diff --git a/src/console.c b/src/console.c index c1c5557b9..09a6cab45 100644 --- a/src/console.c +++ b/src/console.c @@ -1608,7 +1608,7 @@ void CON_Drawer(void) if (con_curlines > 0) CON_DrawConsole(); else if (gamestate == GS_LEVEL - || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE + || gamestate == GS_INTERMISSION || gamestate == GS_ENDING || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) CON_DrawHudlines(); } diff --git a/src/d_main.c b/src/d_main.c index c7d709aec..32e874f07 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -310,6 +310,12 @@ static void D_Display(void) wipe = true; break; + case GS_ENDING: + F_EndingDrawer(); + HU_Erase(); + HU_Drawer(); + break; + case GS_CUTSCENE: F_CutsceneDrawer(); HU_Erase(); diff --git a/src/dehacked.c b/src/dehacked.c index 31c17f188..b4e00de87 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -517,7 +517,9 @@ static void readfreeslots(MYFILE *f) continue; // Copy in the spr2 name and increment free_spr2. if (free_spr2 < NUMPLAYERSPRITES) { + CONS_Printf("Sprite SPR2_%s allocated.\n",word); strncpy(spr2names[free_spr2],word,4); + spr2defaults[free_spr2] = 0; spr2names[free_spr2++][4] = 0; } else CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); @@ -1108,6 +1110,7 @@ static void readlevelheader(MYFILE *f, INT32 num) if (fastcmp(word2, "TITLE")) i = 1100; else if (fastcmp(word2, "EVALUATION")) i = 1101; else if (fastcmp(word2, "CREDITS")) i = 1102; + else if (fastcmp(word2, "ENDING")) i = 1103; else // Support using the actual map name, // i.e., Nextlevel = AB, Nextlevel = FZ, etc. @@ -9493,6 +9496,7 @@ static inline int lib_freeslot(lua_State *L) { CONS_Printf("Sprite SPR2_%s allocated.\n",word); strncpy(spr2names[free_spr2],word,4); + spr2defaults[free_spr2] = 0; spr2names[free_spr2++][4] = 0; } else CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); diff --git a/src/f_finale.c b/src/f_finale.c index 27c9ebd68..bac50dcec 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -14,6 +14,7 @@ #include "doomdef.h" #include "doomstat.h" #include "d_main.h" +#include "d_netcmd.h" #include "f_finale.h" #include "g_game.h" #include "hu_stuff.h" @@ -36,6 +37,7 @@ #include "p_setup.h" #include "st_stuff.h" // hud hiding #include "fastcmp.h" +#include "console.h" #ifdef HAVE_BLUA #include "lua_hud.h" @@ -53,7 +55,6 @@ static INT32 continuetime; // Short delay when continuing static tic_t animtimer; // Used for some animation timings static INT16 skullAnimCounter; // Prompts: Chevron animation -static INT32 roidtics; // Asteroid spinning static INT32 deplete; static tic_t stoptimer; @@ -95,6 +96,17 @@ static patch_t *ttspop5; static patch_t *ttspop6; static patch_t *ttspop7; +static boolean goodending; +static patch_t *endbrdr[2]; // border - blue, white, pink - where have i seen those colours before? +static patch_t *endbgsp[3]; // nebula, sun, planet +static patch_t *endegrk[2]; // eggrock - replaced midway through good ending +static patch_t *endfwrk[3]; // firework - replaced with skin when good ending +static patch_t *endspkl[3]; // sparkle +static patch_t *endglow[2]; // glow aura - replaced with black rock's midway through good ending +static patch_t *endxpld[4]; // mini explosion +static INT32 sparkloffs[8][3][2]; // seven emerald sparkles + eggrock explosions +static INT32 sparklloop; + // // PROMPT STATE // @@ -230,6 +242,7 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset void F_StartIntro(void) { S_StopMusic(); + S_StopSounds(); if (introtoplay) { @@ -393,7 +406,6 @@ void F_StartIntro(void) intro_scenenum = 0; finalecount = animtimer = skullAnimCounter = stoptimer = 0; - roidtics = BASEVIDWIDTH - 64; timetonext = introscenetime[intro_scenenum]; } @@ -676,11 +688,42 @@ static void F_IntroDrawScene(void) if (intro_scenenum == 4) // The asteroid SPINS! { - if (roidtics >= 0) + if (intro_curtime > 1) { - V_DrawScaledPatch(roidtics, 24, 0, - (patch = W_CachePatchName(va("ROID00%.2d", intro_curtime%35), PU_CACHE))); - W_UnlockCachedPatch(patch); + INT32 worktics = intro_curtime - 1; + INT32 scale = FRACUNIT; + patch_t *rockpat; + UINT8 *colormap = NULL; + patch_t *glow; + INT32 trans = 0; + + INT32 x = ((BASEVIDWIDTH - 64)<= 5) + trans = (worktics-5)>>1; + if (trans < 10) + V_DrawFixedPatch(x, y, scale, trans<type != ev_keydown) @@ -1240,10 +1279,8 @@ boolean F_CreditResponder(event_t *event) // ============ // EVALUATION // ============ -#define INTERVAL 50 +#define INTERVAL (360/7) #define TRANSLEVEL V_80TRANS -static INT32 eemeralds_start; -static boolean drawemblem = false, drawchaosemblem = false; void F_StartGameEvaluation(void) { @@ -1265,17 +1302,18 @@ void F_StartGameEvaluation(void) if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) G_SaveGame((UINT32)cursaveslot); + goodending = (ALL7EMERALDS(emeralds)); + gameaction = ga_nothing; paused = false; CON_ToggleOff(); - finalecount = 0; + finalecount = -1; } void F_GameEvaluationDrawer(void) { INT32 x, y, i; - const fixed_t radius = 48*FRACUNIT; angle_t fa; INT32 eemeralds_cur; char patchname[7] = "CEMGx0"; @@ -1283,57 +1321,94 @@ void F_GameEvaluationDrawer(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Draw all the good crap here. - if (ALL7EMERALDS(emeralds)) + if (goodending) V_DrawString(114, 16, 0, "GOT THEM ALL!"); else V_DrawString(124, 16, 0, "TRY AGAIN!"); - eemeralds_start++; - eemeralds_cur = eemeralds_start; + if (finalecount > 0) + { + INT32 scale = FRACUNIT; + patch_t *rockpat; + UINT8 *colormap[2] = {NULL, NULL}; + patch_t *glow; + INT32 trans = 0; + + x = (((BASEVIDWIDTH-82)/2)+11)<= 5) + trans = (finalecount-5)>>1; + if (trans < 10) + V_DrawFixedPatch(x, y, scale, trans<>ANGLETOFINESHIFT) & FINEMASK; - x = 160 + FixedInt(FixedMul(FINECOSINE(fa),radius)); - y = 100 + FixedInt(FixedMul(FINESINE(fa),radius)); + x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINECOSINE(fa)); + y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + (60*FINESINE(fa)); + eemeralds_cur += INTERVAL; + if (i & 1) + eemeralds_cur++; patchname[4] = 'A'+(char)i; - if (emeralds & (1<= 360) - eemeralds_start -= 360; - - if (finalecount == 5*TICRATE) - { - if ((!modifiedgame || savemoddata) && !(netgame || multiplayer)) - { - ++timesBeaten; - - if (ALL7EMERALDS(emeralds)) - ++timesBeatenWithEmeralds; - - if (ultimatemode) - ++timesBeatenUltimate; - - if (M_UpdateUnlockablesAndExtraEmblems()) - S_StartSound(NULL, sfx_s3k68); - - G_SaveGameData(); - } + V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<= 5*TICRATE) { +#if 0 if (drawemblem) V_DrawScaledPatch(120, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE)); if (drawchaosemblem) V_DrawScaledPatch(200, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE)); +#endif V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); @@ -1363,10 +1438,579 @@ void F_GameEvaluationTicker(void) { finalecount++; + if (sparklloop) + sparklloop--; + + if (!goodending + && (finalecount == (5*TICRATE)/2 + || finalecount == (7*TICRATE)/2 + || finalecount == ((7*TICRATE)/2)+5)) + { + S_StartSound(NULL, sfx_s3k5c); + sparklloop = 10; + } + + if (finalecount == 5*TICRATE) + { + if ((!modifiedgame || savemoddata) && !(netgame || multiplayer)) + { + ++timesBeaten; + + if (ALL7EMERALDS(emeralds)) + ++timesBeatenWithEmeralds; + + if (ultimatemode) + ++timesBeatenUltimate; + + if (M_UpdateUnlockablesAndExtraEmblems()) + S_StartSound(NULL, sfx_s3k68); + + G_SaveGameData(); + } + } + if (finalecount > 10*TICRATE) F_StartGameEnd(); } +// ========== +// ENDING +// ========== + +void F_StartEnding(void) +{ + G_SetGamestate(GS_ENDING); + wipetypepost = INT16_MAX; + + // Just in case they're open ... somehow + M_ClearMenus(true); + + // Save before the credits sequence. + if ((!modifiedgame || savemoddata) && !(netgame || multiplayer) && cursaveslot > 0) + G_SaveGame((UINT32)cursaveslot); + + gameaction = ga_nothing; + paused = false; + CON_ToggleOff(); + S_StopMusic(); // todo: placeholder + S_StopSounds(); + + finalecount = -10; // what? this totally isn't a hack. why are you asking? + + memset(sparkloffs, 0, sizeof(INT32)*8*3*2); + sparklloop = 0; + + endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_LEVEL); + + endegrk[0] = W_CachePatchName("ENDEGRK0", PU_LEVEL); + endegrk[1] = W_CachePatchName("ENDEGRK1", PU_LEVEL); + + endglow[0] = W_CachePatchName("ENDGLOW0", PU_LEVEL); + endglow[1] = W_CachePatchName("ENDGLOW1", PU_LEVEL); + + endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_LEVEL); + endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_LEVEL); + endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_LEVEL); + + endspkl[0] = W_CachePatchName("ENDSPKL0", PU_LEVEL); + endspkl[1] = W_CachePatchName("ENDSPKL1", PU_LEVEL); + endspkl[2] = W_CachePatchName("ENDSPKL2", PU_LEVEL); + + endxpld[0] = W_CachePatchName("ENDXPLD0", PU_LEVEL); + endxpld[1] = W_CachePatchName("ENDXPLD1", PU_LEVEL); + endxpld[2] = W_CachePatchName("ENDXPLD2", PU_LEVEL); + endxpld[3] = W_CachePatchName("ENDXPLD3", PU_LEVEL); + + // so we only need to check once + if ((goodending = ALL7EMERALDS(emeralds))) + { + UINT8 skinnum = players[consoleplayer].skin; + spritedef_t *sprdef; + spriteframe_t *sprframe; + if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 5) + { + sprdef = &skins[skinnum].sprites[SPR2_XTRA]; + // character head, skin specific + sprframe = &sprdef->spriteframes[2]; + endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); + sprframe = &sprdef->spriteframes[3]; + endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); + sprframe = &sprdef->spriteframes[4]; + endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_LEVEL); + } + else // eh, yknow what? too lazy to put MISSINGs here. eggman wins if you don't give your character an ending firework display. + { + endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_LEVEL); + endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_LEVEL); + endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_LEVEL); + } + + endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_LEVEL); + } + else + { + // eggman, skin nonspecific + endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_LEVEL); + endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_LEVEL); + endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_LEVEL); + + endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_LEVEL); + } + +#define colset(map, a, b, c) \ + map[1] = (UINT8)a;\ + map[3] = (UINT8)b;\ + map[9] = (UINT8)c + + colset(purplemap, 164, 165, 169); +} + +#define SPARKLLOOPTIME 15 // must be odd +#define INFLECTIONPOINT (6*TICRATE) + +void F_EndingTicker(void) +{ + angle_t workingangle; + fixed_t workingradius; + + if (++finalecount == INFLECTIONPOINT && goodending) // time to swap some assets + { + Z_Free(endegrk[0]); + endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL); + Z_Free(endegrk[1]); + endegrk[1] = W_CachePatchName("ENDEGRK3", PU_LEVEL); + + Z_Free(endglow[0]); + endglow[0] = W_CachePatchName("ENDGLOW2", PU_LEVEL); + Z_Free(endglow[1]); + endglow[1] = W_CachePatchName("ENDGLOW3", PU_LEVEL); + + Z_Free(endxpld[0]); + endxpld[0] = W_CachePatchName("ENDEGRK4", PU_LEVEL); + } + + if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again + { + sparklloop = 0; + if (goodending) + { + UINT8 i; + for (i = 0; i < 7; ++i) + { + sparkloffs[i][2][0] = sparkloffs[i][1][0]; + sparkloffs[i][2][1] = sparkloffs[i][1][1]; + sparkloffs[i][1][0] = sparkloffs[i][0][0]; + sparkloffs[i][1][1] = sparkloffs[i][0][1]; + sparkloffs[i][0][0] = M_RandomRange(-11, 11)<>ANGLETOFINESHIFT; + workingradius = M_RandomKey(26); + sparkloffs[7][0][0] = (30< INFLECTIONPOINT*2) + { + F_StartCredits(); + wipetypepre = INT16_MAX; + colset(purplemap, 160, 161, 163); +#undef colset + } +} + +void F_EndingDrawer(void) +{ + INT32 x, y, i, j, parallaxticker; + patch_t *rockpat; + + if (!goodending || finalecount < INFLECTIONPOINT) + rockpat = W_CachePatchName("ROID0000", PU_LEVEL); + else + rockpat = W_CachePatchName(va("ROID00%.2d", (finalecount - INFLECTIONPOINT)%35), PU_LEVEL); + + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + + parallaxticker = finalecount - INFLECTIONPOINT; + x = -((parallaxticker*20)< 0) // gunchedrock + { + if (parallaxticker < 10) + { + tweakx = parallaxticker<>2; + UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JET, GTC_CACHE); +#endif + + x <<= 1; + y <<= 1; + + // center detritrus + V_DrawFixedPatch(i-x, j-y, FRACUNIT, 0, endegrk[0], +#ifdef TFTMOPTIMUSFADE + colormap); + if (trans < 10) + V_DrawFixedPatch(i-x, j-y, FRACUNIT, trans< 0) + { + i -= (3+(tweakx<<1)); + j += tweaky<<2; + } + + if (parallaxticker <= 70) + { + INT32 trans; + fixed_t scale = FRACUNIT; + UINT8 *colormap[2] = {NULL, NULL}; + + x += i; + y += j; + + if (parallaxticker > 66) + { + scale = ((70 - parallaxticker)<<(FRACBITS-2)); + x += (30*(FRACUNIT-scale)); + y += (30*(FRACUNIT-scale)); + } + else if ((parallaxticker > 60) || (goodending && parallaxticker > 0)) + ; + else + { + doexplosions = true; + if (!sparklloop) + { + x += ((sparkloffs[7][0][0] < 30< INFLECTIONPOINT) + parallaxticker -= 40; + + if ((-parallaxticker/4) < 5) + { + trans = (-parallaxticker/4) + 5; + if (trans < 0) + trans = 0; + V_DrawFixedPatch(x, y, scale, trans< INFLECTIONPOINT) + { + if (finalecount < INFLECTIONPOINT+10) + V_DrawFadeFill(24, 24, BASEVIDWIDTH-48, BASEVIDHEIGHT-48, 0, 0, INFLECTIONPOINT+10-finalecount); + parallaxticker -= 30; + } + + if ((parallaxticker/2) > -15) + colormap[0] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); + V_DrawFixedPatch(x, y, scale, 0, rockpat, colormap[0]); + if ((parallaxticker/2) > -25) + { + trans = (parallaxticker/2) + 15; + if (trans < 0) + trans = -trans; + if (trans < 10) + V_DrawFixedPatch(x, y, scale, trans< INFLECTIONPOINT) + { + if (finalecount < INFLECTIONPOINT+10) + V_DrawFixedPatch(x, y, scale, (finalecount-INFLECTIONPOINT)<= 3 && doexplosions) + { + INT32 boomtime = parallaxticker - sparklloop; + + x = ((((BASEVIDWIDTH-82)/2)+11)< INFLECTIONPOINT && finalecount < INFLECTIONPOINT+10) + V_DrawScaledPatch(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, (finalecount-INFLECTIONPOINT)<= TICRATE && finalecount < INFLECTIONPOINT) + { + INT32 workingtime = finalecount - TICRATE; + fixed_t radius[4]; + angle_t fa; + INT32 eemeralds_cur[4]; + char patchname[7] = "CEMGx0"; + + for (i = 0; i < 4; ++i) + { + if (i == 1) + workingtime -= sparklloop; + else if (i) + workingtime -= SPARKLLOOPTIME; + eemeralds_cur[i] = workingtime % 360; + radius[i] = ((vid.width/vid.dupx)*(INFLECTIONPOINT - TICRATE - workingtime))/(INFLECTIONPOINT - TICRATE); + radius[i] <<= FRACBITS; + } + + for (i = 0; i < 7; ++i) + { + fa = (FixedAngle(eemeralds_cur[0]*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; + x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius[0]); + y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius[0]); + eemeralds_cur[0] += INTERVAL; + if (i & 1) + eemeralds_cur[0]++; + + patchname[4] = 'A'+(char)i; + V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_LEVEL), NULL); + } + for (i = 0; i < 7; ++i) + { + UINT8* colormap; + skincolors_t col = SKINCOLOR_GREEN; + switch (i) + { + case 1: + col = SKINCOLOR_MAGENTA; + break; + case 2: + col = SKINCOLOR_BLUE; + break; + case 3: + col = SKINCOLOR_SKY; + break; + case 4: + col = SKINCOLOR_ORANGE; + break; + case 5: + col = SKINCOLOR_RED; + break; + case 6: + col = SKINCOLOR_GREY; + default: + case 0: + break; + } + + colormap = R_GetTranslationColormap(TC_DEFAULT, col, GTC_CACHE); + + j = (sparklloop & 1) ? 2 : 3; + while (j) + { + fa = (FixedAngle(eemeralds_cur[j]*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; + x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius[j]) + sparkloffs[i][j-1][0]; + y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius[j]) + sparkloffs[i][j-1][1]; + eemeralds_cur[j] += INTERVAL; + if (i & 1) + eemeralds_cur[j]++; + + // if j == 0 - alternate between 0 and 1 + // 1 - 1 and 2 + // 2 - 2 and not rendered + V_DrawFixedPatch(x, y, FRACUNIT, 0, endspkl[(j - ((sparklloop & 1) ? 0 : 1))], colormap); + + j--; + } + } + } // if (goodending... + } // (finalecount > 20) + + // look, i make an ending for you last-minute, the least you could do is let me have this + if (cv_soundtest.value == 413) + { + INT32 trans = 0; + boolean donttouch = false; + const char *str; + if (goodending) + str = va("[S] %s: Engage.", skins[players[consoleplayer].skin].realname); + else + str = "[S] Eggman: Abscond."; + + if (finalecount < 10) + trans = (10-finalecount)/2; + else if (finalecount > (2*INFLECTIONPOINT) - 20) + { + trans = 10 + (finalecount/2) - INFLECTIONPOINT; + donttouch = true; + } + + if (trans != 10) + { + V_DrawCenteredString(BASEVIDWIDTH/2, 8, V_ALLOWLOWERCASE|(trans<'|(trans<= (2*INFLECTIONPOINT)-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); + } + + if (finalecount > (2*INFLECTIONPOINT)-(20+(2*TICRATE))) + { + INT32 trans2 = abs((5*FINECOSINE((FixedAngle((finalecount*5)<>ANGLETOFINESHIFT & FINEMASK)))>>FRACBITS)+2; + if (!donttouch) + { + trans = 10 + ((2*INFLECTIONPOINT)-(20+(2*TICRATE))) - finalecount; + if (trans > trans2) + trans2 = trans; + } + else + trans2 += 2*trans; + if (trans2 < 10) + V_DrawCharacter(26, BASEVIDHEIGHT-33, '\x1C'|(trans2<scene[scenenum].musswitchposition, 0, 0); else S_StopMusic(); + S_StopSounds(); } // @@ -2044,7 +2690,7 @@ void F_CutsceneDrawer(void) F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true); } - V_DrawString(textxpos, textypos, 0, cutscene_disptext); + V_DrawString(textxpos, textypos, V_ALLOWLOWERCASE, cutscene_disptext); } void F_CutsceneTicker(void) diff --git a/src/f_finale.h b/src/f_finale.h index c0c6360c3..0d5bc2475 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -46,6 +46,9 @@ void F_GameEvaluationDrawer(void); void F_StartGameEvaluation(void); void F_GameEvaluationTicker(void); +void F_EndingTicker(void); +void F_EndingDrawer(void); + void F_CreditTicker(void); void F_CreditDrawer(void); @@ -63,6 +66,7 @@ boolean F_GetPromptHideHud(fixed_t y); void F_StartGameEnd(void); void F_StartIntro(void); void F_StartTitleScreen(void); +void F_StartEnding(void); void F_StartCredits(void); boolean F_ContinueResponder(event_t *event); @@ -126,6 +130,7 @@ enum wipe_evaluation_toblack, wipe_gameend_toblack, wipe_intro_toblack, + wipe_ending_toblack, wipe_cutscene_toblack, // custom intermissions @@ -142,15 +147,16 @@ enum wipe_evaluation_final, wipe_gameend_final, wipe_intro_final, + wipe_ending_final, wipe_cutscene_final, // custom intermissions wipe_specinter_final, wipe_multinter_final, - NUMWIPEDEFS + NUMWIPEDEFS, + WIPEFINALSHIFT = (wipe_level_final-wipe_level_toblack) }; -#define WIPEFINALSHIFT 13 extern UINT8 wipedefs[NUMWIPEDEFS]; #endif diff --git a/src/f_wipe.c b/src/f_wipe.c index 26c65ad91..05229f844 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -54,6 +54,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = { 0, // wipe_evaluation_toblack 0, // wipe_gameend_toblack 99, // wipe_intro_toblack (hardcoded) + 0, // wipe_ending_toblack 99, // wipe_cutscene_toblack (hardcoded) 0, // wipe_specinter_toblack @@ -69,6 +70,7 @@ UINT8 wipedefs[NUMWIPEDEFS] = { 0, // wipe_evaluation_final 0, // wipe_gameend_final 99, // wipe_intro_final (hardcoded) + 0, // wipe_ending_final 99, // wipe_cutscene_final (hardcoded) 0, // wipe_specinter_final diff --git a/src/g_game.c b/src/g_game.c index 95cc2288d..c6af0f48d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1842,7 +1842,7 @@ boolean G_Responder(event_t *ev) return true; } } - else if (gamestate == GS_CREDITS) + else if (gamestate == GS_CREDITS || gamestate == GS_ENDING) // todo: keep ending here? { if (HU_Responder(ev)) return true; // chat ate the event @@ -2032,6 +2032,12 @@ void G_Ticker(boolean run) F_IntroTicker(); break; + case GS_ENDING: + if (run) + F_EndingTicker(); + HU_Ticker(); + break; + case GS_CUTSCENE: if (run) F_CutsceneTicker(); @@ -2849,6 +2855,10 @@ void G_ExitLevel(void) // Remove CEcho text on round end. HU_ClearCEcho(); } + else if (gamestate == GS_ENDING) + { + F_StartCredits(); + } else if (gamestate == GS_CREDITS) { F_StartGameEvaluation(); @@ -3116,7 +3126,7 @@ static void G_DoCompleted(void) nextmap = cm; } - if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1102-1) + if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); // wrap around in race @@ -3282,6 +3292,11 @@ void G_EndGame(void) // Only do evaluation and credits in coop games. if (gametype == GT_COOP) { + if (nextmap == 1103-1) // end game with ending + { + F_StartEnding(); + return; + } if (nextmap == 1102-1) // end game with credits { F_StartCredits(); @@ -3700,7 +3715,7 @@ void G_SaveGame(UINT32 slot) backup = va("%s",savename); // save during evaluation or credits? game's over, folks! - if (gamestate == GS_CREDITS || gamestate == GS_EVALUATION) + if (gamestate == GS_ENDING || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) gamecomplete = true; gameaction = ga_nothing; diff --git a/src/g_state.h b/src/g_state.h index 76c9bd16f..dd08c4a83 100644 --- a/src/g_state.h +++ b/src/g_state.h @@ -27,12 +27,14 @@ typedef enum GS_TITLESCREEN, // title screen GS_TIMEATTACK, // time attack menu + GS_CREDITS, // credit sequence GS_EVALUATION, // Evaluation at the end of a game. - GS_GAMEEND, // game end sequence + GS_GAMEEND, // game end sequence - "did you get all those chaos emeralds?" // Hardcoded fades or other fading methods GS_INTRO, // introduction + GS_ENDING, // currently shared between bad and good endings GS_CUTSCENE, // custom cutscene // Not fadable diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index dd9fa8423..6bfd2a4dc 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -283,7 +283,7 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, if (!(option & V_SCALEPATCHMASK)) { - // if it's meant to cover the whole screen, black out the rest + // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) // cx and cy are possibly *slightly* off from float maths // This is done before here compared to software because we directly alter cx and cy to centre if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) @@ -291,8 +291,11 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, // Need to temporarily cache the real patch to get the colour of the top left pixel patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); - const UINT8 *source = (const UINT8 *)(column) + 3; - HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + if (!column->topdelta) + { + const UINT8 *source = (const UINT8 *)(column) + 3; + HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + } Z_Free(realpatch); } // centre screen @@ -439,7 +442,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal if (!(option & V_SCALEPATCHMASK)) { - // if it's meant to cover the whole screen, black out the rest + // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) // cx and cy are possibly *slightly* off from float maths // This is done before here compared to software because we directly alter cx and cy to centre if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) @@ -447,8 +450,11 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // Need to temporarily cache the real patch to get the colour of the top left pixel patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); - const UINT8 *source = (const UINT8 *)(column) + 3; - HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + if (!column->topdelta) + { + const UINT8 *source = (const UINT8 *)(column) + 3; + HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + } Z_Free(realpatch); } // centre screen @@ -683,12 +689,191 @@ void HWR_FadeScreenMenuBack(UINT16 color, UINT8 strength) } else // Do TRANSMAP** fade. { - Surf.FlatColor.rgba = pLocalPalette[color].rgba; - Surf.FlatColor.s.alpha = (UINT8)(strength*25.5f); + Surf.FlatColor.rgba = V_GetColor(color).rgba; + Surf.FlatColor.s.alpha = softwaretranstogl[strength]; } HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } +// -----------------+ +// HWR_DrawFadeFill : draw flat coloured rectangle, with transparency +// -----------------+ +void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength) +{ + FOutVector v[4]; + FSurfaceInfo Surf; + float fx, fy, fw, fh; + + UINT8 perplayershuffle = 0; + + if (w < 0 || h < 0) + return; // consistency w/ software + +// 3--2 +// | /| +// |/ | +// 0--1 + + if (splitscreen && (color & V_PERPLAYER)) + { + fixed_t adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + h >>= 1; + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + w >>= 1; + x >>= 1; + if (stplyr == &players[displayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + color &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } + else if (stplyr == &players[secondarydisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + color &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + y += adjusty; + color &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + y += adjusty; + color &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + color &= ~V_SNAPTOBOTTOM; + } + else //if (stplyr == &players[secondarydisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + y += adjusty; + color &= ~V_SNAPTOTOP; + } + } + } + + fx = (float)x; + fy = (float)y; + fw = (float)w; + fh = (float)h; + + if (!(color & V_NOSCALESTART)) + { + float dupx = (float)vid.dupx, dupy = (float)vid.dupy; + + fx *= dupx; + fy *= dupy; + fw *= dupx; + fh *= dupy; + + if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) + { + if (color & V_SNAPTORIGHT) + fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); + else if (!(color & V_SNAPTOLEFT)) + fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2; + if (perplayershuffle & 4) + fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4; + else if (perplayershuffle & 8) + fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4; + } + if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f) + { + // same thing here + if (color & V_SNAPTOBOTTOM) + fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); + else if (!(color & V_SNAPTOTOP)) + fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2; + if (perplayershuffle & 1) + fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4; + else if (perplayershuffle & 2) + fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4; + } + } + + if (fx >= vid.width || fy >= vid.height) + return; + if (fx < 0) + { + fw += fx; + fx = 0; + } + if (fy < 0) + { + fh += fy; + fy = 0; + } + + if (fw <= 0 || fh <= 0) + return; + if (fx + fw > vid.width) + fw = (float)vid.width - fx; + if (fy + fh > vid.height) + fh = (float)vid.height - fy; + + fx = -1 + fx / (vid.width / 2); + fy = 1 - fy / (vid.height / 2); + fw = fw / (vid.width / 2); + fh = fh / (vid.height / 2); + + v[0].x = v[3].x = fx; + v[2].x = v[1].x = fx + fw; + v[0].y = v[1].y = fy; + v[2].y = v[3].y = fy - fh; + + //Hurdler: do we still use this argb color? if not, we should remove it + v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //; + v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; + + v[0].sow = v[3].sow = 0.0f; + v[2].sow = v[1].sow = 1.0f; + v[0].tow = v[1].tow = 0.0f; + v[2].tow = v[3].tow = 1.0f; + + if (actualcolor & 0xFF00) // Do COLORMAP fade. + { + Surf.FlatColor.rgba = UINT2RGBA(0x01010160); + Surf.FlatColor.s.alpha = (strength*8); + } + else // Do TRANSMAP** fade. + { + Surf.FlatColor.rgba = V_GetColor(actualcolor).rgba; + Surf.FlatColor.s.alpha = softwaretranstogl[strength]; + } + + HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); +} + // Draw the console background with translucency support void HWR_DrawConsoleBack(UINT32 color, INT32 height) { @@ -905,6 +1090,8 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 FSurfaceInfo Surf; float fx, fy, fw, fh; + UINT8 perplayershuffle = 0; + if (w < 0 || h < 0) return; // consistency w/ software @@ -913,46 +1100,110 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 // |/ | // 0--1 + if (splitscreen && (color & V_PERPLAYER)) + { + fixed_t adjusty = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + h >>= 1; + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((color & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f; + w >>= 1; + x >>= 1; + if (stplyr == &players[displayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + color &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } + else if (stplyr == &players[secondarydisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + color &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + y += adjusty; + color &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(color & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + y += adjusty; + color &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + color &= ~V_SNAPTOBOTTOM; + } + else //if (stplyr == &players[secondarydisplayplayer]) + { + if (!(color & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + y += adjusty; + color &= ~V_SNAPTOTOP; + } + } + } + fx = (float)x; fy = (float)y; fw = (float)w; fh = (float)h; - if (!(options & V_NOSCALESTART)) + if (!(color & V_NOSCALESTART)) { float dupx = (float)vid.dupx, dupy = (float)vid.dupy; - if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) - { - RGBA_t rgbaColour = V_GetColor(color); - FRGBAFloat clearColour; - clearColour.red = (float)rgbaColour.s.red / 255; - clearColour.green = (float)rgbaColour.s.green / 255; - clearColour.blue = (float)rgbaColour.s.blue / 255; - clearColour.alpha = 1; - HWD.pfnClearBuffer(true, false, &clearColour); - return; - } - fx *= dupx; fy *= dupy; fw *= dupx; fh *= dupy; - if (fabsf((float)vid.width - ((float)BASEVIDWIDTH * dupx)) > 1.0E-36f) + if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) { - if (options & V_SNAPTORIGHT) + if (color & V_SNAPTORIGHT) fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); - else if (!(options & V_SNAPTOLEFT)) + else if (!(color & V_SNAPTOLEFT)) fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2; + if (perplayershuffle & 4) + fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4; + else if (perplayershuffle & 8) + fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4; } - if (fabsf((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) > 1.0E-36f) + if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f) { // same thing here - if (options & V_SNAPTOBOTTOM) + if (color & V_SNAPTOBOTTOM) fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)); - else if (!(options & V_SNAPTOTOP)) + else if (!(color & V_SNAPTOTOP)) fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2; + if (perplayershuffle & 1) + fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4; + else if (perplayershuffle & 2) + fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4; } } diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index fdfc1d257..fab18e08a 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -49,6 +49,7 @@ void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum); void HWR_PrepLevelCache(size_t pnumtextures); void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color); +void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength); void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 options); // Lat: separate flags from color since color needs to be an uint to work right. void HWR_DrawPic(INT32 x,INT32 y,lumpnum_t lumpnum); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index e26aa98ff..c2faa8b86 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1198,6 +1198,9 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p if (!md2 || !skin) return 0; + if ((spr2 & ~FF_SPR2SUPER) >= free_spr2) + return 0; + while (!(md2->model->spr2frames[spr2*2 + 1]) && spr2 != SPR2_STND && ++i != 32) // recursion limiter @@ -1220,7 +1223,10 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; break; case SPR2_TIRE: - spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; + spr2 = ((player + ? player->charability + : skin->ability) + == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; break; // Use the handy list, that's what it's there for! @@ -1232,6 +1238,9 @@ static UINT8 P_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t *p spr2 |= super; } + if (i >= 32) // probably an infinite loop... + return 0; + return spr2; } diff --git a/src/hu_stuff.c b/src/hu_stuff.c index f86100e27..3bc643c3c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2138,7 +2138,7 @@ void HU_Drawer(void) if (!Playing() || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS || gamestate == GS_EVALUATION - || gamestate == GS_GAMEEND) + || gamestate == GS_ENDING || gamestate == GS_GAMEEND) return; // draw multiplayer rankings diff --git a/src/info.c b/src/info.c index 7606f27a1..83a205be4 100644 --- a/src/info.c +++ b/src/info.c @@ -578,7 +578,8 @@ char spr2names[NUMPLAYERSPRITES][5] = "TALB", "SIGN", - "LIFE" + "LIFE", + "XTRA", }; playersprite_t free_spr2 = SPR2_FIRSTFREESLOT; @@ -595,7 +596,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_DEAD, // SPR2_DRWN, 0, // SPR2_ROLL, SPR2_SPNG, // SPR2_GASP, - 0, // SPR2_JUMP, (conditional) + 0, // SPR2_JUMP, (conditional, will never be referenced) SPR2_FALL, // SPR2_SPNG, SPR2_WALK, // SPR2_FALL, 0, // SPR2_EDGE, @@ -605,7 +606,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_SPNG, // SPR2_FLY , SPR2_FLY , // SPR2_SWIM, - 0, // SPR2_TIRE, (conditional) + 0, // SPR2_TIRE, (conditional, will never be referenced) SPR2_FLY , // SPR2_GLID, SPR2_CLMB, // SPR2_CLNG, @@ -632,7 +633,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_NSTN, // SPR2_NPUL, FF_SPR2SUPER|SPR2_ROLL, // SPR2_NATK, - 0, // SPR2_NGT0, (should never be referenced) + 0, // SPR2_NGT0, (will never be referenced unless skin 0 lacks this) SPR2_NGT0, // SPR2_NGT1, SPR2_NGT1, // SPR2_NGT2, SPR2_NGT2, // SPR2_NGT3, @@ -660,7 +661,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { SPR2_NGTB, // SPR2_DRLB, SPR2_NGTC, // SPR2_DRLC, - 0, // SPR2_TAL0, + 0, // SPR2_TAL0, (this will look mighty stupid but oh well) SPR2_TAL0, // SPR2_TAL1, SPR2_TAL1, // SPR2_TAL2, SPR2_TAL2, // SPR2_TAL3, @@ -675,6 +676,7 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = { 0, // SPR2_SIGN, 0, // SPR2_LIFE, + 0, // SPR2_XTRA (should never be referenced) }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) diff --git a/src/info.h b/src/info.h index 44f08a4e9..b25f21e09 100644 --- a/src/info.h +++ b/src/info.h @@ -834,6 +834,7 @@ typedef enum playersprite SPR2_SIGN, // end sign head SPR2_LIFE, // life monitor icon + SPR2_XTRA, // stuff that isn't in-game - keep this last in the list SPR2_FIRSTFREESLOT, SPR2_LASTFREESLOT = 0x7f, diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 55afa3874..8bd4ce9ff 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -157,6 +157,18 @@ static int lib_setSpr2default(lua_State *L) playersprite_t i; UINT8 j = 0; + if (hud_running) + return luaL_error(L, "Do not alter spr2defaults[] in HUD rendering code!"); + +// todo: maybe allow setting below first freeslot..? step 1 is toggling this, step 2 is testing to see whether it's net-safe +#ifdef SETALLSPR2DEFAULTS +#define FIRSTMODIFY 0 +#else +#define FIRSTMODIFY SPR2_FIRSTFREESLOT + if (free_spr2 == SPR2_FIRSTFREESLOT) + return luaL_error(L, "You can only modify the spr2defaults[] entries of sprite2 freeslots, and none are currently added."); +#endif + lua_remove(L, 1); // don't care about spr2defaults[] dummy userdata. if (lua_isnumber(L, 1)) @@ -175,8 +187,9 @@ static int lib_setSpr2default(lua_State *L) 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 (i < FIRSTMODIFY || i >= free_spr2) + return luaL_error(L, "spr2defaults[] index %d out of range (%d - %d)", i, FIRSTMODIFY, free_spr2-1); +#undef FIRSTMODIFY if (lua_isnumber(L, 2)) j = lua_tonumber(L, 2); @@ -189,11 +202,13 @@ static int lib_setSpr2default(lua_State *L) break; } if (j == free_spr2) - return luaL_error(L, "spr2defaults[] invalid index"); + return luaL_error(L, "spr2defaults[] invalid set"); } + else + return luaL_error(L, "spr2defaults[] invalid set"); - if (j >= free_spr2) - j = 0; // return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1); + if (j < 0 || j >= free_spr2) + return luaL_error(L, "spr2defaults[] set %d out of range (%d - %d)", j, 0, free_spr2-1); spr2defaults[i] = j; return 0; diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index a8f785c5a..cc18ce860 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -27,9 +27,6 @@ enum skin { skin_flags, skin_realname, skin_hudname, - skin_charsel, - skin_face, - skin_superface, skin_ability, skin_ability2, skin_thokitem, @@ -66,9 +63,6 @@ static const char *const skin_opt[] = { "flags", "realname", "hudname", - "charsel", - "face", - "superface", "ability", "ability2", "thokitem", @@ -131,24 +125,6 @@ static int skin_get(lua_State *L) case skin_hudname: lua_pushstring(L, skin->hudname); break; - case skin_charsel: - for (i = 0; i < 8; i++) - if (!skin->charsel[i]) - break; - lua_pushlstring(L, skin->charsel, i); - break; - case skin_face: - for (i = 0; i < 8; i++) - if (!skin->face[i]) - break; - lua_pushlstring(L, skin->face, i); - break; - case skin_superface: - for (i = 0; i < 8; i++) - if (!skin->superface[i]) - break; - lua_pushlstring(L, skin->superface, i); - break; case skin_ability: lua_pushinteger(L, skin->ability); break; diff --git a/src/m_menu.c b/src/m_menu.c index d9d3a6ba0..38326257b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2810,8 +2810,8 @@ boolean M_Responder(event_t *ev) void (*routine)(INT32 choice); // for some casting problem if (dedicated || (demoplayback && titledemo) - || gamestate == GS_INTRO || gamestate == GS_CUTSCENE || gamestate == GS_GAMEEND - || gamestate == GS_CREDITS || gamestate == GS_EVALUATION) + || gamestate == GS_INTRO || gamestate == GS_ENDING || gamestate == GS_CUTSCENE + || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND) return false; if (noFurtherInput) @@ -3511,6 +3511,7 @@ void M_InitCharacterTables(void) strcpy(description[i].picname, ""); strcpy(description[i].skinname, ""); description[i].prev = description[i].next = 0; + description[i].pic = NULL; } } @@ -7557,8 +7558,19 @@ static void M_SetupChoosePlayer(INT32 choice) if (i == char_on) allowed = true; - if (description[i].picname[0] == '\0') - strncpy(description[i].picname, skins[skinnum].charsel, 8); + if (!(description[i].picname[0])) + { + if (skins[skinnum].sprites[SPR2_XTRA].numframes >= 2) + { + spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; + spriteframe_t *sprframe = &sprdef->spriteframes[1]; + description[i].pic = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + } + else + description[i].pic = W_CachePatchName("MISSING", PU_CACHE); + } + else + description[i].pic = W_CachePatchName(description[i].picname, PU_CACHE); } // else -- Technically, character select icons without corresponding skins get bundled away behind this too. Sucks to be them. Z_Free(name); @@ -7712,7 +7724,7 @@ static void M_DrawSetupChoosePlayerMenu(void) // Draw prev character if it's visible and its number isn't greater than the current one or there's more than two if (o < 32) { - patch = W_CachePatchName(description[prev].picname, PU_CACHE); + patch = description[prev].pic; if (SHORT(patch->width) >= 256) V_DrawCroppedPatch(8<height) + 2*(o-32), SHORT(patch->width), 64 - 2*o); else @@ -7723,7 +7735,7 @@ static void M_DrawSetupChoosePlayerMenu(void) // Draw next character if it's visible and its number isn't less than the current one or there's more than two if (o < 128) // (next != i) was previously a part of this, but it's implicitly true if (prev != i) is true. { - patch = W_CachePatchName(description[next].picname, PU_CACHE); + patch = description[next].pic; if (SHORT(patch->width) >= 256) V_DrawCroppedPatch(8<width), 2*o); else @@ -7732,7 +7744,7 @@ static void M_DrawSetupChoosePlayerMenu(void) } } - patch = W_CachePatchName(description[i].picname, PU_CACHE); + patch = description[i].pic; if (o >= 0 && o <= 32) { if (SHORT(patch->width) >= 256) @@ -8124,9 +8136,16 @@ void M_DrawTimeAttackMenu(void) V_DrawString(currentMenu->x, cursory, V_YELLOWMAP, currentMenu->menuitems[itemOn].text); // Character face! - if (W_CheckNumForName(skins[cv_chooseskin.value-1].charsel) != LUMPERROR) { - PictureOfUrFace = W_CachePatchName(skins[cv_chooseskin.value-1].charsel, PU_CACHE); + if (skins[cv_chooseskin.value-1].sprites[SPR2_XTRA].numframes >= 2) + { + spritedef_t *sprdef = &skins[cv_chooseskin.value-1].sprites[SPR2_XTRA]; + spriteframe_t *sprframe = &sprdef->spriteframes[1]; + PictureOfUrFace = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + } + else + PictureOfUrFace = W_CachePatchName("MISSING", PU_CACHE); + if (PictureOfUrFace->width >= 256) V_DrawTinyScaledPatch(224, 120, 0, PictureOfUrFace); else diff --git a/src/m_menu.h b/src/m_menu.h index 04146ebdc..347725e10 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -316,6 +316,7 @@ typedef struct char notes[441]; char picname[8]; char skinname[SKINNAMESIZE*2+2]; // skin&skin\0 + patch_t *pic; UINT8 prev; UINT8 next; } description_t; diff --git a/src/p_setup.c b/src/p_setup.c index c0aa7ffa3..f38ba9334 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3437,13 +3437,13 @@ boolean P_AddWadFile(const char *wadfilename) ST_UnloadGraphics(); HU_LoadGraphics(); ST_LoadGraphics(); - ST_ReloadSkinFaceGraphics(); // // look for skins // R_AddSkins(wadnum); // faB: wadfile index in wadfiles[] R_PatchSkins(wadnum); // toast: PATCH PATCH + ST_ReloadSkinFaceGraphics(); // // search for maps diff --git a/src/r_things.c b/src/r_things.c index 4b1586455..458d15b7f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -486,7 +486,11 @@ void R_InitSprites(void) // it can be is do before loading config for skin cvar possible value R_InitSkins(); for (i = 0; i < numwadfiles; i++) + { R_AddSkins((UINT16)i); + R_PatchSkins((UINT16)i); + } + ST_ReloadSkinFaceGraphics(); // // check if all sprites have frames @@ -2503,6 +2507,9 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) if (!skin) return 0; + if ((spr2 & ~FF_SPR2SUPER) >= free_spr2) + return 0; + while (!(skin->sprites[spr2].numframes) && spr2 != SPR2_STND && ++i < 32) // recursion limiter @@ -2525,8 +2532,10 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) & SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL; break; case SPR2_TIRE: - spr2 = (player && player->charability == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; - break; + spr2 = ((player + ? player->charability + : skin->ability) + == CA_SWIM) ? SPR2_SWIM : SPR2_FLY; // Use the handy list, that's what it's there for! default: @@ -2537,6 +2546,9 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player) spr2 |= super; } + if (i >= 32) // probably an infinite loop... + return 0; + return spr2; } @@ -2556,9 +2568,6 @@ static void Sk_SetDefaultValue(skin_t *skin) strcpy(skin->realname, "Someone"); strcpy(skin->hudname, "???"); - strncpy(skin->charsel, "CHRSONIC", 9); - strncpy(skin->face, "MISSING", 8); - strncpy(skin->superface, "MISSING", 8); skin->starttranscolor = 96; skin->prefcolor = SKINCOLOR_GREEN; @@ -2988,7 +2997,7 @@ void R_AddSkins(UINT16 wadnum) char *value; size_t size; skin_t *skin; - boolean hudname, realname, superface; + boolean hudname, realname; // // search for all skin markers in pwad @@ -3018,7 +3027,7 @@ void R_AddSkins(UINT16 wadnum) skin = &skins[numskins]; Sk_SetDefaultValue(skin); skin->wadnum = wadnum; - hudname = realname = superface = false; + hudname = realname = false; // parse stoken = strtok (buf2, "\r\n= "); while (stoken) @@ -3094,24 +3103,6 @@ void R_AddSkins(UINT16 wadnum) if (!realname) STRBUFCPY(skin->realname, skin->hudname); } - else if (!stricmp(stoken, "charsel")) - { - strupr(value); - strncpy(skin->charsel, value, sizeof skin->charsel); - } - else if (!stricmp(stoken, "face")) - { - strupr(value); - strncpy(skin->face, value, sizeof skin->face); - if (!superface) - strncpy(skin->superface, value, sizeof skin->superface); - } - else if (!stricmp(stoken, "superface")) - { - superface = true; - strupr(value); - strncpy(skin->superface, value, sizeof skin->superface); - } else if (!stricmp(stoken, "availability")) { skin->availability = atoi(value); @@ -3130,6 +3121,7 @@ next_token: // Add sprites R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); + //ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere R_FlushTranslationColormapCache(); @@ -3140,9 +3132,6 @@ next_token: skin_cons_t[numskins].strvalue = skin->name; #endif - // add face graphics - ST_LoadFaceGraphics(skin->face, skin->superface, numskins); - #ifdef HWRENDER if (rendermode == render_opengl) HWR_AddPlayerMD2(numskins); @@ -3265,6 +3254,9 @@ next_token: // Patch sprites R_LoadSkinSprites(wadnum, &lump, &lastlump, skin); + //ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere + + R_FlushTranslationColormapCache(); if (!skin->availability) // Safe to print... CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name); diff --git a/src/r_things.h b/src/r_things.h index d287df832..9c3d16ab0 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -88,7 +88,6 @@ typedef struct char realname[SKINNAMESIZE+1]; // Display name for level completion. char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long) - char charsel[9], face[9], superface[9]; // Arbitrarily named patch lumps UINT8 ability; // ability definition UINT8 ability2; // secondary ability definition diff --git a/src/s_sound.c b/src/s_sound.c index 2db8392d7..120ba5e50 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1682,7 +1682,17 @@ void S_StopMusic(void) if (cv_closedcaptioning.value) { if (closedcaptions[0].s-S_sfx == sfx_None) - closedcaptions[0].t = CAPTIONFADETICS; + { + if (gamestate != wipegamestate) + { + closedcaptions[0].c = NULL; + closedcaptions[0].s = NULL; + closedcaptions[0].t = 0; + closedcaptions[0].b = 0; + } + else + closedcaptions[0].t = CAPTIONFADETICS; + } } } diff --git a/src/st_stuff.c b/src/st_stuff.c index 4122793ad..fc634fe39 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -226,7 +226,7 @@ void ST_doPaletteStuff(void) void ST_UnloadGraphics(void) { - Z_FreeTags(PU_HUDGFX, PU_HUDGFX); + Z_FreeTag(PU_HUDGFX); } void ST_LoadGraphics(void) @@ -341,10 +341,24 @@ void ST_LoadGraphics(void) } // made separate so that skins code can reload custom face graphics -void ST_LoadFaceGraphics(char *facestr, char *superstr, INT32 skinnum) +void ST_LoadFaceGraphics(INT32 skinnum) { - faceprefix[skinnum] = W_CachePatchName(facestr, PU_HUDGFX); - superprefix[skinnum] = W_CachePatchName(superstr, PU_HUDGFX); + if (skins[skinnum].sprites[SPR2_XTRA].numframes) + { + spritedef_t *sprdef = &skins[skinnum].sprites[SPR2_XTRA]; + spriteframe_t *sprframe = &sprdef->spriteframes[0]; + faceprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); + if (skins[skinnum].sprites[(SPR2_XTRA|FF_SPR2SUPER)].numframes) + { + sprdef = &skins[skinnum].sprites[SPR2_XTRA|FF_SPR2SUPER]; + sprframe = &sprdef->spriteframes[0]; + superprefix[skinnum] = W_CachePatchNum(sprframe->lumppat[0], PU_HUDGFX); + } + else + superprefix[skinnum] = faceprefix[skinnum]; // not manually freed, okay to set to same pointer + } + else + faceprefix[skinnum] = superprefix[skinnum] = W_CachePatchName("MISSING", PU_HUDGFX); // ditto facefreed[skinnum] = false; } @@ -353,7 +367,7 @@ void ST_ReloadSkinFaceGraphics(void) INT32 i; for (i = 0; i < numskins; i++) - ST_LoadFaceGraphics(skins[i].face, skins[i].superface, i); + ST_LoadFaceGraphics(i); } static inline void ST_InitData(void) diff --git a/src/st_stuff.h b/src/st_stuff.h index aca4e60d2..40574f46c 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -42,7 +42,7 @@ void ST_UnloadGraphics(void); void ST_LoadGraphics(void); // face load graphics, called when skin changes -void ST_LoadFaceGraphics(char *facestr, char *superstr, INT32 playernum); +void ST_LoadFaceGraphics(INT32 playernum); void ST_ReloadSkinFaceGraphics(void); void ST_doPaletteStuff(void); diff --git a/src/v_video.c b/src/v_video.c index df342e74b..1c56770e5 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -309,12 +309,14 @@ static boolean InitCube(void) return true; } +#ifdef BACKWARDSCOMPATCORRECTION /* So it turns out that the way gamma was implemented previously, the default colour profile of the game was messed up. Since this bad decision has been around for a long time, and the intent is to keep the base game looking the same, I'm not gonna be the one to remove this base modification. toast 20/04/17 +... welp yes i am (27/07/19, see the ifdef around it) */ const UINT8 correctiontable[256] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, @@ -333,6 +335,7 @@ const UINT8 correctiontable[256] = 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255}; +#endif // keep a copy of the palette so that we can get the RGB value for a color index at any time. static void LoadPalette(const char *lumpname) @@ -351,12 +354,18 @@ static void LoadPalette(const char *lumpname) pal = W_CacheLumpNum(lumpnum, PU_CACHE); for (i = 0; i < palsize; i++) { +#ifdef BACKWARDSCOMPATCORRECTION pMasterPalette[i].s.red = pLocalPalette[i].s.red = correctiontable[*pal++]; pMasterPalette[i].s.green = pLocalPalette[i].s.green = correctiontable[*pal++]; pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = correctiontable[*pal++]; +#else + pMasterPalette[i].s.red = pLocalPalette[i].s.red = *pal++; + pMasterPalette[i].s.green = pLocalPalette[i].s.green = *pal++; + pMasterPalette[i].s.blue = pLocalPalette[i].s.blue = *pal++; +#endif pMasterPalette[i].s.alpha = pLocalPalette[i].s.alpha = 0xFF; - // lerp of colour cubing! + // lerp of colour cubing! if you want, make it smoother yourself if (cube) { float working[4][3]; @@ -732,12 +741,15 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t // Center it if necessary if (!(scrn & V_SCALEPATCHMASK)) { - // if it's meant to cover the whole screen, black out the rest + // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) { column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); + if (!column->topdelta) + { + source = (const UINT8 *)(column) + 3; + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, source[0]); + } } if (vid.width != BASEVIDWIDTH * dupx) @@ -1349,13 +1361,16 @@ static UINT32 V_GetHWConsBackColor(void) // THANK YOU MPC!!! +// and thanks toaster for cleaning it up. void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) { UINT8 *dest; - INT32 u, v; + const UINT8 *deststop; + INT32 u; UINT8 *fadetable; UINT32 alphalevel = 0; + UINT8 perplayershuffle = 0; if (rendermode == render_none) return; @@ -1369,16 +1384,91 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) } #endif + if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT))) + { + if (alphalevel == 13) + alphalevel = hudminusalpha[cv_translucenthud.value]; + else if (alphalevel == 14) + alphalevel = 10 - cv_translucenthud.value; + else if (alphalevel == 15) + alphalevel = hudplusalpha[cv_translucenthud.value]; + + if (alphalevel >= 10) + return; // invis + } + + if (splitscreen && (c & V_PERPLAYER)) + { + fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1; + h >>= 1; + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1; + w >>= 1; + x >>= 1; + if (stplyr == &players[displayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } + else if (stplyr == &players[secondarydisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + y += adjusty; + c &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + y += adjusty; + c &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + c &= ~V_SNAPTOBOTTOM; + } + else //if (stplyr == &players[secondarydisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + y += adjusty; + c &= ~V_SNAPTOTOP; + } + } + } + if (!(c & V_NOSCALESTART)) { INT32 dupx = vid.dupx, dupy = vid.dupy; - if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT) - { // Clear the entire screen, from dest to deststop. Yes, this really works. - memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp); - return; - } - x *= dupx; y *= dupy; w *= dupx; @@ -1393,6 +1483,10 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) x += (vid.width - (BASEVIDWIDTH * dupx)); else if (!(c & V_SNAPTOLEFT)) x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + if (perplayershuffle & 4) + x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4; + else if (perplayershuffle & 8) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 4; } if (vid.height != BASEVIDHEIGHT * dupy) { @@ -1401,6 +1495,10 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) y += (vid.height - (BASEVIDHEIGHT * dupy)); else if (!(c & V_SNAPTOTOP)) y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + if (perplayershuffle & 1) + y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4; + else if (perplayershuffle & 2) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4; } } @@ -1423,34 +1521,208 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) h = vid.height-y; dest = screens[0] + y*vid.width + x; - - if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT))) - { - if (alphalevel == 13) - alphalevel = hudminusalpha[cv_translucenthud.value]; - else if (alphalevel == 14) - alphalevel = 10 - cv_translucenthud.value; - else if (alphalevel == 15) - alphalevel = hudplusalpha[cv_translucenthud.value]; - - if (alphalevel >= 10) - return; // invis - } + deststop = screens[0] + vid.rowbytes * vid.height; c &= 255; // Jimita (12-04-2018) - w = min(w, vid.width); - h = min(h, vid.height); - fadetable = ((UINT8 *)transtables + ((alphalevel-1)<= 0) && dest < deststop; dest += vid.width) { - if (!alphalevel) - dest[u] = consolebgmap[dest[u]]; - else + u = 0; + while (u < w) + { dest[u] = fadetable[consolebgmap[dest[u]]]; + u++; + } } + } + else + { + for (;(--h >= 0) && dest < deststop; dest += vid.width) + { + u = 0; + while (u < w) + { + dest[u] = consolebgmap[dest[u]]; + u++; + } + } + } +} + +// +// If color is 0x00 to 0xFF, draw transtable (strength range 0-9). +// Else, use COLORMAP lump (strength range 0-31). +// c is not color, it is for flags only. transparency flags will be ignored. +// IF YOU ARE NOT CAREFUL, THIS CAN AND WILL CRASH! +// I have kept the safety checks for strength out of this function; +// I don't trust Lua users with it, so it doesn't matter. +// +void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, UINT8 strength) +{ + UINT8 *dest; + const UINT8 *deststop; + INT32 u; + UINT8 *fadetable; + UINT8 perplayershuffle = 0; + + if (rendermode == render_none) + return; + +#ifdef HWRENDER + if (rendermode != render_soft && rendermode != render_none) + { + // ughhhhh please can someone else do this? thanks ~toast 25/7/19 in 38 degrees centigrade w/o AC + HWR_DrawFadeFill(x, y, w, h, c, color, strength); // toast two days later - left above comment in 'cause it's funny + return; + } +#endif + +#if 0 // only if for use in-game, otherwise not worth the processor time + if (splitscreen && (c & V_PERPLAYER)) + { + fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1; + h >>= 1; + y >>= 1; +#ifdef QUADS + if (splitscreen > 1) // 3 or 4 players + { + fixed_t adjustx = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1; + w >>= 1; + x >>= 1; + if (stplyr == &players[displayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + c &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT; + } + else if (stplyr == &players[secondarydisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + c &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT; + } + else if (stplyr == &players[thirddisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 4; + y += adjusty; + c &= ~V_SNAPTOTOP|V_SNAPTORIGHT; + } + else //if (stplyr == &players[fourthdisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + if (!(c & (V_SNAPTOLEFT|V_SNAPTORIGHT))) + perplayershuffle |= 8; + x += adjustx; + y += adjusty; + c &= ~V_SNAPTOTOP|V_SNAPTOLEFT; + } + } + else +#endif + // 2 players + { + if (stplyr == &players[displayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 1; + c &= ~V_SNAPTOBOTTOM; + } + else //if (stplyr == &players[secondarydisplayplayer]) + { + if (!(c & (V_SNAPTOTOP|V_SNAPTOBOTTOM))) + perplayershuffle |= 2; + y += adjusty; + c &= ~V_SNAPTOTOP; + } + } + } +#endif + + if (!(c & V_NOSCALESTART)) + { + INT32 dupx = vid.dupx, dupy = vid.dupy; + + x *= dupx; + y *= dupy; + w *= dupx; + h *= dupy; + + // Center it if necessary + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (c & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(c & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + if (perplayershuffle & 4) + x -= (vid.width - (BASEVIDWIDTH * dupx)) / 4; + else if (perplayershuffle & 8) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 4; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if (c & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(c & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + if (perplayershuffle & 1) + y -= (vid.height - (BASEVIDHEIGHT * dupy)) / 4; + else if (perplayershuffle & 2) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 4; + } + } + + if (x >= vid.width || y >= vid.height) + return; // off the screen + if (x < 0) { + w += x; + x = 0; + } + if (y < 0) { + h += y; + y = 0; + } + + if (w <= 0 || h <= 0) + return; // zero width/height wouldn't draw anything + if (x + w > vid.width) + w = vid.width-x; + if (y + h > vid.height) + h = vid.height-y; + + dest = screens[0] + y*vid.width + x; + deststop = screens[0] + vid.rowbytes * vid.height; + + c &= 255; + + fadetable = ((color & 0xFF00) // Color is not palette index? + ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. + : ((UINT8 *)transtables + ((9-strength)<= 0) && dest < deststop; dest += vid.width) + { + u = 0; + while (u < w) + { + dest[u] = fadetable[dest[u]]; + u++; + } + } } // diff --git a/src/v_video.h b/src/v_video.h index 43748692e..7eb990295 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -158,6 +158,8 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum); // fade down the screen buffer before drawing the menu over void V_DrawFadeScreen(UINT16 color, UINT8 strength); +// available to lua over my dead body, which will probably happen in this heat +void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, UINT8 strength); void V_DrawFadeConsBack(INT32 plines); void V_DrawPromptBack(INT32 boxheight, INT32 color); From 7569e0b184d10b739913325fa9f3cbd758391c4a Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Jul 2019 10:41:00 +0100 Subject: [PATCH 14/47] Good morning, fix three little things. * Made the black rock animate backwards through its anim again, to match the 2.1 and earlier intro. * Rid branch of mixed code declaration warnings. * Other cleanup. --- src/f_finale.c | 52 +++++++++++++++----------------------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index bac50dcec..e17c1118a 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -707,7 +707,7 @@ static void F_IntroDrawScene(void) y += (30*(FRACUNIT-scale)); } - rockpat = W_CachePatchName(va("ROID00%.2d", worktics % 35), PU_LEVEL); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_LEVEL); glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_LEVEL); if (worktics >= 5) @@ -1346,9 +1346,9 @@ void F_GameEvaluationDrawer(void) if (goodending) { - rockpat = W_CachePatchName(va("ROID00%.2d", finalecount % 35), PU_LEVEL); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_LEVEL); glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_LEVEL); - x -= 3< 0) // gunchedrock { + INT32 scale = FRACUNIT + ((parallaxticker-10)<<7); + INT32 trans = parallaxticker>>2; + UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JET, GTC_CACHE); + if (parallaxticker < 10) { tweakx = parallaxticker<>2; - UINT8 *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_JET, GTC_CACHE); -#endif x <<= 1; y <<= 1; // center detritrus - V_DrawFixedPatch(i-x, j-y, FRACUNIT, 0, endegrk[0], -#ifdef TFTMOPTIMUSFADE - colormap); + V_DrawFixedPatch(i-x, j-y, FRACUNIT, 0, endegrk[0], colormap); if (trans < 10) - V_DrawFixedPatch(i-x, j-y, FRACUNIT, trans<'|(trans<= (2*INFLECTIONPOINT)-TICRATE) ? V_PURPLEMAP : V_BLUEMAP)|(trans<"); From bebaf6f984894e0215ca2819ed9204d9d438e77f Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Jul 2019 11:40:19 +0100 Subject: [PATCH 15/47] * Add comments for maintenence. * Fix not-guaranteed-to-be-set-to-zero-ness of sparklloop * Add blackrock sparkles to good ending. * Don't have emerald sparkles be randomised. * Adjust credits to include Sal (credits sprites + four merged internal MRs and a bunch of public ones) and a few other known contributors, plus remove oni's name (he requested i do it a whiiile ago) --- src/f_finale.c | 165 +++++++++++++++++++++++++++++-------------------- 1 file changed, 97 insertions(+), 68 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index e17c1118a..64a6503e7 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -104,7 +104,7 @@ static patch_t *endfwrk[3]; // firework - replaced with skin when good ending static patch_t *endspkl[3]; // sparkle static patch_t *endglow[2]; // glow aura - replaced with black rock's midway through good ending static patch_t *endxpld[4]; // mini explosion -static INT32 sparkloffs[8][3][2]; // seven emerald sparkles + eggrock explosions +static INT32 sparkloffs[3][2]; // eggrock explosions/blackrock sparkles static INT32 sparklloop; // @@ -985,6 +985,7 @@ static const char *credits[] = { "\1Assistance", "\"chi.miru\"", // helped port slope drawing code from ZDoom "Andrew \"orospakr\" Clunis", + "Sally \"TehRealSalt\" Cochenour", "Gregor \"Oogaland\" Dick", "Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol) "Victor \"Steel Titanium\" Fuentes", @@ -1004,8 +1005,9 @@ static const char *credits[] = { // Everyone else is acknowledged under "Special Thanks > SRB2 Community Contributors". "", "\1Sprite Artists", - "Odi \"Iceman404\" Atunzu", + "\"Iceman404\"", "Victor \"VAdaPEGA\" Ara\x1Fjo", // Araújo -- sorry for our limited font! D: + "Sally \"TehRealSalt\" Cochenour", "Jim \"MotorRoach\" DeMello", "Desmond \"Blade\" DesJardins", "Sherman \"CoatRack\" DesJardins", @@ -1087,7 +1089,10 @@ static const char *credits[] = { "Simon \"sirjuddington\" Judd", // SLADE developer // Acknowledged here are the following: // Minor merge request authors, see guideline above - // Golden - Expanded thin font + // - Golden - Expanded thin font + // Creators of small quantities of sprite/texture assets + // - Arietty - New Green Hill-styled textures + // - Scizor300 - the only other contributor to the 2.0 SRB2 Asset Pack "SRB2 Community Contributors", "", "\1Produced By", @@ -1279,8 +1284,7 @@ boolean F_CreditResponder(event_t *event) // ============ // EVALUATION // ============ -#define INTERVAL (360/7) -#define TRANSLEVEL V_80TRANS +#define SPARKLLOOPTIME 7 // must be odd void F_StartGameEvaluation(void) { @@ -1309,6 +1313,7 @@ void F_StartGameEvaluation(void) CON_ToggleOff(); finalecount = -1; + sparklloop = 0; } void F_GameEvaluationDrawer(void) @@ -1373,7 +1378,24 @@ void F_GameEvaluationDrawer(void) colormap[1] = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_AQUA, GTC_CACHE); V_DrawFixedPatch(x, y, scale, trans< (finalecount/SPARKLLOOPTIME)) + j = (finalecount/SPARKLLOOPTIME); + while (j) + { + if (j > 1 || sparklloop >= 2) + { + // if j == 0 - alternate between 0 and 1 + // 1 - 1 and 2 + // 2 - 2 and not rendered + V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_LEVEL), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE)); + } + j--; + } + } + else { patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_LEVEL); V_DrawFixedPatch(x, y, scale, 0, eggrock, colormap[0]); @@ -1392,24 +1414,16 @@ void F_GameEvaluationDrawer(void) fa = (FixedAngle(eemeralds_cur*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINECOSINE(fa)); y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + (60*FINESINE(fa)); - eemeralds_cur += INTERVAL; + eemeralds_cur += (360/7); if (i & 1) eemeralds_cur++; patchname[4] = 'A'+(char)i; - V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<= 5*TICRATE) { -#if 0 - if (drawemblem) - V_DrawScaledPatch(120, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE)); - - if (drawchaosemblem) - V_DrawScaledPatch(200, 192, 0, W_CachePatchName("NWNGA0", PU_CACHE)); -#endif - V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); if (!(netgame) && (!modifiedgame || savemoddata)) @@ -1438,16 +1452,33 @@ void F_GameEvaluationTicker(void) { finalecount++; - if (sparklloop) - sparklloop--; - - if (!goodending - && (finalecount == (5*TICRATE)/2 - || finalecount == (7*TICRATE)/2 - || finalecount == ((7*TICRATE)/2)+5)) + if (goodending) { - S_StartSound(NULL, sfx_s3k5c); - sparklloop = 10; + if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again + { + angle_t workingangle = FixedAngle((M_RandomKey(360))<>ANGLETOFINESHIFT; + fixed_t workingradius = M_RandomKey(26); + sparkloffs[2][0] = sparkloffs[1][0]; + sparkloffs[2][1] = sparkloffs[1][1]; + sparkloffs[1][0] = sparkloffs[0][0]; + sparkloffs[1][1] = sparkloffs[0][1]; + sparkloffs[0][0] = (30<>ANGLETOFINESHIFT; workingradius = M_RandomKey(26); - sparkloffs[7][0][0] = (30< INFLECTIONPOINT*2) @@ -1668,7 +1688,7 @@ void F_EndingDrawer(void) boolean borderstuff = false; INT32 tweakx = 0, tweaky = 0; - if (parallaxticker < 75) + if (parallaxticker < 75) // f background's supposed to be visible { V_DrawFixedPatch(-(x/10), -(y/10), FRACUNIT, 0, endbgsp[0], NULL); // nebula V_DrawFixedPatch(-(x/5), -(y/5), FRACUNIT, 0, endbgsp[1], NULL); // sun @@ -1730,7 +1750,7 @@ void F_EndingDrawer(void) j += tweaky<<2; } - if (parallaxticker <= 70) + if (parallaxticker <= 70) // eggrock/blackrock { INT32 trans; fixed_t scale = FRACUNIT; @@ -1752,8 +1772,8 @@ void F_EndingDrawer(void) doexplosions = true; if (!sparklloop) { - x += ((sparkloffs[7][0][0] < 30<= 3 && doexplosions) { INT32 boomtime = parallaxticker - sparklloop; @@ -1843,10 +1864,11 @@ void F_EndingDrawer(void) x = ((((BASEVIDWIDTH-82)/2)+11)<= TICRATE && finalecount < INFLECTIONPOINT) { INT32 workingtime = finalecount - TICRATE; - fixed_t radius[4]; + fixed_t radius = ((vid.width/vid.dupx)*(INFLECTIONPOINT - TICRATE - workingtime))/(INFLECTIONPOINT - TICRATE); angle_t fa; INT32 eemeralds_cur[4]; char patchname[7] = "CEMGx0"; + radius <<= FRACBITS; + for (i = 0; i < 4; ++i) { if (i == 1) @@ -1878,22 +1903,9 @@ void F_EndingDrawer(void) else if (i) workingtime -= SPARKLLOOPTIME; eemeralds_cur[i] = workingtime % 360; - radius[i] = ((vid.width/vid.dupx)*(INFLECTIONPOINT - TICRATE - workingtime))/(INFLECTIONPOINT - TICRATE); - radius[i] <<= FRACBITS; } - for (i = 0; i < 7; ++i) - { - fa = (FixedAngle(eemeralds_cur[0]*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; - x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius[0]); - y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius[0]); - eemeralds_cur[0] += INTERVAL; - if (i & 1) - eemeralds_cur[0]++; - - patchname[4] = 'A'+(char)i; - V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_LEVEL), NULL); - } + // sparkles for (i = 0; i < 7; ++i) { UINT8* colormap; @@ -1928,9 +1940,9 @@ void F_EndingDrawer(void) while (j) { fa = (FixedAngle(eemeralds_cur[j]*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; - x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius[j]) + sparkloffs[i][j-1][0]; - y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius[j]) + sparkloffs[i][j-1][1]; - eemeralds_cur[j] += INTERVAL; + x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius); + y = (BASEVIDHEIGHT<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius); + eemeralds_cur[j] += (360/7); if (i & 1) eemeralds_cur[j]++; @@ -1942,6 +1954,20 @@ void F_EndingDrawer(void) j--; } } + + // ...then emeralds themselves + for (i = 0; i < 7; ++i) + { + fa = (FixedAngle(eemeralds_cur[0]*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK; + x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius); + y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius); + eemeralds_cur[0] += (360/7); + if (i & 1) + eemeralds_cur[0]++; + + patchname[4] = 'A'+(char)i; + V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_LEVEL), NULL); + } } // if (goodending... } // (finalecount > 20) @@ -1989,6 +2015,9 @@ void F_EndingDrawer(void) } } +#undef SPARKLLOOPTIME +#undef INFLECTIONPOINT + // ========== // GAME END // ========== From f47c3f40d104974446e52ba73185a74ef4d4a614 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Jul 2019 14:59:42 +0100 Subject: [PATCH 16/47] Smoothen emerald rotation a tad. (Not gonna upload a new test exe, it's basically identical...) --- src/f_finale.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 64a6503e7..a93163fcc 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1407,16 +1407,14 @@ void F_GameEvaluationDrawer(void) } } - eemeralds_cur = finalecount % 360; + eemeralds_cur = (finalecount % 360)<>ANGLETOFINESHIFT) & FINEMASK; + fa = (FixedAngle(eemeralds_cur)>>ANGLETOFINESHIFT) & FINEMASK; x = (BASEVIDWIDTH<<(FRACBITS-1)) + (60*FINECOSINE(fa)); y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + (60*FINESINE(fa)); - eemeralds_cur += (360/7); - if (i & 1) - eemeralds_cur++; + eemeralds_cur += (360<>ANGLETOFINESHIFT) & FINEMASK; + fa = (FixedAngle(eemeralds_cur[j])>>ANGLETOFINESHIFT) & FINEMASK; x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius); y = (BASEVIDHEIGHT<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius); - eemeralds_cur[j] += (360/7); - if (i & 1) - eemeralds_cur[j]++; + eemeralds_cur[j] += (360<>ANGLETOFINESHIFT) & FINEMASK; + fa = (FixedAngle(eemeralds_cur[0])>>ANGLETOFINESHIFT) & FINEMASK; x = (BASEVIDWIDTH<<(FRACBITS-1)) + FixedMul(FINECOSINE(fa),radius); y = ((BASEVIDHEIGHT+16)<<(FRACBITS-1)) + FixedMul(FINESINE(fa),radius); - eemeralds_cur[0] += (360/7); - if (i & 1) - eemeralds_cur[0]++; + eemeralds_cur[0] += (360< Date: Sun, 28 Jul 2019 17:47:57 +0100 Subject: [PATCH 17/47] * Fix crash error in GL. * Re-enable the perplayer stuff in V_DrawFadeFill - not worth having it disabled when it'll just have to be re-enabled later. * Remove some "consistency with software" stuff in hw_draw.c that already has equivalents --- src/f_finale.c | 5 ----- src/hardware/hw_draw.c | 10 ---------- src/v_video.c | 9 +-------- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index a93163fcc..72bf17f1f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1599,17 +1599,12 @@ void F_EndingTicker(void) if (++finalecount == INFLECTIONPOINT && goodending) // time to swap some assets { - Z_Free(endegrk[0]); endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL); - Z_Free(endegrk[1]); endegrk[1] = W_CachePatchName("ENDEGRK3", PU_LEVEL); - Z_Free(endglow[0]); endglow[0] = W_CachePatchName("ENDGLOW2", PU_LEVEL); - Z_Free(endglow[1]); endglow[1] = W_CachePatchName("ENDGLOW3", PU_LEVEL); - Z_Free(endxpld[0]); endxpld[0] = W_CachePatchName("ENDEGRK4", PU_LEVEL); } diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 6bfd2a4dc..1ba357105 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -706,9 +706,6 @@ void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 ac UINT8 perplayershuffle = 0; - if (w < 0 || h < 0) - return; // consistency w/ software - // 3--2 // | /| // |/ | @@ -870,7 +867,6 @@ void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 ac Surf.FlatColor.rgba = V_GetColor(actualcolor).rgba; Surf.FlatColor.s.alpha = softwaretranstogl[strength]; } - HWD.pfnDrawPolygon(&Surf, v, 4, PF_NoTexture|PF_Modulated|PF_Translucent|PF_NoDepthTest); } @@ -1092,9 +1088,6 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, UINT32 color, INT32 UINT8 perplayershuffle = 0; - if (w < 0 || h < 0) - return; // consistency w/ software - // 3--2 // | /| // |/ | @@ -1263,9 +1256,6 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) UINT8 perplayershuffle = 0; - if (w < 0 || h < 0) - return; // consistency w/ software - // 3--2 // | /| // |/ | diff --git a/src/v_video.c b/src/v_video.c index 1c56770e5..85f22eccb 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -996,12 +996,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (!(scrn & V_SCALEPATCHMASK)) { // 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) - { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); - source = (const UINT8 *)(column) + 3; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); - } + // no the patch is cropped do not do this ever if (vid.width != BASEVIDWIDTH * dupx) { @@ -1581,7 +1576,6 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U } #endif -#if 0 // only if for use in-game, otherwise not worth the processor time if (splitscreen && (c & V_PERPLAYER)) { fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1; @@ -1649,7 +1643,6 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U } } } -#endif if (!(c & V_NOSCALESTART)) { From 1d799630af754e7aec7aa01745c21e1d152f0e49 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Jul 2019 22:45:20 +0100 Subject: [PATCH 18/47] Made it possible to just call `EV_CrumbleChain(rover)` in Lua --- src/lua_baselib.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 712bc4045..97d2fdc24 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2047,12 +2047,19 @@ static int lib_pStartQuake(lua_State *L) static int lib_evCrumbleChain(lua_State *L) { - sector_t *sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); - ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); + sector_t *sec = NULL; + ffloor_t *rover = NULL; NOHUD INLEVEL - /*if (!sec) - return LUA_ErrInvalid(L, "sector_t");*/ + if (lua_isuserdata(L, 2)) + { + sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); + rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); + if (!sec) + return LUA_ErrInvalid(L, "sector_t"); + } + else + rover = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); if (!rover) return LUA_ErrInvalid(L, "ffloor_t"); EV_CrumbleChain(sec, rover); From 5dc095a47d3ae35c189c482f5ee5c1ad6a8051f9 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Jul 2019 22:53:27 +0100 Subject: [PATCH 19/47] Further improvements on MI's request, just to be safe. --- src/lua_baselib.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 97d2fdc24..767ab2dd3 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2051,12 +2051,15 @@ static int lib_evCrumbleChain(lua_State *L) ffloor_t *rover = NULL; NOHUD INLEVEL - if (lua_isuserdata(L, 2)) + if (!lua_isnone(L, 2)) { - sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); + if (!lua_isnil(L, 1)) + { + sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); + if (!sec) + return LUA_ErrInvalid(L, "sector_t"); + } rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR)); - if (!sec) - return LUA_ErrInvalid(L, "sector_t"); } else rover = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); From 47554b57e4bce237e7092a3c77c959cf1d029b05 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 29 Jul 2019 14:55:36 +0100 Subject: [PATCH 20/47] * Made the evaluation screen even more attractive. * Fixed an unused variable warning in lua_skinlib.c. - fixed post-level cutscenes playing when you get game over in MP (still kinda on-topic) Also with apologies to MI: - golden egg statue mode for tutorial, since the grey doesn't contrast enough with the blue and lime green - fixed closed captions for replaced player sounds being incorrect - fixed closed captions overlapping tutorial text --- src/doomstat.h | 2 +- src/f_finale.c | 91 +++++++++++++++++++++++++++-------------------- src/g_game.c | 6 ++-- src/g_game.h | 2 ++ src/lua_baselib.c | 4 +-- src/lua_skinlib.c | 1 - src/m_cond.c | 2 +- src/p_mobj.c | 6 ++++ src/p_setup.c | 2 +- src/p_spec.c | 2 +- src/s_sound.c | 5 +-- src/screen.c | 4 ++- 12 files changed, 76 insertions(+), 51 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 87b98ab40..18300967c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -234,7 +234,7 @@ extern textprompt_t *textprompts[MAX_PROMPTS]; // For the Custom Exit linedef. extern INT16 nextmapoverride; -extern boolean skipstats; +extern UINT8 skipstats; extern UINT32 ssspheres; // Total # of spheres in a level diff --git a/src/f_finale.c b/src/f_finale.c index 72bf17f1f..cb315be03 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -110,7 +110,7 @@ static INT32 sparklloop; // // PROMPT STATE // -static boolean promptactive = false; +boolean promptactive = false; static mobj_t *promptmo; static INT16 promptpostexectag; static boolean promptblockcontrols; @@ -1284,6 +1284,7 @@ boolean F_CreditResponder(event_t *event) // ============ // EVALUATION // ============ + #define SPARKLLOOPTIME 7 // must be odd void F_StartGameEvaluation(void) @@ -1322,14 +1323,11 @@ void F_GameEvaluationDrawer(void) angle_t fa; INT32 eemeralds_cur; char patchname[7] = "CEMGx0"; + const char* endingtext = (goodending ? "CONGRATULATIONS!" : "TRY AGAIN..."); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Draw all the good crap here. - if (goodending) - V_DrawString(114, 16, 0, "GOT THEM ALL!"); - else - V_DrawString(124, 16, 0, "TRY AGAIN!"); if (finalecount > 0) { @@ -1420,6 +1418,9 @@ void F_GameEvaluationDrawer(void) V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<= 5*TICRATE) { V_DrawString(8, 16, V_YELLOWMAP, "Unlocked:"); @@ -1444,28 +1445,18 @@ void F_GameEvaluationDrawer(void) else V_DrawString(8, 96, V_YELLOWMAP, "Prizes not\nawarded in\nmodified games!"); } +#endif } void F_GameEvaluationTicker(void) { - finalecount++; - - if (goodending) + if (++finalecount > 10*TICRATE) { - if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again - { - angle_t workingangle = FixedAngle((M_RandomKey(360))<>ANGLETOFINESHIFT; - fixed_t workingradius = M_RandomKey(26); - sparkloffs[2][0] = sparkloffs[1][0]; - sparkloffs[2][1] = sparkloffs[1][1]; - sparkloffs[1][0] = sparkloffs[0][0]; - sparkloffs[1][1] = sparkloffs[0][1]; - sparkloffs[0][0] = (30<>ANGLETOFINESHIFT; + fixed_t workingradius = M_RandomKey(26); + + sparkloffs[2][0] = sparkloffs[1][0]; + sparkloffs[2][1] = sparkloffs[1][1]; + sparkloffs[1][0] = sparkloffs[0][0]; + sparkloffs[1][1] = sparkloffs[0][1]; + + sparkloffs[0][0] = (30< 10*TICRATE) - F_StartGameEnd(); } #undef SPARKLLOOPTIME @@ -1508,8 +1524,8 @@ void F_GameEvaluationTicker(void) // ENDING // ========== -#define SPARKLLOOPTIME 15 // must be odd #define INFLECTIONPOINT (6*TICRATE) +#define SPARKLLOOPTIME 15 // must be odd void F_StartEnding(void) { @@ -1594,10 +1610,14 @@ void F_StartEnding(void) void F_EndingTicker(void) { - angle_t workingangle; - fixed_t workingradius; + if (++finalecount > INFLECTIONPOINT*2) + { + F_StartCredits(); + wipetypepre = INT16_MAX; + return; + } - if (++finalecount == INFLECTIONPOINT && goodending) // time to swap some assets + if (goodending && finalecount == INFLECTIONPOINT) // time to swap some assets { endegrk[0] = W_CachePatchName("ENDEGRK2", PU_LEVEL); endegrk[1] = W_CachePatchName("ENDEGRK3", PU_LEVEL); @@ -1610,17 +1630,13 @@ void F_EndingTicker(void) if (++sparklloop == SPARKLLOOPTIME) // time to roll the randomisation again { - sparklloop = 0; - workingangle = FixedAngle((M_RandomRange(-170, 80))<>ANGLETOFINESHIFT; - workingradius = M_RandomKey(26); + angle_t workingangle = FixedAngle((M_RandomRange(-170, 80))<>ANGLETOFINESHIFT; + fixed_t workingradius = M_RandomKey(26); + sparkloffs[0][0] = (30< INFLECTIONPOINT*2) - { - F_StartCredits(); - wipetypepre = INT16_MAX; + sparklloop = 0; } } @@ -2005,7 +2021,6 @@ void F_EndingDrawer(void) } #undef SPARKLLOOPTIME -#undef INFLECTIONPOINT // ========== // GAME END diff --git a/src/g_game.c b/src/g_game.c index c6af0f48d..60262161a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -152,7 +152,7 @@ cutscene_t *cutscenes[128]; textprompt_t *textprompts[MAX_PROMPTS]; INT16 nextmapoverride; -boolean skipstats; +UINT8 skipstats; // Pointers to each CTF flag mobj_t *redflag; @@ -2651,7 +2651,7 @@ void G_DoReborn(INT32 playernum) //nextmapoverride = spstage_start; nextmapoverride = gamemap; countdown2 = TICRATE; - skipstats = true; + skipstats = 2; for (i = 0; i < MAXPLAYERS; i++) { @@ -3180,7 +3180,7 @@ void G_AfterIntermission(void) { HU_ClearCEcho(); - if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking) // Start a custom cutscene. + if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); else { diff --git a/src/g_game.h b/src/g_game.h index 3cbde9a3c..f03014439 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -56,6 +56,8 @@ extern INT16 rw_maximums[NUM_WEAPONS]; extern INT32 pausedelay; extern boolean pausebreakkey; +extern boolean promptactive; + // used in game menu extern consvar_t cv_tutorialprompt; extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime, cv_consolechat, cv_chatbacktint, cv_chatspamprotection, cv_compactscoreboard; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 1d69b238b..98f2ba3b8 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2601,12 +2601,12 @@ static int lib_gSetCustomExitVars(lua_State *L) nextmapoverride = (INT16)luaL_checknumber(L, 1); lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available } - skipstats = lua_optboolean(L, 1); + skipstats = luaL_optinteger(L, 2, 0); } else { nextmapoverride = 0; - skipstats = false; + skipstats = 0; } // --- diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index cc18ce860..a28f6a359 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -98,7 +98,6 @@ static int skin_get(lua_State *L) { skin_t *skin = *((skin_t **)luaL_checkudata(L, 1, META_SKIN)); enum skin field = luaL_checkoption(L, 2, NULL, skin_opt); - INT32 i; // skins are always valid, only added, never removed I_Assert(skin != NULL); diff --git a/src/m_cond.c b/src/m_cond.c index e03542bf3..539c6d1f6 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -240,7 +240,7 @@ UINT8 M_UpdateUnlockablesAndExtraEmblems(void) if (cechoLines) { char slashed[1024] = ""; - for (i = 0; (i < 21) && (i < 24 - cechoLines); ++i) + for (i = 0; (i < 19) && (i < 24 - cechoLines); ++i) slashed[i] = '\\'; slashed[i] = 0; diff --git a/src/p_mobj.c b/src/p_mobj.c index 9a6e0f2bb..a48ebfc40 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11100,6 +11100,12 @@ You should think about modifying the deathmatch starts to take full advantage of else skyboxviewpnts[mthing->extrainfo] = mobj; break; + case MT_EGGSTATUE: + if (tutorialmode != (mthing->options & MTF_OBJECTSPECIAL)) + { + mobj->color = SKINCOLOR_GOLD; + mobj->colorized = true; + } case MT_EGGMOBILE3: mobj->cusval = mthing->extrainfo; break; diff --git a/src/p_setup.c b/src/p_setup.c index f38ba9334..dfbba0252 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3126,7 +3126,7 @@ boolean P_SetupLevel(boolean skipprecip) R_PrecacheLevel(); nextmapoverride = 0; - skipstats = false; + skipstats = 0; if (!(netgame || multiplayer) && (!modifiedgame || savemoddata)) mapvisited[gamemap-1] |= MV_VISITED; diff --git a/src/p_spec.c b/src/p_spec.c index 3cd0461e2..88dfad70e 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4624,7 +4624,7 @@ DoneSection2: nextmapoverride = (INT16)(lines[lineindex].frontsector->floorheight>>FRACBITS); if (lines[lineindex].flags & ML_NOCLIMB) - skipstats = true; + skipstats = 1; } } break; diff --git a/src/s_sound.c b/src/s_sound.c index 120ba5e50..9b5df072c 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -519,6 +519,7 @@ void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan) void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) { INT32 sep, pitch, priority, cnum; + const sfxenum_t actual_id = sfx_id; sfxinfo_t *sfx; const mobj_t *origin = (const mobj_t *)origin_p; @@ -657,7 +658,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) #endif // Handle closed caption input. - S_StartCaption(sfx_id, cnum, MAXCAPTIONTICS); + S_StartCaption(actual_id, cnum, MAXCAPTIONTICS); // Assigns the handle to one of the channels in the // mix/output buffer. @@ -710,7 +711,7 @@ dontplay: #endif // Handle closed caption input. - S_StartCaption(sfx_id, cnum, MAXCAPTIONTICS); + S_StartCaption(actual_id, cnum, MAXCAPTIONTICS); // Assigns the handle to one of the channels in the // mix/output buffer. diff --git a/src/screen.c b/src/screen.c index ac7878c4a..fc3f5b8e8 100644 --- a/src/screen.c +++ b/src/screen.c @@ -438,7 +438,9 @@ void SCR_ClosedCaptions(void) if (gamestate == GS_LEVEL) { - if (splitscreen) + if (promptactive) + basey -= 28; + else if (splitscreen) basey -= 8; else if ((modeattacking == ATTACKING_NIGHTS) || (!(maptol & TOL_NIGHTS) From 62c708e64a6ec889f8b0107dc0b07cd641ee14d3 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 29 Jul 2019 20:29:02 +0100 Subject: [PATCH 21/47] Two one liners related to angles, so doin' em in a single branch. * If a spring has vertical speed AND horizontal speed, always set the player's angle when touching it. * If you have less than 32 rings and spill them, they now get launched away from the player's motion, rather than in the direction of the camera. --- src/p_inter.c | 9 +++++++-- src/p_map.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index abf33429f..5b52f2ffb 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -3652,7 +3652,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) { INT32 i; mobj_t *mo; - angle_t fa; + angle_t fa, va; fixed_t ns; fixed_t z; boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap)); @@ -3674,6 +3674,11 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) // Spill weapons first P_PlayerWeaponPanelOrAmmoBurst(player); + if (abs(player->mo->momx) > player->mo->scale || abs(player->mo->momy) > player->mo->scale) + va = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0)>>ANGLETOFINESHIFT; + else + va = player->mo->angle>>ANGLETOFINESHIFT; + for (i = 0; i < num_rings; i++) { INT32 objType = mobjinfo[MT_RING].reactiontime; @@ -3695,7 +3700,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) P_SetScale(mo, player->mo->scale); // Angle offset by player angle, then slightly offset by amount of rings - fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT) - ((num_rings-1)*FINEANGLES/32)) & FINEMASK; + fa = ((i*FINEANGLES/16) + va - ((num_rings-1)*FINEANGLES/32)) & FINEMASK; // 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. diff --git a/src/p_map.c b/src/p_map.c index e78dd1e84..8fe9fb4ae 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -342,7 +342,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) if (horizspeed) { object->player->drawangle = spring->angle; - if (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0) + if (vertispeed || (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0)) { object->angle = spring->angle; From a6a3048c8f9ae1c8dd914754789f12713f84c1af Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 29 Jul 2019 21:03:28 +0100 Subject: [PATCH 22/47] * Fix diagonal spring ring assortments being forced up/down with slopes. --- src/p_mobj.c | 82 +++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1cb7f742d..7c50967cb 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12355,28 +12355,33 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) if (nightsreplace) ringthing = MT_NIGHTSSTAR; + if (mthing->options & MTF_OBJECTFLIP) + { + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[ringthing].height; + if (mthing->options >> ZSHIFT) + z -= ((mthing->options >> ZSHIFT) << FRACBITS); + } + else + { + z = ( +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight); + if (mthing->options >> ZSHIFT) + z += ((mthing->options >> ZSHIFT) << FRACBITS); + } + for (r = 1; r <= 5; r++) { if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : -#endif - sec->ceilingheight) - mobjinfo[ringthing].height - dist*r; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); - } + z -= dist; else - { - z = ( -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight) + dist*r; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); - } + z += dist; mobj = P_SpawnMobj(x, y, z, ringthing); @@ -12410,31 +12415,36 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) closestangle = FixedAngle(mthing->angle*FRACUNIT); fa = (closestangle >> ANGLETOFINESHIFT); + if (mthing->options & MTF_OBJECTFLIP) + { + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[ringthing].height; + if (mthing->options >> ZSHIFT) + z -= ((mthing->options >> ZSHIFT) << FRACBITS); + } + else + { + z = ( +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight); + if (mthing->options >> ZSHIFT) + z += ((mthing->options >> ZSHIFT) << FRACBITS); + } + for (r = 1; r <= iterations; r++) { x += FixedMul(64*FRACUNIT, FINECOSINE(fa)); y += FixedMul(64*FRACUNIT, FINESINE(fa)); if (mthing->options & MTF_OBJECTFLIP) - { - z = ( -#ifdef ESLOPE - sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : -#endif - sec->ceilingheight) - mobjinfo[ringthing].height - 64*FRACUNIT*r; - if (mthing->options >> ZSHIFT) - z -= ((mthing->options >> ZSHIFT) << FRACBITS); - } + z -= 64*FRACUNIT; else - { - z = ( -#ifdef ESLOPE - sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : -#endif - sec->floorheight) + 64*FRACUNIT*r; - if (mthing->options >> ZSHIFT) - z += ((mthing->options >> ZSHIFT) << FRACBITS); - } + z += 64*FRACUNIT; mobj = P_SpawnMobj(x, y, z, ringthing); From deaee586ed035859662037d10f2f5c152fda0c0e Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 29 Jul 2019 21:05:30 +0100 Subject: [PATCH 23/47] Make MANIASPHERES' #define'd away stuff also recreatable with SOC, since I want to release it publically if the team don't want it. --- src/info.c | 6 +++++- src/p_setup.c | 12 +----------- src/st_stuff.c | 6 +----- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/info.c b/src/info.c index a4446d657..0ae723546 100644 --- a/src/info.c +++ b/src/info.c @@ -1791,7 +1791,11 @@ state_t states[NUMSTATES] = // Blue Sphere for special stages {SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE - {SPR_SPHR, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS + {SPR_SPHR, FF_FULLBRIGHT +#ifdef MANIASPHERES + |FF_ANIMATE|FF_RANDOMANIM +#endif + , -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS {SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK // Bomb Sphere diff --git a/src/p_setup.c b/src/p_setup.c index c0aa7ffa3..0b391f390 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -859,12 +859,7 @@ void P_ReloadRings(void) mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) ->sector->floorheight>>FRACBITS); - P_SpawnHoopsAndRings(mt, -#ifdef MANIASPHERES - true); -#else - !G_IsSpecialStage(gamemap)); // prevent flashing spheres in special stages -#endif + P_SpawnHoopsAndRings(mt, true); } } for (i = 0; i < numHoops; i++) @@ -878,11 +873,6 @@ void P_SwitchSpheresBonusMode(boolean bonustime) mobj_t *mo; thinker_t *th; -#ifndef MANIASPHERES - if (G_IsSpecialStage(gamemap)) // prevent flashing spheres in special stages - return; -#endif - // scan the thinkers to find spheres to switch for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { diff --git a/src/st_stuff.c b/src/st_stuff.c index 4122793ad..3b8fc749d 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1617,12 +1617,8 @@ static void ST_drawNiGHTSHUD(void) #endif ST_DrawTopLeftOverlayPatch(16, 8, nbracket); if (G_IsSpecialStage(gamemap)) -#ifdef MANIASPHERES ST_DrawTopLeftOverlayPatch(24, 16, ( - (stplyr->bonustime && (leveltime & 4)) ? nssbon : nsshud)); -#else - ST_DrawTopLeftOverlayPatch(24, 16, (nsshud)); -#endif + (stplyr->bonustime && (leveltime & 4) && (states[S_BLUESPHEREBONUS].frame & FF_ANIMATE)) ? nssbon : nsshud)); else ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12))); From f141220e824363713ed758e129316976677e81df Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 29 Jul 2019 22:13:12 +0100 Subject: [PATCH 24/47] Added escape pod. Okay, now I'm truly done with this branch. https://cdn.discordapp.com/attachments/249925765423038464/605506507345362964/srb20033.gif --- src/f_finale.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/f_finale.c b/src/f_finale.c index cb315be03..3d1b2ab83 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -104,6 +104,7 @@ static patch_t *endfwrk[3]; // firework - replaced with skin when good ending static patch_t *endspkl[3]; // sparkle static patch_t *endglow[2]; // glow aura - replaced with black rock's midway through good ending static patch_t *endxpld[4]; // mini explosion +static patch_t *endescp[5]; // escape pod + flame static INT32 sparkloffs[3][2]; // eggrock explosions/blackrock sparkles static INT32 sparklloop; @@ -1571,6 +1572,12 @@ void F_StartEnding(void) endxpld[2] = W_CachePatchName("ENDXPLD2", PU_LEVEL); endxpld[3] = W_CachePatchName("ENDXPLD3", PU_LEVEL); + endescp[0] = W_CachePatchName("ENDESCP0", PU_LEVEL); + endescp[1] = W_CachePatchName("ENDESCP1", PU_LEVEL); + endescp[2] = W_CachePatchName("ENDESCP2", PU_LEVEL); + endescp[3] = W_CachePatchName("ENDESCP3", PU_LEVEL); + endescp[4] = W_CachePatchName("ENDESCP4", PU_LEVEL); + // so we only need to check once if ((goodending = ALL7EMERALDS(emeralds))) { @@ -1703,6 +1710,20 @@ void F_EndingDrawer(void) V_DrawFixedPatch(-(x/5), -(y/5), FRACUNIT, 0, endbgsp[1], NULL); // sun V_DrawFixedPatch( 0, -(y/2), FRACUNIT, 0, endbgsp[2], NULL); // planet + // player's escape pod + V_DrawFixedPatch((200< -19) + { + INT32 trans = (-parallaxticker)>>1; + if (trans < 0) + trans = 0; + V_DrawFixedPatch((200< 0) // gunchedrock { INT32 scale = FRACUNIT + ((parallaxticker-10)<<7); From 66f84efd02cf24f141d34d0ce31fe2b61b6cd776 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Mon, 29 Jul 2019 17:56:35 -0400 Subject: [PATCH 25/47] SDL2: fixed compiling mixer interface with MSVC --- src/sdl/mixer_sound.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index a1319dbec..6e92a6f0b 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -98,8 +98,8 @@ static INT32 current_track; static void var_cleanup(void) { - loop_point = song_length =\ - music_bytes = fading_source = fading_target =\ + song_length = loop_point = 0.0f; + music_bytes = fading_source = fading_target =\ fading_timer = fading_duration = 0; songpaused = is_looping =\ @@ -569,7 +569,7 @@ static void music_loop(void) { Mix_PlayMusic(music, 0); Mix_SetMusicPosition(loop_point); - music_bytes = loop_point*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition) + music_bytes = (UINT32)(loop_point*44100.0L*4); //assume 44.1khz, 4-byte length (see I_GetSongPosition) } else I_StopSong(); @@ -843,7 +843,7 @@ boolean I_SetSongPosition(UINT32 position) Mix_RewindMusic(); // needed for mp3 if(Mix_SetMusicPosition((float)(position/1000.0L)) == 0) - music_bytes = position/1000.0L*44100.0L*4; //assume 44.1khz, 4-byte length (see I_GetSongPosition) + music_bytes = (UINT32)(position/1000.0L*44100.0L*4); //assume 44.1khz, 4-byte length (see I_GetSongPosition) else // NOTE: This block fires on incorrect song format, // NOT if position input is greater than song length. @@ -887,7 +887,7 @@ UINT32 I_GetSongPosition(void) if (!music || I_SongType() == MU_MID) return 0; else - return music_bytes/44100.0L*1000.0L/4; //assume 44.1khz + return (UINT32)(music_bytes/44100.0L*1000.0L/4); //assume 44.1khz // 4 = byte length for 16-bit samples (AUDIO_S16SYS), stereo (2-channel) // This is hardcoded in I_StartupSound. Other formats for factor: // 8M: 1 | 8S: 2 | 16M: 2 | 16S: 4 From b77780e1e7bdff77a836f50c4e9ac9dde6a8b54c Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Mon, 29 Jul 2019 19:02:45 -0400 Subject: [PATCH 26/47] Fix building with MSVC --- src/p_saveg.c | 2 +- src/p_user.c | 2 +- src/r_things.c | 6 +++++- src/s_sound.c | 4 +++- src/sdl/Srb2SDL-vc10.vcxproj | 2 ++ src/sdl/Srb2SDL-vc10.vcxproj.filters | 7 +++++++ src/win32/Srb2win-vc10.vcxproj | 2 ++ src/win32/Srb2win-vc10.vcxproj.filters | 8 ++++++++ 8 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/p_saveg.c b/src/p_saveg.c index 2e4ba9228..09df38eb0 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3408,7 +3408,7 @@ static void P_NetUnArchiveThinkers(void) { for (;;) { - thinker_t* th; + thinker_t* th = NULL; tclass = READUINT8(save_p); if (tclass == tc_end) diff --git a/src/p_user.c b/src/p_user.c index 6761d567d..b758cebe4 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2049,7 +2049,7 @@ boolean P_PlayerHitFloor(player_t *player) fixed_t mu = FixedMul(player->maxdash, player->mo->scale); fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); fixed_t ev; - mobj_t *missile; + mobj_t *missile = NULL; if (mu2 < mu) mu2 = mu; ev = (50*FRACUNIT - (mu/25))/50; diff --git a/src/r_things.c b/src/r_things.c index 4b1586455..c791571ac 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2446,9 +2446,11 @@ static void R_DrawMaskedList (drawnode_t* head) void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) { - drawnode_t heads[nummasks]; /**< Drawnode lists; as many as number of views/portals. */ + drawnode_t *heads; /**< Drawnode lists; as many as number of views/portals. */ SINT8 i; + heads = calloc(nummasks, sizeof(drawnode_t)); + for (i = 0; i < nummasks; i++) { heads[i].next = heads[i].prev = &heads[i]; @@ -2474,6 +2476,8 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) R_DrawMaskedList(&heads[nummasks - 1]); R_ClearDrawNodes(&heads[nummasks - 1]); } + + free(heads); } // ========================================================================== diff --git a/src/s_sound.c b/src/s_sound.c index 2db8392d7..66b5d4f72 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1988,8 +1988,10 @@ void GameMIDIMusic_OnChange(void) } } +#ifdef HAVE_OPENMPT void ModFilter_OnChange(void) { if (openmpt_mhandle) openmpt_module_set_render_param(openmpt_mhandle, OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, cv_modfilter.value); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index d05a0d324..72c38b3dc 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -277,6 +277,7 @@ + @@ -430,6 +431,7 @@ + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index ca6bd38d2..9e442000f 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -453,6 +453,9 @@ Hw_Hardware + + R_Rend + @@ -894,6 +897,10 @@ Hw_Hardware + + + R_Rend + diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index acab2507a..c0fe8eda9 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -293,6 +293,7 @@ + @@ -443,6 +444,7 @@ + diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters index c21cedb8a..93806e395 100644 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ b/src/win32/Srb2win-vc10.vcxproj.filters @@ -456,6 +456,10 @@ Hw_Hardware + + + R_Rend + @@ -857,6 +861,10 @@ Hw_Hardware + + + R_Rend + From 18e43a5cef6a45ee1f4c5c779bcf8e48ff9e7d65 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 30 Jul 2019 16:44:40 +0100 Subject: [PATCH 27/47] * Fix "exitlevel" being counted as a special stage success despite not giving you an emerald by inverting stagefailed's default value, since there's only a limited number of ways you can WIN at a special stage. * Correct a potential source of desync in P_GiveEmerald. --- src/p_inter.c | 3 +++ src/p_setup.c | 2 +- src/p_tick.c | 3 --- src/p_user.c | 37 ++++++++++++++++++++++++++++++------- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index abf33429f..486c39fb7 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -670,7 +670,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_DoMatchSuper(player); } else + { emeralds |= special->info->speed; + stagefailed = false; + } if (special->target && special->target->type == MT_EMERALDSPAWN) { diff --git a/src/p_setup.c b/src/p_setup.c index c0aa7ffa3..976d19190 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2215,7 +2215,7 @@ static void P_LevelInitStuff(void) ssspheres = timeinmap = 0; // special stage - stagefailed = false; + stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial // Reset temporary record data memset(&ntemprecords, 0, sizeof(nightsdata_t)); diff --git a/src/p_tick.c b/src/p_tick.c index a0f6edef9..cfdd54eb2 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -518,10 +518,7 @@ static inline void P_DoSpecialStageStuff(void) } } else - { sstimer = 0; - stagefailed = true; - } } } diff --git a/src/p_user.c b/src/p_user.c index b758cebe4..cdf8c246c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -302,15 +302,39 @@ void P_GiveEmerald(boolean spawnObj) S_StartSound(NULL, sfx_cgot); // Got the emerald! emeralds |= (1 << em); + stagefailed = false; - if (spawnObj && playeringame[consoleplayer]) + if (spawnObj) { // The Chaos Emerald begins to orbit us! - // Only give it to ONE person! - mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD); - P_SetTarget(&emmo->target, players[consoleplayer].mo); - P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); - P_SetTarget(&players[consoleplayer].mo->tracer, emmo); + // Only visibly give it to ONE person! + UINT8 i, pnum = ((playeringame[consoleplayer]) && (!players[consoleplayer].spectator) && (players[consoleplayer].mo)) ? consoleplayer : 255; + for (i = 0; i < MAXPLAYERS; i++) + { + mobj_t *emmo; + if (!playeringame[i]) + continue; + if (players[i].spectator) + continue; + if (!players[i].mo) + continue; + + emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD); + P_SetTarget(&emmo->target, players[i].mo); + P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em); + P_SetTarget(&players[i].mo->tracer, emmo); + + if (pnum == 255) + { + i = pnum; + continue; + } + + if (i == pnum) + continue; + + emmo->flags2 |= MF2_DONTDRAW; + } } } @@ -615,7 +639,6 @@ static void P_DeNightserizePlayer(player_t *player) if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE) players[i].nightstime = 1; // force everyone else to fall too. player->exiting = 3*TICRATE; - stagefailed = true; // NIGHT OVER // If you screwed up, kiss your score and ring bonus goodbye. // But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground. From d541bb7eadb791416450d13cf7e2d28e541f2677 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 30 Jul 2019 17:24:21 +0100 Subject: [PATCH 28/47] * Fix something I neglected earlier when fixing Ghosts and Replays for 2.2 - the fact that the player's skin will change if they don't have NiGHTS sprites like Sonic does not being accomodated. --- src/g_game.c | 8 +++++++- src/g_game.h | 4 +++- src/p_user.c | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 95cc2288d..3cb5da1b5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4366,7 +4366,7 @@ void G_WriteGhostTic(mobj_t *ghost) ghostext.flags = 0; } - if (ghost->player && ghost->player->followmobj) + if (ghost->player && ghost->player->followmobj) // bloats tails runs but what can ya do { INT16 temp; @@ -4592,6 +4592,9 @@ void G_GhostTicker(void) switch(g->color) { default: + case GHC_RETURNSKIN: + g->mo->skin = g->oldmo.skin; + // fallthru case GHC_NORMAL: // Go back to skin color g->mo->color = g->oldmo.color; break; @@ -4602,6 +4605,9 @@ void G_GhostTicker(void) case GHC_FIREFLOWER: // Fireflower g->mo->color = SKINCOLOR_WHITE; break; + case GHC_NIGHTSSKIN: // not actually a colour + g->mo->skin = &skins[DEFAULTNIGHTSSKIN]; + break; } } if (xziptic & EZT_FLIP) diff --git a/src/g_game.h b/src/g_game.h index 3cbde9a3c..96a192ee8 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -140,7 +140,9 @@ typedef enum GHC_NORMAL = 0, GHC_SUPER, GHC_FIREFLOWER, - GHC_INVINCIBLE + GHC_INVINCIBLE, + GHC_NIGHTSSKIN, // not actually a colour + GHC_RETURNSKIN // ditto } ghostcolor_t; // Record/playback tics diff --git a/src/p_user.c b/src/p_user.c index cdf8c246c..7bd2af127 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -621,7 +621,7 @@ static void P_DeNightserizePlayer(player_t *player) player->mo->skin = &skins[player->skin]; player->followitem = skins[player->skin].followitem; player->mo->color = player->skincolor; - G_GhostAddColor(GHC_NORMAL); + G_GhostAddColor(GHC_RETURNSKIN); // Restore aiming angle if (player == &players[consoleplayer]) @@ -739,6 +739,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor; player->followitem = skins[DEFAULTNIGHTSSKIN].followitem; + G_GhostAddColor(GHC_NIGHTSSKIN); } player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE; From 69e573517f31a9b3c19d31f0f42f6e3cbde32862 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 30 Jul 2019 17:48:13 +0100 Subject: [PATCH 29/47] Fix lua scripts erroring on the title screen because they're run there but it's not counted as GS_LEVEL (aka #168). --- src/f_finale.h | 1 - src/g_state.h | 1 + src/lua_baselib.c | 2 +- src/lua_consolelib.c | 2 +- src/lua_maplib.c | 51 +++++++++++++++++--------------------------- src/lua_mobjlib.c | 9 ++++---- src/lua_playerlib.c | 9 ++++---- src/lua_thinkerlib.c | 9 ++++---- 8 files changed, 37 insertions(+), 47 deletions(-) diff --git a/src/f_finale.h b/src/f_finale.h index c0c6360c3..29e9b4d8c 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -82,7 +82,6 @@ typedef enum // Current menu parameters -extern UINT8 titlemapinaction; extern mobj_t *titlemapcameraref; extern char curbgname[8]; extern SINT8 curfadevalue; diff --git a/src/g_state.h b/src/g_state.h index 76c9bd16f..7ee0cfb63 100644 --- a/src/g_state.h +++ b/src/g_state.h @@ -50,6 +50,7 @@ typedef enum } gameaction_t; extern gamestate_t gamestate; +extern UINT8 titlemapinaction; extern UINT8 ultimatemode; // was sk_insane extern gameaction_t gameaction; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 1d69b238b..7592fdf48 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -33,7 +33,7 @@ #define NOHUD if (hud_running)\ return luaL_error(L, "HUD rendering code should not call this function!"); -#define INLEVEL if (gamestate != GS_LEVEL)\ +#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ return luaL_error(L, "This function can only be used in a level!"); boolean luaL_checkboolean(lua_State *L, int narg) { diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 98d18d8db..ed0295ca1 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -29,7 +29,7 @@ return luaL_error(L, "HUD rendering code should not call this function!"); #define NOHOOK if (!lua_lumploading)\ return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); // for functions only allowed within a level -#define INLEVEL if (gamestate != GS_LEVEL)\ +#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ return luaL_error(L, "This function can only be used in a level!"); static const char *cvname = NULL; diff --git a/src/lua_maplib.c b/src/lua_maplib.c index ded90daf0..1ab2828bf 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -29,6 +29,9 @@ #include "fastcmp.h" #include "doomstat.h" +#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ +return luaL_error(L, "This function can only be used in a level!"); + enum sector_e { sector_valid = 0, sector_floorheight, @@ -333,8 +336,7 @@ static int lib_iterateSectorThinglist(lua_State *L) mobj_t *state = NULL; mobj_t *thing = NULL; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sector.thinglist() directly, use it as 'for rover in sector.thinglist do end'."); @@ -369,8 +371,7 @@ static int lib_iterateSectorFFloors(lua_State *L) ffloor_t *state = NULL; ffloor_t *ffloor = NULL; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do end'."); @@ -1251,8 +1252,7 @@ static int bbox_get(lua_State *L) static int lib_iterateSectors(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sectors.iterate() directly, use it as 'for sector in sectors.iterate do end'."); lua_settop(L, 2); @@ -1270,8 +1270,7 @@ static int lib_iterateSectors(lua_State *L) static int lib_getSector(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) @@ -1305,8 +1304,7 @@ static int lib_numsectors(lua_State *L) static int lib_iterateSubsectors(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call subsectors.iterate() directly, use it as 'for subsector in subsectors.iterate do end'."); lua_settop(L, 2); @@ -1324,8 +1322,7 @@ static int lib_iterateSubsectors(lua_State *L) static int lib_getSubsector(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) @@ -1359,8 +1356,7 @@ static int lib_numsubsectors(lua_State *L) static int lib_iterateLines(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call lines.iterate() directly, use it as 'for line in lines.iterate do end'."); lua_settop(L, 2); @@ -1378,8 +1374,7 @@ static int lib_iterateLines(lua_State *L) static int lib_getLine(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) @@ -1413,8 +1408,7 @@ static int lib_numlines(lua_State *L) static int lib_iterateSides(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call sides.iterate() directly, use it as 'for side in sides.iterate do end'."); lua_settop(L, 2); @@ -1432,8 +1426,7 @@ static int lib_iterateSides(lua_State *L) static int lib_getSide(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) @@ -1467,8 +1460,7 @@ static int lib_numsides(lua_State *L) static int lib_iterateVertexes(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call vertexes.iterate() directly, use it as 'for vertex in vertexes.iterate do end'."); lua_settop(L, 2); @@ -1486,8 +1478,7 @@ static int lib_iterateVertexes(lua_State *L) static int lib_getVertex(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) @@ -1523,8 +1514,7 @@ static int lib_numvertexes(lua_State *L) static int lib_iterateSegs(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do end'."); lua_settop(L, 2); @@ -1542,8 +1532,7 @@ static int lib_iterateSegs(lua_State *L) static int lib_getSeg(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) @@ -1577,8 +1566,7 @@ static int lib_numsegs(lua_State *L) static int lib_iterateNodes(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do end'."); lua_settop(L, 2); @@ -1596,8 +1584,7 @@ static int lib_iterateNodes(lua_State *L) static int lib_getNode(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 8bbbebe1d..5ddcb0ca7 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -22,6 +22,9 @@ #include "lua_libs.h" #include "lua_hud.h" // hud_running errors +#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ +return luaL_error(L, "This function can only be used in a level!"); + static const char *const array_opt[] ={"iterate",NULL}; enum mobj_e { @@ -816,8 +819,7 @@ static int mapthing_set(lua_State *L) static int lib_iterateMapthings(lua_State *L) { size_t i = 0; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) return luaL_error(L, "Don't call mapthings.iterate() directly, use it as 'for mapthing in mapthings.iterate do end'."); lua_settop(L, 2); @@ -835,8 +837,7 @@ static int lib_iterateMapthings(lua_State *L) static int lib_getMapthing(lua_State *L) { int field; - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 700dab211..c4b092c6f 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -22,11 +22,13 @@ #include "lua_libs.h" #include "lua_hud.h" // hud_running errors +#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ +return luaL_error(L, "This function can only be used in a level!"); + static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL if (lua_gettop(L) < 2) { //return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do end'."); @@ -53,8 +55,7 @@ static int lib_getPlayer(lua_State *L) { const char *field; // i -> players[i] - if (gamestate != GS_LEVEL) - return luaL_error(L, "You cannot access this outside of a level!"); + INLEVEL if (lua_type(L, 2) == LUA_TNUMBER) { lua_Integer i = luaL_checkinteger(L, 2); diff --git a/src/lua_thinkerlib.c b/src/lua_thinkerlib.c index 63eb15846..8fa2869c8 100644 --- a/src/lua_thinkerlib.c +++ b/src/lua_thinkerlib.c @@ -16,6 +16,9 @@ #include "lua_script.h" #include "lua_libs.h" +#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ +return luaL_error(L, "This function can only be used in a level!"); + #define META_ITERATIONSTATE "iteration state" /*static const char *const iter_opt[] = { @@ -56,8 +59,7 @@ static int lib_iterateThinkers(lua_State *L) thinker_t *th = NULL, *next = NULL; struct iterationState *it; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL it = luaL_checkudata(L, 1, META_ITERATIONSTATE); @@ -112,8 +114,7 @@ static int lib_startIterate(lua_State *L) { struct iterationState *it; - if (gamestate != GS_LEVEL) - return luaL_error(L, "This function can only be used in a level!"); + INLEVEL lua_pushvalue(L, lua_upvalueindex(1)); it = lua_newuserdata(L, sizeof(struct iterationState)); From 7bff3056720c34bd7419ca3ace4903da0951e418 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 30 Jul 2019 17:57:57 +0100 Subject: [PATCH 30/47] * Strip the word "function" from INLEVEL error messages, since they're now shared between access and function cases. * Move it into lua_script.h, so it's available to everything that needs it. --- src/lua_baselib.c | 2 -- src/lua_consolelib.c | 3 --- src/lua_maplib.c | 3 --- src/lua_mobjlib.c | 3 --- src/lua_playerlib.c | 3 --- src/lua_script.h | 4 ++++ src/lua_thinkerlib.c | 3 --- 7 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 7592fdf48..3fd58f637 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -33,8 +33,6 @@ #define NOHUD if (hud_running)\ return luaL_error(L, "HUD rendering code should not call this function!"); -#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ -return luaL_error(L, "This function can only be used in a level!"); boolean luaL_checkboolean(lua_State *L, int narg) { luaL_checktype(L, narg, LUA_TBOOLEAN); diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index ed0295ca1..c6856b426 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -28,9 +28,6 @@ return luaL_error(L, "HUD rendering code should not call this function!"); // for functions not allowed in hooks or coroutines (supercedes above) #define NOHOOK if (!lua_lumploading)\ return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); -// for functions only allowed within a level -#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ -return luaL_error(L, "This function can only be used in a level!"); static const char *cvname = NULL; diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 1ab2828bf..82843db4e 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -29,9 +29,6 @@ #include "fastcmp.h" #include "doomstat.h" -#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ -return luaL_error(L, "This function can only be used in a level!"); - enum sector_e { sector_valid = 0, sector_floorheight, diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 5ddcb0ca7..de1b854f6 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -22,9 +22,6 @@ #include "lua_libs.h" #include "lua_hud.h" // hud_running errors -#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ -return luaL_error(L, "This function can only be used in a level!"); - static const char *const array_opt[] ={"iterate",NULL}; enum mobj_e { diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index c4b092c6f..b7bdaa1be 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -22,9 +22,6 @@ #include "lua_libs.h" #include "lua_hud.h" // hud_running errors -#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ -return luaL_error(L, "This function can only be used in a level!"); - static int lib_iteratePlayers(lua_State *L) { INT32 i = -1; diff --git a/src/lua_script.h b/src/lua_script.h index b690e4fa7..fcbca2937 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -15,6 +15,7 @@ #include "m_fixed.h" #include "doomtype.h" #include "d_player.h" +#include "g_state.h" #include "blua/lua.h" #include "blua/lualib.h" @@ -97,4 +98,7 @@ void COM_Lua_f(void); // uncomment if you want seg_t/node_t in Lua // #define HAVE_LUA_SEGS +#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ +return luaL_error(L, "This can only be used in a level!"); + #endif diff --git a/src/lua_thinkerlib.c b/src/lua_thinkerlib.c index 8fa2869c8..877294898 100644 --- a/src/lua_thinkerlib.c +++ b/src/lua_thinkerlib.c @@ -16,9 +16,6 @@ #include "lua_script.h" #include "lua_libs.h" -#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\ -return luaL_error(L, "This function can only be used in a level!"); - #define META_ITERATIONSTATE "iteration state" /*static const char *const iter_opt[] = { From 7cb02985f4707f95e4eecbb3102a2d8b8f5a261a Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 31 Jul 2019 23:17:17 +0100 Subject: [PATCH 31/47] * Added boss enable linedef (type 449). - Frontside x offset = boss ID (determined via parameter for all bosses) - Noclimb flag = disable mode - Bosses don't do a fuckin' THING - no state updates, no player searches, no sounds, no lua, no nothin' - and it's all totally netsynced. - The only thing they WILL do is flash infinitely if you hurt them, but this is designed for stuff where you're not meant to be in the same room as the boss til it's activated. - All bosses of all IDs are automatically enabled on mapload, then if an enable mode version of this linedef is present in the map for a specific boss id, that boss id is automatically disabled. * Add multi-boss support via parameter for: - All bosses' MT_BOSSFLYPOINT search - Boss 5's waypoint search - Oldbrak's waypoint search (this one's for you, jood) --- src/p_enemy.c | 52 ++++++++++++++++++++++++++++++-------- src/p_mobj.c | 70 +++++++++++++++++++++++++++++---------------------- src/p_mobj.h | 1 + src/p_saveg.c | 2 ++ src/p_setup.c | 1 + src/p_spec.c | 48 ++++++++++++++++++++++++++++++++++- 6 files changed, 132 insertions(+), 42 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 88405437c..18d6f20c0 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3878,6 +3878,8 @@ bossjustdie: } default: //eggmobiles { + UINT8 extrainfo = (mo->spawnpoint ? mo->spawnpoint->extrainfo : 0); + // Stop exploding and prepare to run. P_SetMobjState(mo, mo->info->xdeathstate); if (P_MobjWasRemoved(mo)) @@ -3897,6 +3899,9 @@ bossjustdie: if (mo2->type != MT_BOSSFLYPOINT) continue; + if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo) + continue; + // If this one's further then the last one, don't go for it. if (mo->target && P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) > @@ -12303,6 +12308,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) //INT32 locvar2 = var2; boolean avoidcenter; UINT32 i; + UINT8 extrainfo = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0); #ifdef HAVE_BLUA if (LUA_CallAction("A_Boss5FindWaypoint", actor)) return; @@ -12312,16 +12318,34 @@ void A_Boss5FindWaypoint(mobj_t *actor) if (locvar1 == 2) // look for the boss waypoint { - for (i = 0; i < nummapthings; i++) + thinker_t *th; + mobj_t *mo2; + P_SetTarget(&actor->tracer, NULL); + // Flee! Flee! Find a point to escape to! If none, just shoot upward! + // scan the thinkers to find the runaway point + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { - if (!mapthings[i].mobj) + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; - if (mapthings[i].mobj->type != MT_BOSSFLYPOINT) + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_BOSSFLYPOINT) continue; - P_SetTarget(&actor->tracer, mapthings[i].mobj); - break; + + if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo) + continue; + + // If this one's further then the last one, don't go for it. + if (actor->tracer && + P_AproxDistance(P_AproxDistance(actor->x - mo2->x, actor->y - mo2->y), actor->z - mo2->z) > + P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z)) + continue; + + // Otherwise... Do! + P_SetTarget(&actor->tracer, mo2); } - if (i == nummapthings) + if (!actor->tracer) return; // no boss flypoints found } else if (locvar1 == 1) // always go to ambush-marked waypoint @@ -12335,11 +12359,13 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (mapthings[i].mobj->type != MT_FANGWAYPOINT) continue; - if (mapthings[i].options & MTF_AMBUSH) - { - P_SetTarget(&actor->tracer, mapthings[i].mobj); - break; - } + if (mapthings[i].extrainfo != extrainfo) + continue; + if (!(mapthings[i].options & MTF_AMBUSH)) + continue; + + P_SetTarget(&actor->tracer, mapthings[i].mobj); + break; } if (i == nummapthings) @@ -12363,6 +12389,8 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (actor->tracer == mapthings[i].mobj) // this was your tracer last time continue; + if (mapthings[i].extrainfo != extrainfo) + continue; if (mapthings[i].options & MTF_AMBUSH) { if (avoidcenter) @@ -12418,6 +12446,8 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (actor->tracer == mapthings[i].mobj) // this was your tracer last time continue; + if (mapthings[i].extrainfo != extrainfo) + continue; if (mapthings[i].options & MTF_AMBUSH) { if (avoidcenter) diff --git a/src/p_mobj.c b/src/p_mobj.c index 1cb7f742d..fe0044634 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5236,6 +5236,7 @@ static void P_Boss7Thinker(mobj_t *mobj) INT32 i; boolean foundgoop = false; INT32 closestNum; + UINT8 extrainfo = (mobj->spawnpoint ? mobj->spawnpoint->extrainfo : 0); // Looks for players in goop. If you find one, try to jump on him. for (i = 0; i < MAXPLAYERS; i++) @@ -5261,17 +5262,23 @@ static void P_Boss7Thinker(mobj_t *mobj) continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint) - { - dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y); + if (mo2->type != MT_BOSS3WAYPOINT) + continue; + if (!mo2->spawnpoint) + continue; + if (mo2->spawnpoint->extrainfo != extrainfo) + continue; + if (mobj->health <= mobj->info->damage && !(mo2->spawnpoint->options & 7)) + continue; // don't jump to center - if (closestNum == -1 || dist < closestdist) - { - closestNum = (mo2->spawnpoint->options & 7); - closestdist = dist; - foundgoop = true; - } - } + dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y); + + if (!(closestNum == -1 || dist < closestdist)) + continue; + + closestNum = (mo2->spawnpoint->options & 7); + closestdist = dist; + foundgoop = true; } waypointNum = closestNum; break; @@ -5280,17 +5287,14 @@ static void P_Boss7Thinker(mobj_t *mobj) if (!foundgoop) { - if (mobj->z > 1056*FRACUNIT) - waypointNum = 0; - else + // Don't jump to the center when health is low. + // Force the player to beat you with missiles. + if (mobj->z <= 1056*FRACUNIT || mobj->health <= mobj->info->damage) waypointNum = 1 + P_RandomKey(4); + else + waypointNum = 0; } - // Don't jump to the center when health is low. - // Force the player to beat you with missiles. - if (mobj->health <= mobj->info->damage && waypointNum == 0) - waypointNum = 1 + P_RandomKey(4); - if (mobj->tracer && mobj->tracer->type == MT_BOSS3WAYPOINT && mobj->tracer->spawnpoint && (mobj->tracer->spawnpoint->options & 7) == waypointNum) { @@ -5299,15 +5303,12 @@ static void P_Boss7Thinker(mobj_t *mobj) else waypointNum--; - waypointNum %= 5; - - if (waypointNum < 0) - waypointNum = 0; + if (mobj->health <= mobj->info->damage) + waypointNum = ((waypointNum + 3) % 4) + 1; // plus four to avoid modulo being negative, minus one to avoid waypoint #0 + else + waypointNum = ((waypointNum + 5) % 5); } - if (waypointNum == 0 && mobj->health <= mobj->info->damage) - waypointNum = 1 + (P_RandomFixed() & 1); - // scan the thinkers to find // the waypoint to use for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -5316,11 +5317,17 @@ static void P_Boss7Thinker(mobj_t *mobj) continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && (mo2->spawnpoint->options & 7) == waypointNum) - { - hitspot = mo2; - break; - } + if (mo2->type != MT_BOSS3WAYPOINT) + continue; + if (!mo2->spawnpoint) + continue; + if ((mo2->spawnpoint->options & 7) != waypointNum) + continue; + if (mo2->spawnpoint->extrainfo != extrainfo) + continue; + + hitspot = mo2; + break; } if (hitspot == NULL) @@ -7667,6 +7674,9 @@ void P_MobjThinker(mobj_t *mobj) } else if (mobj->flags & MF_BOSS) { + if (mobj->spawnpoint && (mobj->spawnpoint->extrainfo < 16) && (bossdisabled & (1<spawnpoint->extrainfo))) + return; + #ifdef HAVE_BLUA if (LUAh_BossThinker(mobj)) { diff --git a/src/p_mobj.h b/src/p_mobj.h index bfcb09210..77791f928 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -470,4 +470,5 @@ extern INT32 numhuntemeralds; extern boolean runemeraldmanager; extern UINT16 emeraldspawndelay; extern INT32 numstarposts; +extern UINT16 bossdisabled; #endif diff --git a/src/p_saveg.c b/src/p_saveg.c index 09df38eb0..24b68b971 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3990,6 +3990,7 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, leveltime); WRITEUINT32(save_p, ssspheres); WRITEINT16(save_p, lastmap); + WRITEUINT16(save_p, bossdisabled); WRITEUINT16(save_p, emeralds); WRITEUINT8(save_p, stagefailed); @@ -4067,6 +4068,7 @@ static inline boolean P_NetUnArchiveMisc(void) leveltime = READUINT32(save_p); ssspheres = READUINT32(save_p); lastmap = READINT16(save_p); + bossdisabled = READUINT16(save_p); emeralds = READUINT16(save_p); stagefailed = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index c0aa7ffa3..4d713881d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -102,6 +102,7 @@ line_t *lines; side_t *sides; mapthing_t *mapthings; INT32 numstarposts; +UINT16 bossdisabled; boolean levelloading; UINT8 levelfadecol; diff --git a/src/p_spec.c b/src/p_spec.c index 3cd0461e2..f1fb5c82f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3554,6 +3554,29 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; + case 449: // Enable bosses with parameter + { + INT32 bossid = sides[line->sidenum[0]].textureoffset>>FRACBITS; + if (bossid & ~15) // if any bits other than first 16 are set + { + CONS_Alert(CONS_WARNING, + M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), + line->tag); + break; + } + if (line->flags & ML_NOCLIMB) + { + bossdisabled |= (1<tag, mo, NULL); break; @@ -6399,7 +6422,10 @@ void P_SpawnSpecials(INT32 fromnetsave) // This used to be used, and *should* be used in the future, // but currently isn't. - (void)fromnetsave; + //(void)fromnetsave; -- hooray, it's used! + + if (!fromnetsave) + bossdisabled = 0; // Init special SECTORs. sector = sectors; @@ -7289,6 +7315,26 @@ void P_SpawnSpecials(INT32 fromnetsave) case 431: break; + case 449: // Enable bosses with parameter + { + INT32 bossid = sides[*lines[i].sidenum].textureoffset>>FRACBITS; + if (bossid & ~15) // if any bits other than first 16 are set + { + CONS_Alert(CONS_WARNING, + M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), + lines[i].tag); + break; + } + if (fromnetsave) + break; + if (!(lines[i].flags & ML_NOCLIMB)) + { + bossdisabled |= (1< Date: Thu, 1 Aug 2019 11:35:04 +0100 Subject: [PATCH 32/47] Ok, now the MobjThinker Lua hook is neutralised properly as well. --- src/p_mobj.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index fe0044634..fe45a799a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7011,6 +7011,9 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->flags & MF_NOTHINK) return; + if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && !(mobj->spawnpoint->extrainfo & ~15) && (bossdisabled & (1<spawnpoint->extrainfo))) + return; + // Remove dead target/tracer. if (mobj->target && P_MobjWasRemoved(mobj->target)) P_SetTarget(&mobj->target, NULL); @@ -7674,9 +7677,6 @@ void P_MobjThinker(mobj_t *mobj) } else if (mobj->flags & MF_BOSS) { - if (mobj->spawnpoint && (mobj->spawnpoint->extrainfo < 16) && (bossdisabled & (1<spawnpoint->extrainfo))) - return; - #ifdef HAVE_BLUA if (LUAh_BossThinker(mobj)) { From 39c15e71b061099465938907fe2398102fc5411b Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 1 Aug 2019 08:01:29 -0400 Subject: [PATCH 33/47] Was reviewing old merge requests as a procrastination technique, and discovered that the followmobj's scale was being inaccurately handled for Smiles' tails! Fixed that... --- src/p_user.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index b758cebe4..2ca6c3535 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11641,7 +11641,6 @@ void P_PlayerAfterThink(player_t *player) player->followmobj->threshold = player->mo->z; player->followmobj->movecount = player->panim; player->followmobj->angle = horizangle; - player->followmobj->scale = player->mo->scale; P_SetScale(player->followmobj, player->mo->scale); player->followmobj->destscale = player->mo->destscale; player->followmobj->radius = player->mo->radius; From 8fa0641e99b47573184238ce03eb563ab3d890f4 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 1 Aug 2019 18:12:12 +0100 Subject: [PATCH 34/47] Instead of checking whether mobj->spawnpoint->extrainfo is in the correct range every tic, have a lua error for trying to set it outside (since there'll no doubt be other consequences to being outside the range too) --- src/lua_mobjlib.c | 7 ++++++- src/p_mobj.c | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 8bbbebe1d..5fc3babd3 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -804,7 +804,12 @@ static int mapthing_set(lua_State *L) else if(fastcmp(field,"z")) mt->z = (INT16)luaL_checkinteger(L, 3); else if(fastcmp(field,"extrainfo")) - mt->extrainfo = (UINT8)luaL_checkinteger(L, 3); + { + INT32 extrainfo = luaL_checkinteger(L, 3); + if (extrainfo & ~15) + return luaL_error(L, "mapthing_t extrainfo set %d out of range (%d - %d)", extrainfo, 0, 15); + mt->extrainfo = (UINT8)extrainfo; + } else if(fastcmp(field,"mobj")) mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); else diff --git a/src/p_mobj.c b/src/p_mobj.c index fe45a799a..5b924c3eb 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7011,7 +7011,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->flags & MF_NOTHINK) return; - if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && !(mobj->spawnpoint->extrainfo & ~15) && (bossdisabled & (1<spawnpoint->extrainfo))) + if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<spawnpoint->extrainfo))) return; // Remove dead target/tracer. From 0821f7fb2168c6d063b05f7620baf28c35a52524 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Thu, 1 Aug 2019 18:56:00 +0100 Subject: [PATCH 35/47] Add openfloorrover and openceilingrover vars so that PIT_CheckLine can update tmfloorrover and tmceilingrover properly via P_LineOpening ...which should hopefully stop that issue where you just teleport back to the ground. Assuming this works as expected. Also this is untested lol. --- src/p_maputl.c | 13 +++++++++++++ src/p_maputl.h | 1 + 2 files changed, 14 insertions(+) diff --git a/src/p_maputl.c b/src/p_maputl.c index 0ca84096a..4dafbcc7f 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -311,6 +311,7 @@ fixed_t opentop, openbottom, openrange, lowfloor, highceiling; #ifdef ESLOPE pslope_t *opentopslope, *openbottomslope; #endif +ffloor_t *openfloorrover, *openceilingrover; // P_CameraLineOpening // P_LineOpening, but for camera @@ -517,6 +518,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) I_Assert(front != NULL); I_Assert(back != NULL); + openfloorrover = openceilingrover = NULL; + { // Set open and high/low values here fixed_t frontheight, backheight; @@ -641,6 +644,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) pslope_t *ceilingslope = opentopslope; pslope_t *floorslope = openbottomslope; #endif + ffloor_t *floorrover = NULL; + ffloor_t *ceilingrover = NULL; // Check for frontsector's fake floors for (rover = front->ffloors; rover; rover = rover->next) @@ -668,6 +673,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE ceilingslope = *rover->b_slope; #endif + ceilingrover = rover; } else if (bottomheight < highestceiling) highestceiling = bottomheight; @@ -680,6 +686,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE floorslope = *rover->t_slope; #endif + floorrover = rover; } else if (topheight > lowestfloor) lowestfloor = topheight; @@ -712,6 +719,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE ceilingslope = *rover->b_slope; #endif + ceilingrover = rover; } else if (bottomheight < highestceiling) highestceiling = bottomheight; @@ -724,6 +732,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE floorslope = *rover->t_slope; #endif + floorrover = rover; } else if (topheight > lowestfloor) lowestfloor = topheight; @@ -743,6 +752,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE ceilingslope = NULL; #endif + ceilingrover = NULL; } else if (polysec->floorheight < highestceiling && delta1 >= delta2) highestceiling = polysec->floorheight; @@ -752,6 +762,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE floorslope = NULL; #endif + floorrover = NULL; } else if (polysec->ceilingheight > lowestfloor && delta1 < delta2) lowestfloor = polysec->ceilingheight; @@ -765,6 +776,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE openbottomslope = floorslope; #endif + openfloorrover = floorrover; } if (lowestceiling < opentop) { @@ -772,6 +784,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE opentopslope = ceilingslope; #endif + openceilingrover = floorrover; } if (lowestfloor > lowfloor) diff --git a/src/p_maputl.h b/src/p_maputl.h index 1fcb68d4c..5042817c5 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -58,6 +58,7 @@ extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling; #ifdef ESLOPE extern pslope_t *opentopslope, *openbottomslope; #endif +extern ffloor_t *openfloorrover, *openceilingrover; void P_LineOpening(line_t *plinedef, mobj_t *mobj); From 67f7c9d7d9d0bcdbc7588d464bad57743e5c08b4 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Thu, 1 Aug 2019 20:17:15 +0100 Subject: [PATCH 36/47] Whoops, forgot this part --- src/p_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index e78dd1e84..f7e1d72c8 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1808,7 +1808,7 @@ static boolean PIT_CheckLine(line_t *ld) { tmceilingz = opentop; ceilingline = ld; - tmceilingrover = NULL; + tmceilingrover = openceilingrover; #ifdef ESLOPE tmceilingslope = opentopslope; #endif @@ -1817,7 +1817,7 @@ static boolean PIT_CheckLine(line_t *ld) if (openbottom > tmfloorz) { tmfloorz = openbottom; - tmfloorrover = NULL; + tmfloorrover = openfloorrover; #ifdef ESLOPE tmfloorslope = openbottomslope; #endif From ac058529c5b2a7287afd479648ec76e6cfe9cbfd Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Thu, 1 Aug 2019 20:48:24 +0100 Subject: [PATCH 37/47] Whoops the second --- src/p_maputl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_maputl.c b/src/p_maputl.c index 4dafbcc7f..740797fb0 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -784,7 +784,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) #ifdef ESLOPE opentopslope = ceilingslope; #endif - openceilingrover = floorrover; + openceilingrover = ceilingrover; } if (lowestfloor > lowfloor) From f2349c5ce485ef169fcc9322e790e722cd0744c6 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Aug 2019 13:18:57 +0100 Subject: [PATCH 38/47] fixed sphere's CA2_MELEE stasis issue --- src/p_user.c | 77 +++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 29e29d7c1..4a804ace8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2037,47 +2037,50 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) else player->pflags &= ~PF_GLIDING; } - else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING) + else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) { - mobjtype_t type = player->revitem; - 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; - - // hearticles - if (type) + if (player->mo->state-states != S_PLAY_MELEE_LANDING) { - UINT8 i = 0; - angle_t throwang = -(2*ANG30); - fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); - fixed_t zo = 6*player->mo->scale; - fixed_t mu = FixedMul(player->maxdash, player->mo->scale); - fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); - fixed_t ev; - mobj_t *missile = NULL; - if (mu2 < mu) - mu2 = mu; - ev = (50*FRACUNIT - (mu/25))/50; - while (i < 5) - { - missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); - P_SetTarget(&missile->target, player->mo); - missile->angle = throwang + player->drawangle; - P_Thrust(missile, player->drawangle + ANGLE_90, - P_ReturnThrustY(missile, throwang, mu)); // side to side component - P_Thrust(missile, player->drawangle, mu2); // forward component - P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); - missile->momz += player->mo->pmomz; - missile->fuse = TICRATE/2; - missile->extravalue2 = ev; + mobjtype_t type = player->revitem; + 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; - i++; - throwang += ANG30; + // hearticles + if (type) + { + UINT8 i = 0; + angle_t throwang = -(2*ANG30); + fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale); + fixed_t zo = 6*player->mo->scale; + fixed_t mu = FixedMul(player->maxdash, player->mo->scale); + fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy); + fixed_t ev; + mobj_t *missile = NULL; + if (mu2 < mu) + mu2 = mu; + ev = (50*FRACUNIT - (mu/25))/50; + while (i < 5) + { + missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type); + P_SetTarget(&missile->target, player->mo); + missile->angle = throwang + player->drawangle; + P_Thrust(missile, player->drawangle + ANGLE_90, + P_ReturnThrustY(missile, throwang, mu)); // side to side component + P_Thrust(missile, player->drawangle, mu2); // forward component + P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true); + missile->momz += player->mo->pmomz; + missile->fuse = TICRATE/2; + missile->extravalue2 = ev; + + i++; + throwang += ANG30; + } + if (mobjinfo[type].seesound && missile) + S_StartSound(missile, missile->info->seesound); } - if (mobjinfo[type].seesound && missile) - S_StartSound(missile, missile->info->seesound); } } else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) From 42a36de4595fc55fdbba6ffcd61d94690cf174b6 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 2 Aug 2019 16:51:44 +0100 Subject: [PATCH 39/47] Modify P_CheckSector with a modified version of Sal's attempted proper fix for polyobjects crushing, so that we only need to check the polyobject's control sector directly in the waypoints code. This time I've definitely fixed that teleport to ground issue I'm pretty sure, I don't get it in my tests at least. --- src/p_map.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++- src/p_polyobj.c | 8 ++-- 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index f7e1d72c8..76bb99bff 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2089,6 +2089,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) #ifdef ESLOPE tmfloorslope = NULL; #endif + tmfloorrover = NULL; } if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) { @@ -2096,6 +2097,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) #ifdef ESLOPE tmceilingslope = NULL; #endif + tmceilingrover = NULL; } } plink = (polymaplink_t *)(plink->link.next); @@ -4079,6 +4081,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush) boolean P_CheckSector(sector_t *sector, boolean crunch) { msecnode_t *n; + size_t i; nofit = false; crushchange = crunch; @@ -4093,9 +4096,57 @@ boolean P_CheckSector(sector_t *sector, boolean crunch) // First, let's see if anything will keep it from crushing. + + // Sal: This stupid function chain is required to fix polyobjects not being able to crush. + // Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead + validcount++; + + for (i = 0; i < sector->linecount; i++) + { + if (sector->lines[i]->polyobj) + { + polyobj_t *po = sector->lines[i]->polyobj; + if (po->validcount == validcount) + continue; // skip if already checked + if (!(po->flags & POF_SOLID)) + continue; + if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector + { + INT32 x, y; + po->validcount = validcount; + + for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y) + { + for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x) + { + mobj_t *mo; + + if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) + continue; + + mo = blocklinks[y * bmapwidth + x]; + + for (; mo; mo = mo->bnext) + { + // Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect + + if (!P_MobjTouchingPolyobj(po, mo)) + continue; + + if (!PIT_ChangeSector(mo, false)) + { + nofit = true; + return nofit; + } + } + } + } + } + } + } + if (sector->numattached) { - size_t i; sector_t *sec; for (i = 0; i < sector->numattached; i++) { @@ -4155,9 +4206,53 @@ boolean P_CheckSector(sector_t *sector, boolean crunch) } while (n); // repeat from scratch until all things left are marked valid // Nothing blocked us, so lets crush for real! + + // Sal: This stupid function chain is required to fix polyobjects not being able to crush. + // Monster Iestyn: don't use P_CheckSector actually just look for objects in the blockmap instead + validcount++; + + for (i = 0; i < sector->linecount; i++) + { + if (sector->lines[i]->polyobj) + { + polyobj_t *po = sector->lines[i]->polyobj; + if (po->validcount == validcount) + continue; // skip if already checked + if (!(po->flags & POF_SOLID)) + continue; + if (po->lines[0]->backsector == sector) // Make sure you're currently checking the control sector + { + INT32 x, y; + po->validcount = validcount; + + for (y = po->blockbox[BOXBOTTOM]; y <= po->blockbox[BOXTOP]; ++y) + { + for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x) + { + mobj_t *mo; + + if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight) + continue; + + mo = blocklinks[y * bmapwidth + x]; + + for (; mo; mo = mo->bnext) + { + // Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect + + if (!P_MobjTouchingPolyobj(po, mo)) + continue; + + PIT_ChangeSector(mo, true); + return nofit; + } + } + } + } + } + } if (sector->numattached) { - size_t i; sector_t *sec; for (i = 0; i < sector->numattached; i++) { diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 475fa41b7..857e6f3d1 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1873,7 +1873,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight = target->z - amtz; po->lines[0]->backsector->ceilingheight = target->z + amtz; // Sal: Remember to check your sectors! - P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); + //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); // Apply action to mirroring polyobjects as well start = 0; @@ -1887,7 +1887,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight += diffz; // move up/down by same amount as the parent did po->lines[0]->backsector->ceilingheight += diffz; // Sal: Remember to check your sectors! - P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); + //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); } @@ -2050,7 +2050,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight += momz; po->lines[0]->backsector->ceilingheight += momz; // Sal: Remember to check your sectors! - P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // frontsector is NEEDED for crushing + //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // frontsector is NEEDED for crushing P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); // backsector may not be necessary, but just in case // Apply action to mirroring polyobjects as well @@ -2065,7 +2065,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight += momz; po->lines[0]->backsector->ceilingheight += momz; // Sal: Remember to check your sectors! - P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); + //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); } } From 8d561334256bc6704634004940fd066aed716b5f Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Aug 2019 20:02:55 +0100 Subject: [PATCH 40/47] Fix old Special Stage failure sounds not always playing. --- src/p_spec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index 3cd0461e2..7e1230528 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4601,7 +4601,10 @@ DoneSection2: if (player->bot) break; if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6) + { player->nightstime = 6; // Just let P_Ticker take care of the rest. + return; + } // Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c) { From c4f0fdb7837d4c4288bf711b5c2be67ee28a0974 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Aug 2019 22:52:37 +0100 Subject: [PATCH 41/47] Perfect bonus support for non-NiGHTS special stages --- src/y_inter.c | 137 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 50 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index 992193964..42aee79de 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -86,8 +86,8 @@ typedef union INT32 passedx3; INT32 passedx4; - y_bonus_t bonus; - patch_t *bonuspatch; + y_bonus_t bonuses[2]; + patch_t *bonuspatches[2]; patch_t *pscore; // SCORE UINT32 score; // fake score @@ -326,34 +326,36 @@ void Y_IntermissionDrawer(void) // draw the header if (intertic <= 2*TICRATE) animatetic = 0; - else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0') + else if (!animatetic && data.spec.bonuses[0].points == 0 && data.spec.bonuses[1].points == 0 && data.spec.passed3[0] != '\0') animatetic = intertic + TICRATE; if (animatetic && (tic_t)intertic >= animatetic) { const INT32 scradjust = (vid.width/vid.dupx)>>3; // 40 for BASEVIDWIDTH INT32 animatetimer = (intertic - animatetic); - if (animatetimer <= 14) + if (animatetimer <= 16) { - xoffset1 = -(animatetimer * scradjust); - xoffset2 = -((animatetimer-2) * scradjust); - xoffset3 = -((animatetimer-4) * scradjust); - xoffset4 = -((animatetimer-6) * scradjust); - xoffset5 = -((animatetimer-8) * scradjust); + xoffset1 = -(animatetimer * scradjust); + xoffset2 = -((animatetimer- 2) * scradjust); + xoffset3 = -((animatetimer- 4) * scradjust); + xoffset4 = -((animatetimer- 6) * scradjust); + xoffset5 = -((animatetimer- 8) * scradjust); + xoffset6 = -((animatetimer-10) * scradjust); if (xoffset2 > 0) xoffset2 = 0; if (xoffset3 > 0) xoffset3 = 0; if (xoffset4 > 0) xoffset4 = 0; if (xoffset5 > 0) xoffset5 = 0; + if (xoffset6 > 0) xoffset6 = 0; } - else if (animatetimer < 32) + else if (animatetimer < 34) { drawsection = 1; - xoffset1 = (22-animatetimer) * scradjust; - xoffset2 = (24-animatetimer) * scradjust; - xoffset3 = (26-animatetimer) * scradjust; - xoffset4 = (28-animatetimer) * scradjust; - xoffset5 = (30-animatetimer) * scradjust; - xoffset6 = (32-animatetimer) * scradjust; + xoffset1 = (24-animatetimer) * scradjust; + xoffset2 = (26-animatetimer) * scradjust; + xoffset3 = (28-animatetimer) * scradjust; + xoffset4 = (30-animatetimer) * scradjust; + xoffset5 = (32-animatetimer) * scradjust; + xoffset6 = (34-animatetimer) * scradjust; if (xoffset1 < 0) xoffset1 = 0; if (xoffset2 < 0) xoffset2 = 0; if (xoffset3 < 0) xoffset3 = 0; @@ -370,9 +372,9 @@ void Y_IntermissionDrawer(void) if (drawsection == 1) { - const char *ringtext = "\x86" "50 RINGS, NO SHIELD"; - const char *tut1text = "\x86" "PRESS " "\x82" "SPIN"; - const char *tut2text = "\x86" "MID-" "\x82" "JUMP"; + const char *ringtext = "\x82" "50 RINGS, NO SHIELD"; + const char *tut1text = "\x82" "PRESS " "\x80" "SPIN"; + const char *tut2text = "\x82" "MID-" "\x80" "JUMP"; ttheight = 16; V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); ttheight += V_LevelNameHeight(data.spec.passed3) + 2; @@ -389,6 +391,7 @@ void Y_IntermissionDrawer(void) } else { + INT32 yoffset = 0; if (data.spec.passed1[0] != '\0') { ttheight = 24; @@ -402,22 +405,31 @@ void Y_IntermissionDrawer(void) V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); } - V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatch); - V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonus.points); - V_DrawScaledPatch(152 + xoffset4, 124, 0, data.spec.pscore); - V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125, 0, data.spec.score); + V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatches[0]); + V_DrawTallNum(BASEVIDWIDTH + xoffset3 - 68, 109, 0, data.spec.bonuses[0].points); + if (data.spec.bonuses[1].display) + { + V_DrawScaledPatch(152 + xoffset4, 124, 0, data.spec.bonuspatches[1]); + V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125, 0, data.spec.bonuses[1].points); + yoffset = 16; + // hack; pass the buck along... + xoffset4 = xoffset5; + xoffset5 = xoffset6; + } + V_DrawScaledPatch(152 + xoffset4, 124+yoffset, 0, data.spec.pscore); + V_DrawTallNum(BASEVIDWIDTH + xoffset4 - 68, 125+yoffset, 0, data.spec.score); // Draw continues! if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay { UINT8 continues = data.spec.continues & 0x7F; - V_DrawScaledPatch(152 + xoffset5, 150, 0, data.spec.pcontinues); + V_DrawScaledPatch(152 + xoffset5, 150+yoffset, 0, data.spec.pcontinues); for (i = 0; i < continues; ++i) { if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10)) break; - V_DrawContinueIcon(246 + xoffset5 - (i*12), 162, 0, *data.spec.playerchar, *data.spec.playercolor); + V_DrawContinueIcon(246 + xoffset5 - (i*12), 162+yoffset, 0, *data.spec.playerchar, *data.spec.playercolor); } } } @@ -904,7 +916,7 @@ void Y_Ticker(void) { INT32 i; UINT32 oldscore = data.spec.score; - boolean skip = false, super = false; + boolean skip = false, super = false, anybonuses = false; if (!intertic) // first time only { @@ -946,16 +958,26 @@ void Y_Ticker(void) return; } - // ring bonus counts down by 222 each tic - data.spec.bonus.points -= 222; - data.spec.score += 222; - if (data.spec.bonus.points < 0 || skip == true) // went too far + // bonuses count down by 222 each tic + for (i = 0; i < 2; ++i) { - data.spec.score += data.spec.bonus.points; - data.spec.bonus.points = 0; + if (!data.spec.bonuses[i].points) + continue; + + data.spec.bonuses[i].points -= 222; + data.spec.score += 222; + if (data.spec.bonuses[i].points < 0 || skip == true) // too far? + { + data.spec.score += data.spec.bonuses[i].points; + data.spec.bonuses[i].points = 0; + } + if (data.spec.score > MAXSCORE) + data.spec.score = MAXSCORE; + if (data.spec.bonuses[i].points > 0) + anybonuses = true; } - if (!data.spec.bonus.points) + if (!anybonuses) { tallydonetic = intertic; if (!((data.spec.continues & 0x80) || (super && ALL7EMERALDS(emeralds)))) // don't set endtic yet! @@ -1301,7 +1323,9 @@ void Y_StartIntermission(void) // give out ring bonuses Y_AwardSpecialStageBonus(); - data.spec.bonuspatch = W_CachePatchName(data.spec.bonus.patch, PU_STATIC); + for (i = 0; i < 2; ++i) + data.spec.bonuspatches[i] = W_CachePatchName(data.spec.bonuses[i].patch, PU_STATIC); + data.spec.pscore = W_CachePatchName("YB_SCORE", PU_STATIC); data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_STATIC); @@ -1831,7 +1855,7 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct) memset(bstruct, 0, sizeof(y_bonus_t)); strncpy(bstruct->patch, "YB_PERFE", sizeof(bstruct->patch)); - if (data.coop.gotperfbonus == -1) + if (intertype != int_coop || data.coop.gotperfbonus == -1) { INT32 sharedringtotal = 0; for (i = 0; i < MAXPLAYERS; i++) @@ -1840,15 +1864,17 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct) sharedringtotal += players[i].rings; } if (!sharedringtotal || nummaprings == -1 || sharedringtotal < nummaprings) - data.coop.gotperfbonus = 0; + bstruct->display = false; else - data.coop.gotperfbonus = 1; + { + bstruct->display = true; + bstruct->points = 50000; + } } - if (!data.coop.gotperfbonus) + if (intertype != int_coop) return; - bstruct->display = true; - bstruct->points = 50000; + data.coop.gotperfbonus = (bstruct->display ? 1 : 0); } // This list can be extended in the future with SOC/Lua, perhaps. @@ -1953,23 +1979,33 @@ static void Y_AwardCoopBonuses(void) static void Y_AwardSpecialStageBonus(void) { INT32 i, oldscore, ptlives; - y_bonus_t localbonus; + y_bonus_t localbonuses[2]; data.spec.score = players[consoleplayer].score; - memset(&data.spec.bonus, 0, sizeof(data.spec.bonus)); - data.spec.bonuspatch = NULL; + memset(data.spec.bonuses, 0, sizeof(data.spec.bonuses)); + memset(data.spec.bonuspatches, 0, sizeof(data.coop.bonuspatches)); for (i = 0; i < MAXPLAYERS; i++) { oldscore = players[i].score; if (!playeringame[i] || players[i].lives < 1) // not active or game over - Y_SetNullBonus(&players[i], &localbonus); - else if (maptol & TOL_NIGHTS) // Mare score instead of Rings - Y_SetNightsBonus(&players[i], &localbonus); + { + Y_SetNullBonus(&players[i], &localbonuses[0]); + Y_SetNullBonus(&players[i], &localbonuses[1]); + } + else if (maptol & TOL_NIGHTS) // NiGHTS bonus score instead of Rings + { + Y_SetNightsBonus(&players[i], &localbonuses[0]); + Y_SetNullBonus(&players[i], &localbonuses[1]); + } else - Y_SetRingBonus(&players[i], &localbonus); - players[i].score += localbonus.points; + { + Y_SetRingBonus(&players[i], &localbonuses[0]); + Y_SetPerfectBonus(&players[i], &localbonuses[1]); + } + players[i].score += localbonuses[0].points; + players[i].score += localbonuses[1].points; if (players[i].score > MAXSCORE) players[i].score = MAXSCORE; @@ -1982,7 +2018,7 @@ static void Y_AwardSpecialStageBonus(void) if (i == consoleplayer) { data.spec.gotlife = (((netgame || multiplayer) && gametype == GT_COOP && cv_cooplives.value == 0) ? 0 : ptlives); - M_Memcpy(&data.spec.bonus, &localbonus, sizeof(data.spec.bonus)); + M_Memcpy(&data.spec.bonuses, &localbonuses, sizeof(data.spec.bonuses)); // Continues related data.spec.continues = min(players[i].continues, 8); @@ -2057,7 +2093,8 @@ static void Y_UnloadData(void) // unload the special stage patches //UNLOAD(data.spec.cemerald); //UNLOAD(data.spec.nowsuper); - UNLOAD(data.spec.bonuspatch); + UNLOAD(data.spec.bonuspatches[1]); + UNLOAD(data.spec.bonuspatches[0]); UNLOAD(data.spec.pscore); UNLOAD(data.spec.pcontinues); break; From 16c541ef1b80b75d1ef41bbb3103307538e9d98f Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Aug 2019 23:51:22 +0100 Subject: [PATCH 42/47] Add rings to old/MP special stage HUD + make both them and spheres (in old special stage only) count down rather than up, to match s3k --- src/st_stuff.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 3b8fc749d..241e35143 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -110,6 +110,7 @@ static patch_t *orngstat; static patch_t *redstat; static patch_t *yelstat; static patch_t *nbracket; +static patch_t *nring; static patch_t *nhud[12]; static patch_t *nsshud; static patch_t *nbon[12]; @@ -311,6 +312,7 @@ void ST_LoadGraphics(void) redstat = W_CachePatchName("REDSTAT", PU_HUDGFX); yelstat = W_CachePatchName("YELSTAT", PU_HUDGFX); nbracket = W_CachePatchName("NBRACKET", PU_HUDGFX); + nring = W_CachePatchName("NRNG1", PU_HUDGFX); for (i = 0; i < 12; ++i) { nhud[i] = W_CachePatchName(va("NHUD%d", i+1), PU_HUDGFX); @@ -1545,7 +1547,7 @@ static void ST_drawNiGHTSLink(void) static void ST_drawNiGHTSHUD(void) { INT32 origamount; - INT32 total_spherecount; + INT32 total_spherecount, total_ringcount; const boolean oldspecialstage = (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS)); // Drill meter @@ -1625,21 +1627,20 @@ static void ST_drawNiGHTSHUD(void) if (G_IsSpecialStage(gamemap)) { INT32 i; - total_spherecount = 0; + total_spherecount = total_ringcount = 0; for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/ && players[i].spheres) - total_spherecount += players[i].spheres; + { + if (!playeringame[i]) + continue; + total_spherecount += players[i].spheres; + total_ringcount += players[i].rings; + } } else - total_spherecount = stplyr->spheres; - - /*if (oldspecialstage) { - if (total_spherecount < ssspheres) - total_spherecount = ssspheres - total_spherecount; - else - total_spherecount = 0; - }*/ + total_spherecount = stplyr->spheres; + total_ringcount = stplyr->spheres; + } if (stplyr->capsule) { @@ -1727,6 +1728,23 @@ static void ST_drawNiGHTSHUD(void) else ST_DrawTopLeftOverlayPatch(40, 8 + 5, narrow[8]); + if (oldspecialstage) + { + // invert for s3k style junk + total_spherecount = ssspheres - total_spherecount; + total_ringcount = nummaprings - total_ringcount; + if (total_spherecount < 0) + total_spherecount = 0; + if (total_ringcount < 0) + total_ringcount = 0; + + // now rings! you know, for that perfect bonus. + V_DrawScaledPatch(272, 8, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, nbracket); + V_DrawScaledPatch(280, 16+1, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, nring); + V_DrawScaledPatch(280, 8+5, V_FLIP|V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, narrow[8]); + V_DrawTallNum(272, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, total_ringcount); + } + if (total_spherecount >= 100) V_DrawTallNum((total_spherecount >= 1000) ? 76 : 72, 8 + 11, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTOLEFT|V_HUDTRANS, total_spherecount); else From 876f87e793bacaff87c9d260f935f927eabc70fa Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 2 Aug 2019 23:56:25 +0100 Subject: [PATCH 43/47] Have the ring bonus in MP Special Stages be based on the shared sum of all players'. --- src/y_inter.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/y_inter.c b/src/y_inter.c index 42aee79de..975902ab0 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1877,6 +1877,22 @@ static void Y_SetPerfectBonus(player_t *player, y_bonus_t *bstruct) data.coop.gotperfbonus = (bstruct->display ? 1 : 0); } +static void Y_SetSpecialRingBonus(player_t *player, y_bonus_t *bstruct) +{ + INT32 i, sharedringtotal = 0; + + (void)player; + strncpy(bstruct->patch, "YB_RING", sizeof(bstruct->patch)); + bstruct->display = true; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) continue; + sharedringtotal += players[i].rings; + } + bstruct->points = max(0, (sharedringtotal) * 100); +} + // This list can be extended in the future with SOC/Lua, perhaps. typedef void (*bonus_f)(player_t *, y_bonus_t *); bonus_f bonuses_list[6][4] = { @@ -2001,7 +2017,7 @@ static void Y_AwardSpecialStageBonus(void) } else { - Y_SetRingBonus(&players[i], &localbonuses[0]); + Y_SetSpecialRingBonus(&players[i], &localbonuses[0]); Y_SetPerfectBonus(&players[i], &localbonuses[1]); } players[i].score += localbonuses[0].points; From 105df2395d4078bf7c6f318fbf1245cce50ff839 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Aug 2019 12:09:18 +0100 Subject: [PATCH 44/47] MI made a good argument for bossdisabled not being conditional on fromnetsave. --- src/p_spec.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index f1fb5c82f..ce769ac52 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6422,10 +6422,10 @@ void P_SpawnSpecials(INT32 fromnetsave) // This used to be used, and *should* be used in the future, // but currently isn't. - //(void)fromnetsave; -- hooray, it's used! + (void)fromnetsave; - if (!fromnetsave) - bossdisabled = 0; + // yep, we do this here - "bossdisabled" is considered an apparatus of specials. + bossdisabled = 0; // Init special SECTORs. sector = sectors; @@ -7325,8 +7325,6 @@ void P_SpawnSpecials(INT32 fromnetsave) lines[i].tag); break; } - if (fromnetsave) - break; if (!(lines[i].flags & ML_NOCLIMB)) { bossdisabled |= (1< Date: Sat, 3 Aug 2019 12:25:46 +0100 Subject: [PATCH 45/47] Add a condition to bail on the HUD's ring counting down calculation if nummaprings is 0 or -1. --- src/st_stuff.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 241e35143..962bdd722 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1732,11 +1732,15 @@ static void ST_drawNiGHTSHUD(void) { // invert for s3k style junk total_spherecount = ssspheres - total_spherecount; - total_ringcount = nummaprings - total_ringcount; if (total_spherecount < 0) total_spherecount = 0; - if (total_ringcount < 0) - total_ringcount = 0; + + if (nummaprings > 0) // don't count down if there ISN'T a valid maximum number of rings, like sonic 3 + { + total_ringcount = nummaprings - total_ringcount; + if (total_ringcount < 0) + total_ringcount = 0; + } // now rings! you know, for that perfect bonus. V_DrawScaledPatch(272, 8, V_PERPLAYER|V_SNAPTOTOP|V_SNAPTORIGHT|V_HUDTRANS, nbracket); From f3baac85770e26b3b5efd3b3294422c9a250d3cc Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 3 Aug 2019 08:04:02 -0400 Subject: [PATCH 46/47] Fix the minor issues since steel's busy --- src/p_spec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index f712f4b23..f6c0be083 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3916,13 +3916,15 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); } } + break; + case 460: // Award rings { INT16 rings = (sides[line->sidenum[0]].textureoffset>>FRACBITS); - tic_t delay = (sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT32 delay = (sides[line->sidenum[0]].rowoffset>>FRACBITS); if (mo && mo->player) { - if (delay <= 0 || !(leveltime % (delay))) + if (delay <= 0 || !(leveltime % delay)) P_GivePlayerRings(mo->player, rings); } } From f9037509a13758a20410f3463a898e43685b6df9 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Sat, 3 Aug 2019 19:06:45 +0100 Subject: [PATCH 47/47] Remove commented out P_CheckSector calls and add extra comments explaining the situation --- src/p_polyobj.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 857e6f3d1..040bdca2a 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1873,7 +1873,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight = target->z - amtz; po->lines[0]->backsector->ceilingheight = target->z + amtz; // Sal: Remember to check your sectors! - //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); + // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap + // updating objects in the front one too just added teleporting to ground bugs P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); // Apply action to mirroring polyobjects as well start = 0; @@ -1887,7 +1888,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight += diffz; // move up/down by same amount as the parent did po->lines[0]->backsector->ceilingheight += diffz; // Sal: Remember to check your sectors! - //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); + // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap + // updating objects in the front one too just added teleporting to ground bugs P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); } @@ -2050,8 +2052,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight += momz; po->lines[0]->backsector->ceilingheight += momz; // Sal: Remember to check your sectors! - //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); // frontsector is NEEDED for crushing - P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); // backsector may not be necessary, but just in case + // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap + // updating objects in the front one too just added teleporting to ground bugs + P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); // Apply action to mirroring polyobjects as well start = 0; @@ -2065,7 +2068,8 @@ void T_PolyObjWaypoint(polywaypoint_t *th) po->lines[0]->backsector->floorheight += momz; po->lines[0]->backsector->ceilingheight += momz; // Sal: Remember to check your sectors! - //P_CheckSector(po->lines[0]->frontsector, (boolean)(po->damage)); + // Monster Iestyn: we only need to bother with the back sector, now that P_CheckSector automatically checks the blockmap + // updating objects in the front one too just added teleporting to ground bugs P_CheckSector(po->lines[0]->backsector, (boolean)(po->damage)); } }