Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
Show changes
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2009 by Stephen McGranahan.
// Copyright (C) 2015-2023 by Sonic Team Junior.
// Copyright (C) 2015-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -28,6 +28,8 @@
pslope_t *slopelist = NULL;
UINT16 slopecount = 0;
static void P_UpdateMidtextureSlopesForSector(sector_t *sector);
// Calculate line normal
void P_CalculateSlopeNormal(pslope_t *slope)
{
......@@ -180,7 +182,7 @@ void T_DynamicSlopeLine (dynlineplanethink_t* th)
pslope_t* slope = th->slope;
line_t* srcline = th->sourceline;
fixed_t zdelta;
fixed_t zdelta, oldoz = slope->o.z;
switch(th->type) {
case DP_FRONTFLOOR:
......@@ -207,11 +209,14 @@ void T_DynamicSlopeLine (dynlineplanethink_t* th)
return;
}
if (slope->zdelta != FixedDiv(zdelta, th->extent)) {
if (slope->zdelta != FixedDiv(zdelta, th->extent) || oldoz != slope->o.z) {
slope->zdelta = FixedDiv(zdelta, th->extent);
slope->zangle = R_PointToAngle2(0, 0, th->extent, -zdelta);
slope->moved = true;
P_CalculateSlopeNormal(slope);
P_UpdateMidtextureSlopesForSector(srcline->frontsector);
if (srcline->backsector)
P_UpdateMidtextureSlopesForSector(srcline->backsector);
}
}
......@@ -232,6 +237,12 @@ void T_DynamicSlopeVert (dynvertexplanethink_t* th)
}
ReconfigureViaVertexes(th->slope, th->vex[0], th->vex[1], th->vex[2]);
for (i = 0; i < 3; i++)
{
if (th->secs[i])
P_UpdateMidtextureSlopesForSector(th->secs[i]);
}
}
static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent)
......@@ -758,6 +769,111 @@ pslope_t *P_MakeSlopeViaEquationConstants(const double a, const double b, const
return ret;
}
static pslope_t *P_GetReferenceSlopeForMidtexture(line_t *line)
{
if (line->flags & ML_MIDPEG)
{
// Line has ML_MIDPEG, so use the floor slope
fixed_t frontheight = P_GetSectorFloorZAt(line->frontsector, line->v1->x, line->v1->y);
fixed_t backheight = P_GetSectorFloorZAt(line->backsector, line->v1->x, line->v1->y);
if (frontheight > backheight)
{
return line->frontsector->f_slope;
}
else
{
return line->backsector->f_slope;
}
}
else
{
// Line does not have ML_MIDPEG, so use the ceiling slope
fixed_t frontheight = P_GetSectorCeilingZAt(line->frontsector, line->v1->x, line->v1->y);
fixed_t backheight = P_GetSectorCeilingZAt(line->backsector, line->v1->x, line->v1->y);
if (frontheight < backheight)
{
return line->frontsector->c_slope;
}
else
{
return line->backsector->c_slope;
}
}
return NULL;
}
// Updates a slope for a solid midtexture based on the slope of the sector it's in.
static void P_UpdateSolidMidtextureSlope(line_t *line, pslope_t *ref)
{
pslope_t *slope = line->midtexslope;
if (ref == NULL)
return;
// Set origin
vector3_t origin;
origin.x = line->v1->x;
origin.y = line->v1->y;
origin.z = P_GetSlopeZAt(ref, origin.x, origin.y);
FV3_Copy(&slope->o, &origin);
// Get where the line ends
vector3_t point;
point.x = line->v2->x;
point.y = line->v2->y;
point.z = P_GetSlopeZAt(ref, point.x, point.y);
// Get length of the line
fixed_t extent = R_PointToDist2(0, 0, line->dx, line->dy);
// Precalculate variables
slope->zdelta = FixedDiv(origin.z - point.z, extent);
slope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
slope->xydirection = line->angle;
// Precalculate the direction
vector2_t dir;
dir.x = FixedMul(FINECOSINE(slope->zangle >> ANGLETOFINESHIFT), FINECOSINE((slope->xydirection+ANGLE_180) >> ANGLETOFINESHIFT));
dir.y = FixedMul(FINECOSINE(slope->zangle >> ANGLETOFINESHIFT), FINESINE((slope->xydirection+ANGLE_180) >> ANGLETOFINESHIFT));
FV2_Copy(&slope->d, &dir);
P_CalculateSlopeNormal(slope);
// Calling P_CalculateSlopeVectors is not necessary.
slope->moved = true;
}
// Goes through every line in the sector and updates the midtexture slope if it is present
static void P_UpdateMidtextureSlopesForSector(sector_t *sector)
{
for (size_t i = 0; i < sector->linecount; i++)
{
if (sector->lines[i]->midtexslope != NULL)
P_UpdateSolidMidtextureSlope(sector->lines[i], P_GetReferenceSlopeForMidtexture(sector->lines[i]));
}
}
// Creates a solid midtexture slope for the line if possible
static void P_CreateSolidMidtextureSlope(line_t *line)
{
if (line->backsector == NULL) // Ignore single-sided lines (of course)
return;
if ((line->flags & ML_MIDSOLID) == 0) // Ignore if the midtexture is not solid
return;
pslope_t *ref = P_GetReferenceSlopeForMidtexture(line);
if (ref)
{
line->midtexslope = Slope_Add(ref->flags & SL_NOPHYSICS);
P_UpdateSolidMidtextureSlope(line, ref);
}
}
/// Initializes and reads the slopes from the map data.
void P_SpawnSlopes(const boolean fromsave) {
size_t i;
......@@ -785,14 +901,21 @@ void P_SpawnSlopes(const boolean fromsave) {
/// Copies slopes from tagged sectors via line specials.
/// \note Doesn't actually copy, but instead they share the same pointers.
// Also, creates midtexture slopes.
for (i = 0; i < numlines; i++)
switch (lines[i].special)
{
line_t *line = &lines[i];
switch (line->special)
{
case 720:
P_CopySectorSlope(&lines[i]);
P_CopySectorSlope(line);
default:
break;
}
P_CreateSolidMidtextureSlope(line);
}
}
/// Initializes slopes.
......@@ -810,10 +933,10 @@ void P_InitSlopes(void)
// Returns the height of the sloped plane at (x, y) as a fixed_t
fixed_t P_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y)
{
fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) +
FixedMul(y - slope->o.y, slope->d.y);
fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) / 2 +
FixedMul(y - slope->o.y, slope->d.y) / 2;
return slope->o.z + FixedMul(dist, slope->zdelta);
return slope->o.z + FixedMul(dist, slope->zdelta) * 2;
}
// Like P_GetSlopeZAt but falls back to z if slope is NULL
......@@ -923,15 +1046,37 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope)
{
vector3_t slopemom, axis;
angle_t ang;
angle_t advanceAng = ANG15;
const boolean upwards = (slope->zangle < ANGLE_180);
if (slope->flags & SL_NOPHYSICS)
return 0;
// If there's physics, time for launching.
// Doesn't kill the vertical momentum as much as P_SlopeLaunch does.
ang = slope->zangle + ANG15*((slope->zangle > 0) ? 1 : -1);
if (ang > ANGLE_90 && ang < ANGLE_180)
ang = ((slope->zangle > 0) ? ANGLE_90 : InvAngle(ANGLE_90)); // hard cap of directly upwards
ang = slope->zangle;
// for the time being, let's pretend the slope inclines upwards only
if (!upwards)
{
ang += ANGLE_180;
}
// angles past 90 degrees need to shrink to get closer to 90 degrees
if (ang > ANGLE_90)
{
advanceAng = InvAngle(advanceAng);
}
// now we set the actual final angle
if ((ang > ANGLE_90) != (ang + advanceAng > ANGLE_90)) // does advancing the angle push it past directly upwards?
{
ang = (upwards ? ANGLE_90 : InvAngle(ANGLE_90)); // hard cap of directly upwards
}
else
{
ang = slope->zangle + advanceAng;
}
slopemom.x = mo->momx;
slopemom.y = mo->momy;
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2009 by Stephen McGranahan.
// Copyright (C) 2015-2023 by Sonic Team Junior.
// Copyright (C) 2015-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -135,22 +135,24 @@ void P_ParseAnimationDefintion(SINT8 istexture);
static boolean P_FindTextureForAnimation(anim_t *anim, animdef_t *animdef)
{
if (R_CheckTextureNumForName(animdef->startname) == -1)
INT32 start = R_CheckTextureNumForName(animdef->startname, TEXTURETYPE_TEXTURE);
if (start == -1)
return false;
anim->picnum = R_TextureNumForName(animdef->endname);
anim->basepic = R_TextureNumForName(animdef->startname);
anim->basepic = start;
anim->picnum = R_CheckTextureNumForName(animdef->endname, TEXTURETYPE_TEXTURE);
return true;
}
static boolean P_FindFlatForAnimation(anim_t *anim, animdef_t *animdef)
{
if (R_CheckFlatNumForName(animdef->startname) == -1)
INT32 start = R_CheckTextureNumForName(animdef->startname, TEXTURETYPE_FLAT);
if (start == -1)
return false;
anim->picnum = R_CheckFlatNumForName(animdef->endname);
anim->basepic = R_CheckFlatNumForName(animdef->startname);
anim->basepic = start;
anim->picnum = R_CheckTextureNumForName(animdef->endname, TEXTURETYPE_FLAT);
return true;
}
......@@ -2405,11 +2407,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
y = line->args[3] << FRACBITS;
z = line->args[4] << FRACBITS;
P_UnsetThingPosition(mo);
mo->x += x;
mo->y += y;
mo->z += z;
P_SetThingPosition(mo);
P_SetOrigin(mo, mo->x + x, mo->y + y, mo->z + z);
if (mo->player)
{
......@@ -2417,6 +2415,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
P_SetOrigin(bot, bot->x + x, bot->y + y, bot->z + z);
if (splitscreen && mo->player == &players[secondarydisplayplayer] && camera2.chase)
{
camera2.reset = true;
camera2.x += x;
camera2.y += y;
camera2.z += z;
......@@ -2424,6 +2423,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
}
else if (camera.chase && mo->player == &players[displayplayer])
{
camera.reset = true;
camera.x += x;
camera.y += y;
camera.z += z;
......@@ -2548,7 +2548,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
char *text = Z_Malloc(len + 1, PU_CACHE, NULL);
memcpy(text, lump, len);
text[len] = '\0';
COM_BufInsertText(text);
COM_BufInsertTextEx(text, COM_LUA);
Z_Free(text);
}
}
......@@ -3644,7 +3644,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
if (mo2->type != MT_EGGTRAP)
continue;
if (mo2->thinker.function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (mo2->thinker.removing)
continue;
P_KillMobj(mo2, NULL, mo, 0);
......@@ -3684,7 +3684,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 466: // Set level failure state
{
if (line->args[1])
if (line->args[0])
{
stagefailed = false;
CONS_Debug(DBG_GAMELOGIC, "Stage can be completed successfully!\n");
......@@ -3856,7 +3856,7 @@ void P_SetupSignExit(player_t *player)
// spin all signposts in the level then.
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (think->removing)
continue;
thing = (mobj_t *)think;
......@@ -3894,7 +3894,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (think->removing)
continue;
mo = (mobj_t *)think;
......@@ -4397,7 +4397,7 @@ static void P_ProcessEggCapsule(player_t *player, sector_t *sector)
// The chimps are my friends.. heeheeheheehehee..... - LouisJM
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
if (mo2->type != MT_EGGTRAP)
......@@ -4677,7 +4677,7 @@ static void P_ProcessZoomTube(player_t *player, mtag_t sectag, boolean end)
player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY);
player->climbing = 0;
if (player->mo->state-states != S_PLAY_ROLL)
if (!P_IsPlayerInState(player, S_PLAY_ROLL))
{
P_SetMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_spin);
......@@ -4758,7 +4758,7 @@ static void P_ProcessRopeHang(player_t *player, mtag_t sectag)
if (player->cmd.buttons & BT_SPIN)
return;
if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate])
if (!(player->pflags & PF_SLIDING) && P_IsPlayerInState(player, S_PLAY_PAIN))
return;
if (player->exiting)
......@@ -6238,7 +6238,7 @@ static void P_DoPortalCopyFromLine(sector_t *dest_sector, int plane_type, int ta
}
}
static sectorportal_t *P_SectorGetPortalOrCreate(sector_t *sector, UINT32 *num, UINT32 *result)
static sectorportal_t *P_SectorGetPortalOrCreate(sector_t *sector, UINT32 *num, UINT32 *result, boolean ceiling)
{
sectorportal_t *secportal = NULL;
......@@ -6246,8 +6246,8 @@ static sectorportal_t *P_SectorGetPortalOrCreate(sector_t *sector, UINT32 *num,
{
*num = P_NewSectorPortal();
secportal = &secportals[*num];
secportal->origin.x = sector->soundorg.x;
secportal->origin.y = sector->soundorg.y;
secportal->target = sector;
secportal->ceiling = ceiling;
*result = *num;
}
else
......@@ -6261,12 +6261,12 @@ static sectorportal_t *P_SectorGetPortalOrCreate(sector_t *sector, UINT32 *num,
static sectorportal_t *P_SectorGetFloorPortalOrCreate(sector_t *sector, UINT32 *result)
{
return P_SectorGetPortalOrCreate(sector, &sector->portal_floor, result);
return P_SectorGetPortalOrCreate(sector, &sector->portal_floor, result, false);
}
static sectorportal_t *P_SectorGetCeilingPortalOrCreate(sector_t *sector, UINT32 *result)
{
return P_SectorGetPortalOrCreate(sector, &sector->portal_ceiling, result);
return P_SectorGetPortalOrCreate(sector, &sector->portal_ceiling, result, true);
}
static void P_CopySectorPortalToLines(UINT32 portal_num, int sector_tag)
......@@ -8805,7 +8805,7 @@ void T_Pusher(pusher_t *p)
if (thing->player && thing->player->powers[pw_carry] == CR_ROPEHANG)
continue;
if (thing->player && (thing->state == &states[thing->info->painstate]) && (thing->player->powers[pw_flashing] > (flashingtics/4)*3 && thing->player->powers[pw_flashing] <= flashingtics))
if (thing->player && P_IsPlayerInState(thing->player, S_PLAY_PAIN) && (thing->player->powers[pw_flashing] > (flashingtics/4)*3 && thing->player->powers[pw_flashing] <= flashingtics))
continue;
inFOF = touching = moved = false;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -162,7 +162,7 @@ void Command_CountMobjs_f(void)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
if (((mobj_t *)th)->type == i)
......@@ -182,7 +182,7 @@ void Command_CountMobjs_f(void)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
if (((mobj_t *)th)->type == i)
......@@ -348,6 +348,7 @@ void P_RemoveThinkerDelayed(thinker_t *thinker)
void P_RemoveThinker(thinker_t *thinker)
{
LUA_InvalidateUserdata(thinker);
thinker->removing = true;
thinker->function.acp1 = (actionf_p1)P_RemoveThinkerDelayed;
}
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2025 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -47,6 +47,7 @@
#include "m_cheat.h"
// Thok camera snap (ctrl-f "chalupa")
#include "g_input.h"
#include "simple_hashmap.h"
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
......@@ -435,7 +436,7 @@ UINT8 P_FindLowestMare(void)
// to find the egg capsule with the lowest mare
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -488,7 +489,7 @@ boolean P_TransferToNextMare(player_t *player)
// to find the closest axis point
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -539,7 +540,7 @@ static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
// to find the closest axis point
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -574,7 +575,7 @@ static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
// to find the closest axis point
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -615,7 +616,7 @@ void P_TransferToAxis(player_t *player, INT32 axisnum)
// to find the closest axis point
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -669,7 +670,7 @@ static void P_DeNightserizePlayer(player_t *player)
player->powers[pw_carry] = CR_NIGHTSFALL;
player->powers[pw_underwater] = 0;
player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_SHIELDDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST);
player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST);
player->secondjump = 0;
player->homing = 0;
player->climbing = 0;
......@@ -716,7 +717,7 @@ static void P_DeNightserizePlayer(player_t *player)
// Check to see if the player should be killed.
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -802,7 +803,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
if (mapheaderinfo[gamemap-1]->nightstimer[newmare] > 0)
nighttime = mapheaderinfo[gamemap-1]->nightstimer[newmare];
player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_SHIELDDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
player->homing = 0;
player->mo->fuse = 0;
player->speed = 0;
......@@ -915,7 +916,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->textvar = NTV_BONUSTIMEEND; // Score and grades
player->finishedspheres = (INT16)(player->spheres);
player->finishedrings = (INT16)(player->rings);
// Add score to temp leaderboards
player->lastmaretime = leveltime - player->marebegunat;
G_AddTempNightsRecords(player, player->marescore, player->lastmaretime, (UINT8)(oldmare + 1));
......@@ -968,6 +969,33 @@ pflags_t P_GetJumpFlags(player_t *player)
return PF_JUMPED;
}
// If the state is a custom state for the player's skin, retrieve its "canonical" state
// e.g. S_SKIN_BIGTHECAT_WALK => S_PLAY_WALK
statenum_t P_GetCanonicalPlayerState(player_t *player, statenum_t state)
{
skin_t *skin = skins[player->skin];
statenum_t mappedstate;
SIMPLEHASH_FIND_INT(skin->customtodefaultstate, hashentry_int32_int32_t, state, state, mappedstate)
return mappedstate;
}
boolean P_IsPlayerInState(player_t *player, statenum_t state)
{
return (P_GetCanonicalPlayerState(player, player->mo->state - states) == state);
}
boolean P_IsPlayerInSuperTransformationState(player_t *player)
{
statenum_t state = player->mo->state - states;
return (state >= S_PLAY_SUPER_TRANS1 && state <= S_PLAY_SUPER_TRANS6);
}
boolean P_IsPlayerInNightsTransformationState(player_t *player)
{
statenum_t state = player->mo->state - states;
return (state >= S_PLAY_NIGHTS_TRANS1 && state <= S_PLAY_NIGHTS_TRANS6);
}
//
// P_PlayerInPain
//
......@@ -976,11 +1004,14 @@ pflags_t P_GetJumpFlags(player_t *player)
//
boolean P_PlayerInPain(player_t *player)
{
if (P_MobjWasRemoved(player->mo))
return false;
// no silly, sliding isn't pain
if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing])
return true;
if (player->mo->state == &states[S_PLAY_STUN])
if (P_IsPlayerInState(player, S_PLAY_STUN))
return true;
return false;
......@@ -1004,7 +1035,7 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor)
fixed_t fallbackspeed;
P_ResetPlayer(player);
P_SetMobjState(player->mo, player->mo->info->painstate);
P_SetMobjState(player->mo, S_PLAY_PAIN);
if (player->mo->eflags & MFE_VERTICALFLIP)
player->mo->z--;
......@@ -1089,6 +1120,13 @@ void P_ResetPlayer(player_t *player)
if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer))
{
player->mo->tracer->flags |= MF_PUSHABLE;
// goose the mom a little bit to trigger gravity to process for a tic
if (player->mo->tracer->eflags & MFE_VERTICALFLIP)
player->mo->tracer->momz -= 1;
else
player->mo->tracer->momz += 1;
P_SetTarget(&player->mo->tracer->tracer, NULL);
}
P_SetTarget(&player->mo->tracer, NULL);
......@@ -1352,6 +1390,8 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
P_PlayJingle(player, JT_SUPER);
S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
player->mo->momx = player->mo->momy = player->mo->momz = player->cmomx = player->cmomy = player->rmomx = player->rmomy = 0;
// Transformation animation
......@@ -1368,11 +1408,8 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
player->powers[pw_sneakers] = 0;
}
if (G_CoopGametype())
S_StartSound(player->mo, sfx_supert); //only hear it near yourself in co-op
else
if (!G_CoopGametype())
{
S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
HU_SetCEchoFlags(0);
HU_SetCEchoDuration(5);
HU_DoCEcho(va("%s\\is now super.\\\\\\\\", player_names[player-players]));
......@@ -1407,7 +1444,7 @@ void P_DoSuperDetransformation(player_t *player)
if (!G_CoopGametype())
player->powers[pw_flashing] = flashingtics-1;
if (player->mo->sprite2 & SPR2F_SUPER)
if (player->mo->sprite2 & FF_SPR2SUPER)
P_SetMobjState(player->mo, player->mo->state-states);
// Inform the netgame that the champion has fallen in the heat of battle.
......@@ -1889,7 +1926,7 @@ void P_SpawnShieldOrb(player_t *player)
// blaze through the thinkers to see if an orb already exists!
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
shieldobj = (mobj_t *)th;
......@@ -2071,6 +2108,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->renderflags = mobj->renderflags;
ghost->blendmode = mobj->blendmode;
ghost->alpha = mobj->alpha;
ghost->spritexscale = mobj->spritexscale;
ghost->spriteyscale = mobj->spriteyscale;
......@@ -2372,7 +2410,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
if (dorollstuff)
{
if ((player->charability2 == CA2_SPINDASH) && !((player->pflags & (PF_SPINNING|PF_THOKKED)) == PF_THOKKED) && !(player->charability == CA_THOK && player->secondjump)
&& (player->cmd.buttons & BT_SPIN) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
&& (player->cmd.buttons & BT_SPIN) && (FixedHypot(player->mo->momx, player->mo->momy) >= (5*player->mo->scale)))
player->pflags = (player->pflags|PF_SPINNING) & ~PF_THOKKED;
else if (!(player->pflags & PF_STARTDASH))
player->pflags &= ~PF_SPINNING;
......@@ -2380,7 +2418,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
if (player->pflags & PF_BOUNCING)
{
if (dorollstuff && player->mo->state-states != S_PLAY_BOUNCE_LANDING)
if (dorollstuff && !P_IsPlayerInState(player, S_PLAY_BOUNCE_LANDING))
{
P_MobjCheckWater(player->mo);
player->mo->momz *= -1;
......@@ -2417,9 +2455,9 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
player->pflags &= ~PF_GLIDING;
}
else if (player->charability == CA_GLIDEANDCLIMB && player->pflags & PF_THOKKED && !(player->pflags & (PF_JUMPED|PF_SHIELDABILITY))
&& (player->mo->floorz != player->mo->watertop) && player->mo->state-states == S_PLAY_FALL)
&& (player->mo->floorz != player->mo->watertop) && P_IsPlayerInState(player, S_PLAY_FALL))
{
if (player->mo->state-states != S_PLAY_GLIDE_LANDING)
if (!P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING))
{
P_ResetPlayer(player);
P_SetMobjState(player->mo, S_PLAY_GLIDE_LANDING);
......@@ -2440,7 +2478,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
else if (player->charability2 == CA2_MELEE
&& ((player->panim == PA_ABILITY2) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY && player->cmd.buttons & (BT_JUMP|BT_SPIN))))
{
if (player->mo->state-states != S_PLAY_MELEE_LANDING)
if (!P_IsPlayerInState(player, S_PLAY_MELEE_LANDING))
{
mobjtype_t type = player->revitem;
P_SetMobjState(player->mo, S_PLAY_MELEE_LANDING);
......@@ -2488,7 +2526,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
}
}
}
else if (player->charability == CA_GLIDEANDCLIMB && (player->mo->state-states == S_PLAY_GLIDE_LANDING))
else if (player->charability == CA_GLIDEANDCLIMB && (P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING)))
;
else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
;
......@@ -2511,10 +2549,10 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH)
P_SetMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= runspd
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
&& (player->panim != PA_RUN || P_IsPlayerInState(player, S_PLAY_FLOAT_RUN)))
P_SetMobjState(player->mo, S_PLAY_RUN);
else if ((player->rmomx || player->rmomy)
&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
&& (player->panim != PA_WALK || P_IsPlayerInState(player, S_PLAY_FLOAT)))
P_SetMobjState(player->mo, S_PLAY_WALK);
else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE)
P_SetMobjState(player->mo, S_PLAY_STND);
......@@ -2524,10 +2562,10 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH)
P_SetMobjState(player->mo, S_PLAY_DASH);
else if (player->speed >= runspd
&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
&& (player->panim != PA_RUN || P_IsPlayerInState(player, S_PLAY_FLOAT_RUN)))
P_SetMobjState(player->mo, S_PLAY_RUN);
else if ((player->mo->momx || player->mo->momy)
&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
&& (player->panim != PA_WALK || P_IsPlayerInState(player, S_PLAY_FLOAT)))
P_SetMobjState(player->mo, S_PLAY_WALK);
else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE)
P_SetMobjState(player->mo, S_PLAY_STND);
......@@ -3300,6 +3338,7 @@ static void P_DoPlayerHeadSigns(player_t *player)
sign->frame = 2|FF_FULLBRIGHT;
}
}
}
if (!P_MobjWasRemoved(sign) && splitscreen) // Hide the sign from yourself in splitscreen - In single-screen, it wouldn't get spawned if it shouldn't be visible
{
......@@ -3337,7 +3376,6 @@ static void P_DoPlayerHeadSigns(player_t *player)
}
#endif
}
}
}
//
......@@ -3701,9 +3739,9 @@ static void P_DoClimbing(player_t *player)
climb = false;
if (player->climbing && climb && (player->mo->momx || player->mo->momy || player->mo->momz)
&& player->mo->state-states != S_PLAY_CLIMB)
&& !P_IsPlayerInState(player, S_PLAY_CLIMB))
P_SetMobjState(player->mo, S_PLAY_CLIMB);
else if ((!(player->mo->momx || player->mo->momy || player->mo->momz) || !climb) && player->mo->state-states != S_PLAY_CLING)
else if ((!(player->mo->momx || player->mo->momy || player->mo->momz) || !climb) && !P_IsPlayerInState(player, S_PLAY_CLING))
P_SetMobjState(player->mo, S_PLAY_CLING);
if (!floorclimb)
......@@ -3736,9 +3774,9 @@ static void P_DoClimbing(player_t *player)
climb = false;
if (player->climbing && climb && (player->mo->momx || player->mo->momy || player->mo->momz)
&& player->mo->state-states != S_PLAY_CLIMB)
&& !P_IsPlayerInState(player, S_PLAY_CLIMB))
P_SetMobjState(player->mo, S_PLAY_CLIMB);
else if ((!(player->mo->momx || player->mo->momy || player->mo->momz) || !climb) && player->mo->state-states != S_PLAY_CLING)
else if ((!(player->mo->momx || player->mo->momy || player->mo->momz) || !climb) && !P_IsPlayerInState(player, S_PLAY_CLING))
P_SetMobjState(player->mo, S_PLAY_CLING);
if (cmd->buttons & BT_SPIN && !(player->pflags & PF_JUMPSTASIS))
......@@ -4115,7 +4153,7 @@ static void P_DoTeeter(player_t *player)
teeteryl = teeteryh = player->mo->y;
couldteeter = false;
solidteeter = teeter;
if (!P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_CheckSolidsTeeter))
if (!P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_CheckSolidsTeeter, tmthing))
goto teeterdone; // we've found something that stops us teetering at all
teeterdone:
teeter = solidteeter;
......@@ -4200,7 +4238,6 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
if (player->pflags & PF_ATTACKDOWN || player->climbing || (G_TagGametype() && !(player->pflags & PF_TAGIT)))
return;
// Fire a fireball if we have the Fire Flower powerup!
if (((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER) && !(player->weapondelay))
{
player->pflags |= PF_ATTACKDOWN;
......@@ -4212,7 +4249,6 @@ static void P_DoFiring(player_t *player, ticcmd_t *cmd)
return;
}
// No ringslinging outside of ringslinger!
if (!G_RingSlingerGametype() || player->weapondelay)
return;
......@@ -4391,7 +4427,34 @@ static void P_DoSuperStuff(player_t *player)
// If you're super and not Sonic, de-superize!
if (!(ALL7EMERALDS(emeralds) && player->charflags & SF_SUPER))
{
P_DoSuperDetransformation(player);
player->powers[pw_super] = 0;
P_SetMobjState(player->mo, S_PLAY_STND);
if (P_IsLocalPlayer(player))
{
music_stack_noposition = true; // HACK: Do not reposition next music
music_stack_fadeout = MUSICRATE/2; // HACK: Fade out current music
}
P_RestoreMusic(player);
P_SpawnShieldOrb(player);
// Restore color
if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER)
{
player->mo->color = SKINCOLOR_WHITE;
G_GhostAddColor(GHC_FIREFLOWER);
}
else
{
player->mo->color = P_GetPlayerColor(player);
G_GhostAddColor(GHC_NORMAL);
}
if (!G_CoopGametype())
{
HU_SetCEchoFlags(0);
HU_SetCEchoDuration(5);
HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[player-players]));
}
return;
}
......@@ -4401,7 +4464,7 @@ static void P_DoSuperStuff(player_t *player)
G_GhostAddColor(GHC_SUPER);
if (player->mo->state == &states[S_PLAY_SUPER_TRANS6]) // stop here for now
if (P_IsPlayerInState(player, S_PLAY_SUPER_TRANS6)) // stop here for now
return;
// Deplete one ring every second while super
......@@ -4418,37 +4481,28 @@ static void P_DoSuperStuff(player_t *player)
// Ran out of rings while super!
if (player->rings <= 0 || player->exiting)
{
P_DoSuperDetransformation(player);
}
}
}
//
// P_SuperReady
//
// Returns true if player is ready to transform or detransform
// Returns true if player is ready to turn super, duh
//
boolean P_SuperReady(player_t *player, boolean transform)
boolean P_SuperReady(player_t *player)
{
if (!transform &&
(player->powers[pw_super] < TICRATE*3/2
|| !G_CoopGametype())) // No turning back in competitive!
return false;
else if (transform
&& (player->powers[pw_super]
|| !ALL7EMERALDS(emeralds)
|| !(player->rings >= 50)))
return false;
if (player->mo
if (!player->powers[pw_super]
&& !player->powers[pw_invulnerability]
&& !player->powers[pw_tailsfly]
&& !player->powers[pw_carry]
&& (player->charflags & SF_SUPER)
&& !P_PlayerInPain(player)
&& !player->climbing
&& !(player->pflags & (PF_JUMPSTASIS|PF_THOKKED|PF_STARTDASH|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY))
&& ((player->pflags & PF_JUMPED) || (P_IsObjectOnGround(player->mo) && (player->panim == PA_IDLE || player->panim == PA_EDGE
|| player->panim == PA_WALK || player->panim == PA_RUN || (player->charflags & SF_DASHMODE && player->panim == PA_DASH))))
&& !(maptol & TOL_NIGHTS))
&& (player->pflags & PF_JUMPED)
&& !(player->powers[pw_shield] & SH_NOSTACK)
&& !(maptol & TOL_NIGHTS)
&& ALL7EMERALDS(emeralds)
&& (player->rings >= 50))
return true;
return false;
......@@ -4546,6 +4600,13 @@ void P_DoJump(player_t *player, boolean soundandstate, boolean allowflip)
player->mo->momz += player->mo->tracer->momz;
if (!P_IsObjectOnGround(player->mo->tracer))
P_SetObjectMomZ(player->mo->tracer, -9*FRACUNIT, true);
// goose the mom a little bit to trigger gravity to process for a tic
if (player->mo->tracer->eflags & MFE_VERTICALFLIP)
player->mo->tracer->momz -= 1;
else
player->mo->tracer->momz += 1;
player->mo->tracer->flags |= MF_PUSHABLE;
P_SetTarget(&player->mo->tracer->tracer, NULL);
}
......@@ -4686,7 +4747,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
{
boolean canstand = true; // can we stand on the ground? (mostly relevant for slopes)
if (player->pflags & PF_STASIS
&& (player->pflags & PF_JUMPSTASIS || player->mo->state-states != S_PLAY_GLIDE_LANDING))
&& (player->pflags & PF_JUMPSTASIS || !P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING)))
return;
if (cmd->buttons & BT_SPIN)
......@@ -4706,7 +4767,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
{
case CA2_SPINDASH: // Spinning and Spindashing
// Start revving
if ((cmd->buttons & BT_SPIN) && (player->speed < FixedMul(5<<FRACBITS, player->mo->scale) || player->mo->state - states == S_PLAY_GLIDE_LANDING)
if ((cmd->buttons & BT_SPIN) && (player->speed < FixedMul(5<<FRACBITS, player->mo->scale) || P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING))
&& !player->mo->momz && onground && !(player->pflags & (PF_SPINDOWN|PF_SPINNING))
&& canstand)
{
......@@ -4721,7 +4782,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
// Revving
else if ((cmd->buttons & BT_SPIN) && (player->pflags & PF_STARTDASH))
{
if (player->speed > 5*player->mo->scale)
if (player->speed >= 5*player->mo->scale)
{
player->pflags &= ~PF_STARTDASH;
P_SetMobjState(player->mo, S_PLAY_ROLL);
......@@ -4761,9 +4822,8 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
if (!player->spectator)
S_StartSound(player->mo, sfx_spin);
}
else
// Catapult the player from a spindash rev!
if (onground && !(player->pflags & PF_SPINDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
else if (onground && !(player->pflags & PF_SPINDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
{
player->pflags &= ~PF_STARTDASH;
if (player->powers[pw_carry] == CR_BRAKGOOP)
......@@ -4996,7 +5056,7 @@ void P_DoBubbleBounce(player_t *player)
//
void P_DoAbilityBounce(player_t *player, boolean changemomz)
{
if (player->mo->state-states == S_PLAY_BOUNCE_LANDING)
if (P_IsPlayerInState(player, S_PLAY_BOUNCE_LANDING))
return;
if (changemomz)
......@@ -5095,7 +5155,7 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -5147,7 +5207,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
{
mobj_t *lockonshield = NULL;
if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SHIELDDOWN)
if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN)
&& ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted
{
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT && !(player->charflags & SF_NOSHIELDABILITY))
......@@ -5170,14 +5230,14 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
if (!P_MobjWasRemoved(visual))
{
P_SetTarget(&visual->target, lockonshield);
visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
visual->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
P_SetMobjStateNF(visual, visual->info->spawnstate+1);
}
}
}
}
}
if ((!(player->charflags & SF_NOSHIELDABILITY)) && (cmd->buttons & BT_SHIELD && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) // Shield button effects
if ((!(player->charflags & SF_NOSHIELDABILITY)) && (cmd->buttons & BT_SPIN && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) // Spin button effects
{
// Force stop
if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
......@@ -5266,7 +5326,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock
//
// Handles player jumping
//
static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd, boolean spinshieldhack)
static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
{
mobj_t *lockonthok = NULL, *visual = NULL;
......@@ -5299,13 +5359,12 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd, boolean spinshieldhac
;
else if (P_PlayerShieldThink(player, cmd, lockonthok, visual))
;
else if (cmd->buttons & BT_SPIN)
else if ((cmd->buttons & BT_SPIN))
{
if (spinshieldhack && !(player->pflags & PF_SPINDOWN) && P_SuperReady(player, true)
&& !player->powers[pw_invulnerability] && !(player->powers[pw_shield] & SH_NOSTACK)) // These two checks are no longer in P_SuperReady
if (!(player->pflags & PF_SPINDOWN) && P_SuperReady(player))
{
// If you're using two-button play, can turn Super and aren't already,
// and you don't have a shield, then turn Super!
// If you can turn super and aren't already,
// and you don't have a shield, do it!
P_DoSuperTransformation(player, false);
}
else if (!LUA_HookPlayer(player, HOOK(JumpSpinSpecial)))
......@@ -5408,6 +5467,12 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd, boolean spinshieldhac
}
else if (player->pflags & PF_SLIDING || ((gametyperules & GTR_TEAMFLAGS) && player->gotflag) || player->pflags & PF_SHIELDABILITY)
;
/*else if (P_SuperReady(player))
{
// If you can turn super and aren't already,
// and you don't have a shield, do it!
P_DoSuperTransformation(player, false);
}*/
else if (player->pflags & PF_JUMPED)
{
if (!LUA_HookPlayer(player, HOOK(AbilitySpecial)))
......@@ -6072,7 +6137,7 @@ static void P_3dMovement(player_t *player)
// When sliding, don't allow forward/back
if (player->pflags & PF_SLIDING)
cmd->forwardmove = 0;
else if (onground && player->mo->state == states+S_PLAY_PAIN)
else if (onground && P_IsPlayerInState(player, S_PLAY_PAIN))
P_SetMobjState(player->mo, S_PLAY_WALK);
player->aiming = cmd->aiming<<FRACBITS;
......@@ -6125,7 +6190,7 @@ static void P_3dMovement(player_t *player)
{
if (player->pflags & PF_BOUNCING)
{
if (player->mo->state-states == S_PLAY_BOUNCE_LANDING)
if (P_IsPlayerInState(player, S_PLAY_BOUNCE_LANDING))
{
thrustfactor = player->thrustfactor*8;
acceleration = player->accelstart/8 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration/8;
......@@ -6462,7 +6527,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
// Find next waypoint
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -6498,7 +6563,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
{
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -6527,7 +6592,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
{
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -6878,10 +6943,10 @@ static void P_DoNiGHTSCapsule(player_t *player)
{
if (player->mo->momx || player->mo->momy || player->mo->momz)
{
if (player->mo->state != &states[S_PLAY_NIGHTS_PULL])
if (!P_IsPlayerInState(player, S_PLAY_NIGHTS_PULL))
P_SetMobjState(player->mo, S_PLAY_NIGHTS_PULL);
}
else if (player->mo->state != &states[S_PLAY_NIGHTS_ATTACK])
else if (!P_IsPlayerInState(player, S_PLAY_NIGHTS_ATTACK))
{
S_StartSound(player->mo, sfx_spin);
P_SetMobjState(player->mo, S_PLAY_NIGHTS_ATTACK);
......@@ -6897,7 +6962,7 @@ static void P_DoNiGHTSCapsule(player_t *player)
if (!(player->charflags & SF_NONIGHTSROTATION))
{
if ((player->mo->state == &states[S_PLAY_NIGHTS_PULL])
if ((P_IsPlayerInState(player, S_PLAY_NIGHTS_PULL))
&& (player->mo->sprite2 == SPR2_NPUL))
player->mo->spriteroll -= ANG30;
else
......@@ -7212,15 +7277,11 @@ static void P_NiGHTSMovement(player_t *player)
if (playeringame[i] /*&& players[i].powers[pw_carry] == CR_NIGHTSMODE*/
&& (players[i].capsule && players[i].capsule->reactiontime))
capsule = true;
if (!capsule
&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
&& !player->exiting)
if (!capsule && !P_IsPlayerInNightsTransformationState(player) && !player->exiting)
player->nightstime--;
}
else if (!(gametyperules & GTR_RACE)
&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
&& !P_IsPlayerInNightsTransformationState(player)
&& !(player->capsule && player->capsule->reactiontime)
&& !player->exiting)
player->nightstime--;
......@@ -7259,7 +7320,7 @@ static void P_NiGHTSMovement(player_t *player)
// to find the closest axis point
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -7360,8 +7421,7 @@ static void P_NiGHTSMovement(player_t *player)
return;
}
if (player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
if (P_IsPlayerInNightsTransformationState(player))
{
player->mo->momx = player->mo->momy = player->mo->momz = 0;
player->mo->spriteroll = 0;
......@@ -7380,14 +7440,14 @@ static void P_NiGHTSMovement(player_t *player)
#if 0//def ROTSPRITE
if (!(player->charflags & SF_NONIGHTSROTATION) && player->mo->momz)
{
if (player->mo->state != &states[S_PLAY_NIGHTS_DRILL])
if (!P_IsPlayerInState(player, S_PLAY_NIGHTS_DRILL))
P_SetMobjState(player->mo, S_PLAY_NIGHTS_DRILL);
player->mo->spriteroll = ANGLE_90;
}
else
#endif
{
if (player->mo->state != &states[S_PLAY_NIGHTS_FLOAT])
if (!P_IsPlayerInState(player, S_PLAY_NIGHTS_FLOAT))
P_SetMobjState(player->mo, S_PLAY_NIGHTS_FLOAT);
player->drawangle += ANGLE_22h;
}
......@@ -8019,7 +8079,7 @@ static void P_SkidStuff(player_t *player)
// Spawn a particle every 3 tics.
if (!(player->skidtime % 3))
{
if (player->mo->state-states == S_PLAY_GLIDE_LANDING)
if (P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING))
P_SpawnSkidDust(player, player->mo->radius, true);
else
P_SpawnSkidDust(player, 0, false);
......@@ -8039,7 +8099,7 @@ static void P_SkidStuff(player_t *player)
// If your push angle is more than this close to a full 180 degrees, trigger a skid.
if (dang > ANGLE_157h)
{
if (player->mo->state-states != S_PLAY_SKID)
if (!P_IsPlayerInState(player, S_PLAY_SKID))
P_SetMobjState(player->mo, S_PLAY_SKID);
player->mo->tics = player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
S_StartSound(player->mo, sfx_skid);
......@@ -8060,11 +8120,10 @@ void P_MovePlayer(player_t *player)
{
ticcmd_t *cmd;
INT32 i;
boolean spinshieldhack = false; // Hack: Is Spin and Shield bound to the same button (pressed on the same tic)?
fixed_t runspd;
if (player->mo->state >= &states[S_PLAY_SUPER_TRANS1] && player->mo->state <= &states[S_PLAY_SUPER_TRANS6])
if (P_IsPlayerInSuperTransformationState(player))
{
player->mo->momx = player->mo->momy = player->mo->momz = 0;
return;
......@@ -8085,7 +8144,7 @@ void P_MovePlayer(player_t *player)
if ((player->powers[pw_carry] == CR_BRAKGOOP)
|| (player->pflags & PF_GLIDING && player->skidtime)
|| (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
|| (player->charability2 == CA2_MELEE && player->mo->state-states == S_PLAY_MELEE_LANDING))
|| (player->charability2 == CA2_MELEE && P_IsPlayerInState(player, S_PLAY_MELEE_LANDING)))
player->pflags |= PF_FULLSTASIS;
else if (player->powers[pw_nocontrol])
{
......@@ -8094,7 +8153,7 @@ void P_MovePlayer(player_t *player)
player->pflags |= PF_JUMPSTASIS;
}
if (player->charability == CA_GLIDEANDCLIMB && player->mo->state-states == S_PLAY_GLIDE_LANDING)
if (player->charability == CA_GLIDEANDCLIMB && P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING))
{
player->pflags |= PF_STASIS;
}
......@@ -8159,7 +8218,7 @@ void P_MovePlayer(player_t *player)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -8273,7 +8332,7 @@ void P_MovePlayer(player_t *player)
{
// If the player is in dashmode, here's their peelout.
if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim == PA_RUN && !player->skidtime && (onground || ((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super]))
P_SetMobjState (player->mo, S_PLAY_DASH);
P_SetMobjState(player->mo, S_PLAY_DASH);
// If the player is moving fast enough,
// break into a run!
else if (player->speed >= runspd && player->panim == PA_WALK && !player->skidtime
......@@ -8287,11 +8346,11 @@ void P_MovePlayer(player_t *player)
// Floating at slow speeds has its own special animation.
else if ((((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super]) && player->panim == PA_IDLE && !onground)
P_SetMobjState (player->mo, S_PLAY_FLOAT);
P_SetMobjState(player->mo, S_PLAY_FLOAT);
// Otherwise, just walk.
else if ((player->rmomx || player->rmomy) && player->panim == PA_IDLE)
P_SetMobjState (player->mo, S_PLAY_WALK);
P_SetMobjState(player->mo, S_PLAY_WALK);
}
// If your peelout animation is playing, and you're
......@@ -8312,9 +8371,9 @@ void P_MovePlayer(player_t *player)
// Correct floating when ending up on the ground.
if (onground)
{
if (player->mo->state-states == S_PLAY_FLOAT)
if (P_IsPlayerInState(player, S_PLAY_FLOAT))
P_SetMobjState(player->mo, S_PLAY_WALK);
else if (player->mo->state-states == S_PLAY_FLOAT_RUN)
else if (P_IsPlayerInState(player, S_PLAY_FLOAT_RUN))
P_SetMobjState(player->mo, S_PLAY_RUN);
}
......@@ -8380,7 +8439,7 @@ void P_MovePlayer(player_t *player)
fixed_t glidespeed = player->actionspd;
fixed_t momx = mo->momx - player->cmomx, momy = mo->momy - player->cmomy;
angle_t angle, moveangle = R_PointToAngle2(0, 0, momx, momy);
boolean swimming = mo->state - states == S_PLAY_SWIM;
boolean swimming = P_IsPlayerInState(player, S_PLAY_SWIM);
boolean in2d = mo->flags2 & MF2_TWOD || twodlevel;
if (player->powers[pw_super] || player->powers[pw_sneakers])
......@@ -8527,7 +8586,7 @@ void P_MovePlayer(player_t *player)
}
}
}
else if (player->mo->state-states == S_PLAY_BOUNCE)
else if (P_IsPlayerInState(player, S_PLAY_BOUNCE))
P_SetMobjState(player->mo, S_PLAY_FALL);
// If you're running fast enough, you can create splashes as you run in shallow water.
......@@ -8571,7 +8630,7 @@ void P_MovePlayer(player_t *player)
if (!(player->charability == CA_FLY || player->charability == CA_SWIM)) // why are you flying when you cannot fly?!
{
if (player->powers[pw_tailsfly]
|| player->mo->state-states == S_PLAY_FLY_TIRED)
|| P_IsPlayerInState(player, S_PLAY_FLY_TIRED))
{
if (onground)
P_SetMobjState(player->mo, S_PLAY_WALK);
......@@ -8639,11 +8698,11 @@ void P_MovePlayer(player_t *player)
else
{
// Tails-gets-tired Stuff
if (player->panim == PA_ABILITY && player->mo->state-states != S_PLAY_FLY_TIRED)
if (player->panim == PA_ABILITY && !P_IsPlayerInState(player, S_PLAY_FLY_TIRED))
P_SetMobjState(player->mo, S_PLAY_FLY_TIRED);
if (player->charability == CA_FLY && (leveltime % 10 == 0)
&& player->mo->state-states == S_PLAY_FLY_TIRED
&& P_IsPlayerInState(player, S_PLAY_FLY_TIRED)
&& !(player->mo->eflags & MFE_UNDERWATER)
&& !player->spectator)
S_StartSound(player->mo, sfx_pudpud);
......@@ -8682,13 +8741,10 @@ void P_MovePlayer(player_t *player)
&& !(player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)))
P_ElementalFire(player, false);
if ((cmd->buttons & (BT_SPIN|BT_SHIELD)) == (BT_SPIN|BT_SHIELD) && !(player->pflags & (PF_SPINDOWN|PF_SHIELDDOWN)))
spinshieldhack = true; // Spin and Shield is bound to the same button (pressed on the same tic), so enable two-button play (Jump and Spin+Shield)
P_DoSpinAbility(player, cmd);
// jumping
P_DoJumpStuff(player, cmd, spinshieldhack);
P_DoJumpStuff(player, cmd);
// If you're not spinning, you'd better not be spindashing!
if (!(player->pflags & PF_SPINNING) && player->powers[pw_carry] != CR_NIGHTSMODE)
......@@ -8741,7 +8797,7 @@ void P_MovePlayer(player_t *player)
}
// Otherwise, face the direction you're travelling.
else if (player->panim == PA_WALK || player->panim == PA_RUN || player->panim == PA_DASH || player->panim == PA_ROLL || player->panim == PA_JUMP
|| (player->panim == PA_ABILITY && player->mo->state-states == S_PLAY_GLIDE))
|| (player->panim == PA_ABILITY && P_IsPlayerInState(player, S_PLAY_GLIDE)))
player->mo->angle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);
// Update the local angle control.
......@@ -8766,7 +8822,7 @@ void P_MovePlayer(player_t *player)
if (!(player->mo->momz || player->mo->momx || player->mo->momy) && !(player->mo->eflags & MFE_GOOWATER)
&& player->panim == PA_IDLE && !(player->powers[pw_carry]))
P_DoTeeter(player);
// Toss a flag
if (G_GametypeHasTeams() && (cmd->buttons & BT_TOSSFLAG) && !(player->powers[pw_super]) && !(player->tossdelay))
{
......@@ -8776,25 +8832,10 @@ void P_MovePlayer(player_t *player)
P_PlayerFlagBurst(player, true);
}
// Check for fire and shield buttons
// check for fire
if (!player->exiting)
{
P_DoFiring(player, cmd);
// Shield button behavior
// Check P_PlayerShieldThink for actual shields!
if ((cmd->buttons & BT_SHIELD) && !(player->pflags & PF_SHIELDDOWN) && !spinshieldhack)
{
// Transform into super if we can!
if (P_SuperReady(player, true))
P_DoSuperTransformation(player, false);
// Detransform from super if we can!
else if (P_SuperReady(player, false))
P_DoSuperDetransformation(player);
}
}
{
boolean atspinheight = false;
fixed_t oldheight = player->mo->height;
......@@ -8812,6 +8853,8 @@ void P_MovePlayer(player_t *player)
player->mo->height = P_GetPlayerSpinHeight(player);
atspinheight = true;
}
else if (player->powers[pw_carry] == CR_PLAYER || player->powers[pw_carry] == CR_PTERABYTE) // You're slightly shorter while being carried
player->mo->height = FixedDiv(P_GetPlayerHeight(player), FixedDiv(14*FRACUNIT,10*FRACUNIT));
else
player->mo->height = P_GetPlayerHeight(player);
......@@ -9015,7 +9058,7 @@ static void P_DoRopeHang(player_t *player)
return;
}
if (player->mo->state-states != S_PLAY_RIDE)
if (!P_IsPlayerInState(player, S_PLAY_RIDE))
P_SetMobjState(player->mo, S_PLAY_RIDE);
// If not allowed to move, we're done here.
......@@ -9142,7 +9185,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (think->removing)
continue;
mo = (mobj_t *)think;
......@@ -9240,7 +9283,7 @@ mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction,
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (think->removing)
continue;
mo = (mobj_t *)think;
......@@ -9359,7 +9402,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (think->removing)
continue;
mo = (mobj_t *)think;
......@@ -9505,7 +9548,7 @@ void P_FindEmerald(void)
// to find all emeralds
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -9813,7 +9856,7 @@ static CV_PossibleValue_t campos_cons_t[] = { {INT32_MIN, "MIN"}, {INT32_MAX, "M
consvar_t cv_cam_dist = CVAR_INIT ("cam_curdist", "160", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
consvar_t cv_cam_height = CVAR_INIT ("cam_curheight", "25", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
consvar_t cv_cam_still = CVAR_INIT ("cam_still", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
consvar_t cv_cam_speed = CVAR_INIT ("cam_speed", "0.3", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
consvar_t cv_cam_speed = CVAR_INIT ("cam_speed", "0.4", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
consvar_t cv_cam_rotate = CVAR_INIT ("cam_rotate", "0", CV_CALL|CV_NOINIT|CV_ALLOWLUA, CV_CamRotate, CV_CamRotate_OnChange);
consvar_t cv_cam_rotspeed = CVAR_INIT ("cam_rotspeed", "10", CV_SAVE|CV_ALLOWLUA, rotation_cons_t, NULL);
consvar_t cv_cam_turnmultiplier = CVAR_INIT ("cam_turnmultiplier", "0.75", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, multiplier_cons_t, NULL);
......@@ -9822,7 +9865,7 @@ consvar_t cv_cam_adjust = CVAR_INIT ("cam_adjust", "On", CV_SAVE|CV_ALLOWLUA, CV
consvar_t cv_cam2_dist = CVAR_INIT ("cam2_curdist", "160", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
consvar_t cv_cam2_height = CVAR_INIT ("cam2_curheight", "25", CV_FLOAT|CV_ALLOWLUA, campos_cons_t, NULL);
consvar_t cv_cam2_still = CVAR_INIT ("cam2_still", "Off", CV_ALLOWLUA, CV_OnOff, NULL);
consvar_t cv_cam2_speed = CVAR_INIT ("cam2_speed", "0.3", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
consvar_t cv_cam2_speed = CVAR_INIT ("cam2_speed", "0.4", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, CV_CamSpeed, NULL);
consvar_t cv_cam2_rotate = CVAR_INIT ("cam2_rotate", "0", CV_CALL|CV_NOINIT|CV_ALLOWLUA, CV_CamRotate, CV_CamRotate2_OnChange);
consvar_t cv_cam2_rotspeed = CVAR_INIT ("cam2_rotspeed", "10", CV_SAVE|CV_ALLOWLUA, rotation_cons_t, NULL);
consvar_t cv_cam2_turnmultiplier = CVAR_INIT ("cam2_turnmultiplier", "0.75", CV_FLOAT|CV_SAVE|CV_ALLOWLUA, multiplier_cons_t, NULL);
......@@ -9952,9 +9995,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
&& !((gametyperules & GTR_FRIENDLY) && (netgame || multiplayer) && cv_exitmove.value)
&& !(twodlevel || (mo->flags2 & MF2_TWOD)))
sign = mo->target;
else if ((player->powers[pw_carry] == CR_NIGHTSMODE)
&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6]))
else if (player->powers[pw_carry] == CR_NIGHTSMODE && !P_IsPlayerInNightsTransformationState(player))
{
P_CalcChasePostImg(player, thiscam);
return true;
......@@ -10906,7 +10947,7 @@ static mobj_t *P_GetAxis(INT32 num)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mobj = (mobj_t *)th;
......@@ -11271,7 +11312,7 @@ static void P_MinecartThink(player_t *player)
}
}
if (player->mo->state-states != S_PLAY_STND)
if (!P_IsPlayerInState(player, S_PLAY_STND))
{
P_SetMobjState(player->mo, S_PLAY_STND);
player->mo->tics = -1;
......@@ -11349,12 +11390,12 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
}
else if (player->panim == PA_PAIN)
backwards /= 16;
else if (player->mo->state-states == S_PLAY_GASP)
else if (P_IsPlayerInState(player, S_PLAY_GASP))
{
backwards /= 16;
zoffs += 12*FRACUNIT;
}
else if (player->mo->state-states == S_PLAY_EDGE)
else if (P_IsPlayerInState(player, S_PLAY_EDGE))
{
backwards /= 16;
zoffs = 3*FRACUNIT;
......@@ -11383,13 +11424,13 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
}
else if (player->panim == PA_SPRING || player->panim == PA_JUMP)
chosenstate = S_TAILSOVERLAY_MINUS60DEGREES;
else if (player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
else if (player->panim == PA_FALL || P_IsPlayerInState(player, S_PLAY_RIDE))
chosenstate = S_TAILSOVERLAY_PLUS60DEGREES;
else if (player->panim == PA_PAIN)
chosenstate = S_TAILSOVERLAY_PAIN;
else if (player->mo->state-states == S_PLAY_GASP)
else if (P_IsPlayerInState(player, S_PLAY_GASP))
chosenstate = S_TAILSOVERLAY_GASP;
else if (player->mo->state-states == S_PLAY_EDGE)
else if (P_IsPlayerInState(player, S_PLAY_EDGE))
chosenstate = S_TAILSOVERLAY_EDGE;
else if (player->panim == PA_DASH)
chosenstate = S_TAILSOVERLAY_DASH;
......@@ -11397,7 +11438,7 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
chosenstate = S_TAILSOVERLAY_RUN;
else if (player->panim == PA_WALK)
{
if (!smilesonground || player->mo->state-states == S_PLAY_SKID)
if (!smilesonground || P_IsPlayerInState(player, S_PLAY_SKID))
chosenstate = S_TAILSOVERLAY_PLUS30DEGREES;
else if (player->speed >= FixedMul(player->runspeed/2, player->mo->scale))
chosenstate = S_TAILSOVERLAY_0DEGREES;
......@@ -11439,7 +11480,7 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
#endif
// animation...
if (player->panim == PA_SPRING || player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
if (player->panim == PA_SPRING || player->panim == PA_FALL || P_IsPlayerInState(player, S_PLAY_RIDE))
{
if (FixedDiv(abs(player->mo->momz), player->mo->scale) < 20<<FRACBITS)
ticnum = 2;
......@@ -11448,7 +11489,7 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
}
else if (player->panim == PA_PAIN)
ticnum = 2;
else if (player->mo->state-states == S_PLAY_GASP)
else if (P_IsPlayerInState(player, S_PLAY_GASP))
tails->tics = -1;
else if (player->mo->sprite2 == SPR2_TIRE)
ticnum = (doswim ? 2 : 4);
......@@ -11495,6 +11536,18 @@ void P_DoTailsOverlay(player_t *player, mobj_t *tails)
}
// Metal Sonic's jet fume
//
// The follow object's state is set to its spawn state when deactivated.
// When the player is on a moving animation, the follow object goes to its see state.
// When dash mode is entered, the follow object switches to its melee state.
//
// If MF2_FRET is set, the jet fume will flash during dash mode.
// MF2_AMBUSH can be used to enable Metal Sonic's skidding animation.
// MF2_JUSTATTACKED will enable the color cycling.
// If the follow item is MT_METALJETFUME, the above two effects are automatically applied.
//
// MF2_STRONGBOX is internally used to track if the jet fume is in its deactivated state or not.
// MF2_BOSSNOTRAP is internally used to instantly reset the jet fume's scale to its intended scale.
void P_DoMetalJetFume(player_t *player, mobj_t *fume)
{
static const UINT8 FUME_SKINCOLORS[] =
......@@ -11521,15 +11574,28 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
fixed_t heightoffset = ((mo->eflags & MFE_VERTICALFLIP) ? mo->height - (P_GetPlayerHeight(player) >> 1) : (P_GetPlayerHeight(player) >> 1));
panim_t panim = player->panim;
tic_t dashmode = min(player->dashmode, DASHMODE_MAX);
boolean ismetaljetfume = fume->type == MT_METALJETFUME;
boolean notmoving = panim != PA_WALK && panim != PA_RUN && panim != PA_DASH;
boolean underwater = mo->eflags & MFE_UNDERWATER;
statenum_t stat = fume->state-states;
boolean resetinterp = false;
if (panim != PA_WALK && panim != PA_RUN && panim != PA_DASH) // turn invisible when not in a coherent movement state
if (notmoving) // deactivate when not in a coherent movement state
{
if (stat != fume->info->spawnstate)
if ((fume->flags2 & MF2_STRONGBOX) == 0)
{
P_SetMobjState(fume, fume->info->spawnstate);
return;
fume->flags2 |= MF2_STRONGBOX;
}
if (P_MobjWasRemoved(fume) || ismetaljetfume)
return;
}
// Rotate on skid animation if follow item is MT_METALJETFUME, or if MF2_AMBUSH is set
if (player->mo->sprite2 == SPR2_SKID)
{
if ((ismetaljetfume && (player->charflags & SF_JETFUME)) || (fume->flags2 & MF2_AMBUSH))
angle += ANGLE_90;
}
if (underwater) // No fume underwater; spawn bubbles instead!
......@@ -11567,54 +11633,82 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
if (panim == PA_WALK)
{
if (stat != fume->info->spawnstate)
if ((fume->flags2 & MF2_STRONGBOX) == 0)
{
fume->threshold = 0;
P_SetMobjState(fume, fume->info->spawnstate);
fume->threshold = 0;
fume->flags2 &= ~MF2_STRONGBOX;
}
return;
if (P_MobjWasRemoved(fume) || ismetaljetfume)
return;
}
}
if (stat == fume->info->spawnstate) // If currently inivisble, activate!
// If currently deactivated, activate!
if (!notmoving && !underwater && (fume->flags2 & MF2_STRONGBOX))
{
P_SetMobjState(fume, (stat = fume->info->seestate));
if (P_MobjWasRemoved(fume))
return;
P_SetScale(fume, mo->scale, false);
fume->flags2 &= ~MF2_STRONGBOX;
resetinterp = true;
}
if (dashmode > DASHMODE_THRESHOLD && stat != fume->info->seestate) // If in dashmode, grow really big and flash
// If in dash mode, grow really big
if (dashmode > DASHMODE_THRESHOLD && stat != fume->info->meleestate)
{
fume->destscale = mo->scale;
fume->flags2 ^= MF2_DONTDRAW;
fume->flags2 |= mo->flags2 & MF2_DONTDRAW;
// Flash if follow item is MT_METALJETFUME, or if MF2_FRET is set
if (ismetaljetfume || (fume->flags2 & MF2_FRET))
fume->flags2 ^= MF2_DONTDRAW;
}
else // Otherwise, pick a size and color depending on speed and proximity to dashmode
{
if (dashmode == DASHMODE_THRESHOLD && dashmode > (tic_t)fume->movecount) // If just about to enter dashmode, play the startup animation again
// If just about to enter dash mode, play the startup animation again
if (dashmode == DASHMODE_THRESHOLD && dashmode > (tic_t)fume->movecount)
{
P_SetMobjState(fume, (stat = fume->info->seestate));
P_SetMobjState(fume, fume->info->meleestate);
if (P_MobjWasRemoved(fume))
return;
P_SetScale(fume, 2*mo->scale, true);
}
fume->flags2 = (fume->flags2 & ~MF2_DONTDRAW) | (mo->flags2 & MF2_DONTDRAW);
fume->destscale = (mo->scale + FixedDiv(player->speed, player->normalspeed)) / (underwater ? 6 : 3);
fume->color = FUME_SKINCOLORS[(dashmode * sizeof(FUME_SKINCOLORS)) / (DASHMODE_MAX + 1)];
// Do color cycling if follow item is MT_METALJETFUME, or if MF2_JUSTATTACKED is set
if (ismetaljetfume || (fume->flags2 & MF2_JUSTATTACKED))
fume->color = FUME_SKINCOLORS[(dashmode * sizeof(FUME_SKINCOLORS)) / (DASHMODE_MAX + 1)];
if (underwater)
{
fume->frame = (fume->frame & FF_FRAMEMASK) | FF_ANIMATE | (P_RandomRange(0, 9) * FF_TRANS10);
fume->frame = (fume->frame & ~FF_TRANSMASK) | (P_RandomRange(0, 9) << FF_TRANSSHIFT);
fume->threshold = 1;
}
else if (fume->threshold)
{
fume->frame = (fume->frame & FF_FRAMEMASK) | fume->state->frame;
fume->frame = (fume->frame & FF_FRAMEMASK) | (fume->state->frame & ~FF_FRAMEMASK);
fume->threshold = 0;
}
}
fume->movecount = dashmode; // keeps track of previous dashmode value so we know whether Metal is entering or leaving it
fume->flags2 = (fume->flags2 & ~MF2_OBJECTFLIP) | (mo->flags2 & MF2_OBJECTFLIP); // Make sure to flip in reverse gravity!
fume->eflags = (fume->eflags & ~MFE_VERTICALFLIP) | (mo->eflags & MFE_VERTICALFLIP); // Make sure to flip in reverse gravity!
// keeps track of previous dash mode value so we know whether Metal is entering or leaving it
fume->movecount = dashmode;
// Make sure to flip in reverse gravity!
fume->flags2 = (fume->flags2 & ~MF2_OBJECTFLIP) | (mo->flags2 & MF2_OBJECTFLIP);
fume->eflags = (fume->eflags & ~MFE_VERTICALFLIP) | (mo->eflags & MFE_VERTICALFLIP);
// Set the appropriate scale at spawn
// This is... strange, but I had to choose a flag that a follow object would not ordinarily use.
if ((fume->flags2 & MF2_BOSSNOTRAP) == 0)
{
P_SetScale(fume, fume->destscale, true);
fume->flags2 |= MF2_BOSSNOTRAP;
}
// Finally, set its position
dist = -mo->radius - FixedMul(fume->info->radius, fume->destscale - mo->scale/3);
......@@ -11624,9 +11718,10 @@ void P_DoMetalJetFume(player_t *player, mobj_t *fume)
fume->y = mo->y + P_ReturnThrustY(fume, angle, dist);
fume->z = mo->z + heightoffset - (fume->height >> 1);
P_SetThingPosition(fume);
if (resetinterp) R_ResetMobjInterpolationState(fume);
if (resetinterp)
R_ResetMobjInterpolationState(fume);
// If dashmode is high enough, spawn a trail
// If dash mode is high enough, spawn a trail
if (player->normalspeed >= skins[player->skin]->normalspeed*2)
{
mobj_t *ghost = P_SpawnGhostMobj(fume);
......@@ -11640,6 +11735,8 @@ void P_DoFollowMobj(player_t *player, mobj_t *followmobj)
{
if (LUA_HookFollowMobj(player, followmobj) || P_MobjWasRemoved(followmobj))
{;}
else if (player->charflags & SF_JETFUME)
P_DoMetalJetFume(player, followmobj);
else
{
switch (followmobj->type)
......@@ -11988,7 +12085,7 @@ void P_PlayerThink(player_t *player)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
if (th->removing)
continue;
mo2 = (mobj_t *)th;
......@@ -12048,7 +12145,7 @@ void P_PlayerThink(player_t *player)
ticmiss++;
P_DoRopeHang(player);
P_DoJumpStuff(player, &player->cmd, false); // P_DoRopeHang would set PF_SPINDOWN, so no spinshieldhack here
P_DoJumpStuff(player, &player->cmd);
}
else //if (player->powers[pw_carry] == CR_ZOOMTUBE)
{
......@@ -12129,6 +12226,10 @@ void P_PlayerThink(player_t *player)
case CR_DUSTDEVIL:
player->drawangle += ANG20;
break;
case CR_FAN:
if (player->pflags & PF_ANALOGMODE) // Don't impact drawangle in any special way when on a fan
player->drawangle = player->mo->angle;
break;
/* -- in case we wanted to have the camera freely movable during zoom tubes
case CR_ZOOMTUBE:*/
case CR_ROPEHANG:
......@@ -12211,10 +12312,9 @@ void P_PlayerThink(player_t *player)
diff = InvAngle(diff);
if (diff > ANG10/2)
{
statenum_t stat = player->mo->state-states;
if (stat == S_PLAY_WAIT)
if (P_IsPlayerInState(player, S_PLAY_WAIT))
P_SetMobjState(player->mo, S_PLAY_STND);
else if (stat == S_PLAY_STND && player->mo->tics != -1)
else if (P_IsPlayerInState(player, S_PLAY_STND) && player->mo->tics != -1)
player->mo->tics++;
}
}
......@@ -12239,7 +12339,7 @@ void P_PlayerThink(player_t *player)
// fake skidding! see P_SkidStuff for reference on conditionals
else if (!player->skidtime && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID) && P_AproxDistance(player->mo->momx, player->mo->momy) >= FixedMul(player->runspeed, player->mo->scale)) // modified from player->runspeed/2 'cuz the skid was just TOO frequent ngl
{
if (player->mo->state-states != S_PLAY_SKID)
if (!P_IsPlayerInState(player, S_PLAY_SKID))
P_SetMobjState(player->mo, S_PLAY_SKID);
player->mo->tics = player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
......@@ -12318,12 +12418,6 @@ void P_PlayerThink(player_t *player)
player->pflags &= ~PF_SPINDOWN;
}
// Check for Shield button
if (cmd->buttons & BT_SHIELD)
player->pflags |= PF_SHIELDDOWN;
else
player->pflags &= ~PF_SHIELDDOWN;
// IF PLAYER NOT HERE THEN FLASH END IF
if (player->quittime && player->powers[pw_flashing] < flashingtics - 1
&& !(G_TagGametype() && !(player->pflags & PF_TAGIT)) && !player->gotflag)
......@@ -12416,16 +12510,14 @@ void P_PlayerThink(player_t *player)
player->stronganim = 0;
//pw_super acts as a timer now
if (player->powers[pw_super]
&& (player->mo->state < &states[S_PLAY_SUPER_TRANS1]
|| player->mo->state > &states[S_PLAY_SUPER_TRANS6]))
if (player->powers[pw_super] && !P_IsPlayerInSuperTransformationState(player))
player->powers[pw_super]++;
if (player->powers[pw_carry] == CR_BRAKGOOP)
{
if (!player->powers[pw_flashing])
{
if (player->mo->state != &states[S_PLAY_STND])
if (!P_IsPlayerInState(player, S_PLAY_STND))
P_SetMobjState(player->mo, S_PLAY_STND);
else
player->mo->tics = 2;
......@@ -12474,8 +12566,6 @@ void P_PlayerThink(player_t *player)
else
player->mo->flags2 &= ~MF2_DONTDRAW;
player->pflags &= ~PF_SLIDING;
#define dashmode player->dashmode
// Dash mode - thanks be to VelocitOni
if ((player->charflags & SF_DASHMODE) && !player->gotflag && !player->powers[pw_carry] && !player->exiting && !(maptol & TOL_NIGHTS) && !metalrecording) // woo, dashmode! no nights tho.
......@@ -12552,6 +12642,12 @@ void P_PlayerThink(player_t *player)
LUA_HookPlayer(player, HOOK(PlayerThink));
// Remove PF_SLIDING *AFTER* PlayerThink hooks, because
// no one wants to add a ThinkFrame just for detecting this (i'm also very lazy)
// This is such a trivial change, I doubt it'll change anything major
// -luigi budd
player->pflags &= ~PF_SLIDING;
/*
// Colormap verification
{
......@@ -12790,7 +12886,7 @@ void P_PlayerAfterThink(player_t *player)
S_StartSound(NULL, sfx_wepchg);
if ((player->pflags & PF_SLIDING) && ((player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE)) != PF_JUMPED))
P_SetMobjState(player->mo, player->mo->info->painstate);
P_SetMobjState(player->mo, S_PLAY_PAIN);
/* if (player->powers[pw_carry] == CR_NONE && player->mo->tracer && !player->homing)
P_SetTarget(&player->mo->tracer, NULL);
......@@ -12829,9 +12925,9 @@ void P_PlayerAfterThink(player_t *player)
else
{
if (tails->player)
P_TryMove(player->mo, tails->x + P_ReturnThrustX(tails, tails->player->drawangle, 4*FRACUNIT), tails->y + P_ReturnThrustY(tails, tails->player->drawangle, 4*FRACUNIT), true);
P_TryMove(player->mo, tails->x + P_ReturnThrustX(tails, tails->player->drawangle, 4*tails->scale), tails->y + P_ReturnThrustY(tails, tails->player->drawangle, 4*tails->scale), true);
else
P_TryMove(player->mo, tails->x + P_ReturnThrustX(tails, tails->angle, 4*FRACUNIT), tails->y + P_ReturnThrustY(tails, tails->angle, 4*FRACUNIT), true);
P_TryMove(player->mo, tails->x + P_ReturnThrustX(tails, tails->angle, 4*tails->scale), tails->y + P_ReturnThrustY(tails, tails->angle, 4*tails->scale), true);
player->mo->momx = tails->momx;
player->mo->momy = tails->momy;
player->mo->momz = tails->momz;
......@@ -12845,12 +12941,12 @@ void P_PlayerAfterThink(player_t *player)
P_SetPlayerAngle(player, player->mo->angle);
}
if (P_AproxDistance(player->mo->x - tails->x, player->mo->y - tails->y) > player->mo->radius)
if (P_AproxDistance(player->mo->x - tails->x, player->mo->y - tails->y) > tails->radius)
player->powers[pw_carry] = CR_NONE;
if (player->powers[pw_carry] == CR_PLAYER)
{
if (player->mo->state-states != S_PLAY_RIDE)
if (!P_IsPlayerInState(player, S_PLAY_RIDE))
P_SetMobjState(player->mo, S_PLAY_RIDE);
if (tails->player && (tails->skin && ((skin_t *)(tails->skin))->sprites[SPR2_SWIM].numframes) && (tails->eflags & MFE_UNDERWATER))
tails->player->powers[pw_tailsfly] = 0;
......@@ -12875,7 +12971,7 @@ void P_PlayerAfterThink(player_t *player)
player->mo->z = item->z - FixedDiv(player->mo->height, 3*FRACUNIT/2);
player->mo->momx = player->mo->momy = player->mo->momz = 0;
P_SetThingPosition(player->mo);
if (player->mo->state-states != S_PLAY_RIDE)
if (!P_IsPlayerInState(player, S_PLAY_RIDE))
P_SetMobjState(player->mo, S_PLAY_RIDE);
// Controllable missile
......@@ -13066,14 +13162,14 @@ void P_PlayerAfterThink(player_t *player)
player->mo->momy = ptera->momy;
player->mo->momz = ptera->momz;
if (P_AproxDistance(player->mo->x - ptera->x - ptera->watertop, player->mo->y - ptera->y - ptera->waterbottom) > player->mo->radius)
if (P_AproxDistance(player->mo->x - ptera->x - ptera->watertop, player->mo->y - ptera->y - ptera->waterbottom) > ptera->radius)
goto dropoff;
ptera->watertop >>= 1;
ptera->waterbottom >>= 1;
ptera->cvmem >>= 1;
if (player->mo->state-states != S_PLAY_FALL)
if (!P_IsPlayerInState(player, S_PLAY_FALL))
P_SetMobjState(player->mo, S_PLAY_FALL);
break;
......@@ -13143,7 +13239,8 @@ void P_PlayerAfterThink(player_t *player)
player->followmobj->colorized = true;
break;
default:
player->followmobj->flags2 |= MF2_LINKDRAW;
if ((player->charflags & SF_JETFUME) == 0)
player->followmobj->flags2 |= MF2_LINKDRAW;
break;
}
}
......@@ -13219,9 +13316,9 @@ boolean P_PlayerCanEnterSpinGaps(player_t *player)
return false;
return ((player->pflags & (PF_SPINNING|PF_SLIDING|PF_GLIDING)) // players who are spinning, sliding, or gliding
|| (player->charability == CA_GLIDEANDCLIMB && player->mo->state-states == S_PLAY_GLIDE_LANDING) // players who are landing from a glide
|| (player->charability == CA_GLIDEANDCLIMB && P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING)) // players who are landing from a glide
|| ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)
&& player->dashmode >= DASHMODE_THRESHOLD && player->mo->state-states == S_PLAY_DASH) // machine players in dashmode
&& player->dashmode >= DASHMODE_THRESHOLD && P_IsPlayerInState(player, S_PLAY_DASH)) // machine players in dashmode
|| JUMPCURLED(player)); // players who are jumpcurled, but only if they would normally jump that way
}
......@@ -13229,13 +13326,13 @@ boolean P_PlayerCanEnterSpinGaps(player_t *player)
boolean P_PlayerShouldUseSpinHeight(player_t *player)
{
return ((player->pflags & (PF_SPINNING|PF_SLIDING|PF_GLIDING))
|| (player->mo->state == &states[player->mo->info->painstate])
|| P_IsPlayerInState(player, S_PLAY_PAIN)
|| (player->panim == PA_ROLL)
|| ((player->powers[pw_tailsfly] || (player->charability == CA_FLY && player->mo->state-states == S_PLAY_FLY_TIRED))
|| ((player->powers[pw_tailsfly] || (player->charability == CA_FLY && P_IsPlayerInState(player, S_PLAY_FLY_TIRED)))
&& !(player->charflags & SF_NOJUMPSPIN))
|| (player->charability == CA_GLIDEANDCLIMB && player->mo->state-states == S_PLAY_GLIDE_LANDING)
|| (player->charability == CA_GLIDEANDCLIMB && P_IsPlayerInState(player, S_PLAY_GLIDE_LANDING))
|| ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)
&& player->dashmode >= DASHMODE_THRESHOLD && player->mo->state-states == S_PLAY_DASH)
&& player->dashmode >= DASHMODE_THRESHOLD && P_IsPlayerInState(player, S_PLAY_DASH))
|| JUMPCURLED(player));
}
......
......@@ -275,7 +275,7 @@ boolean R_ThingBoundingBoxVisible(mobj_t *thing)
switch (thing->type)
{
default:
// First person / awayviewmobj -- rendering a bbox
// First person / awayviewmobj -- rendering a bbox
// too close to the viewpoint causes anomalies
// and these are exactly on the viewpoint!
if (thing != r_viewmobj)
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -230,6 +230,18 @@ static INT32 R_DoorClosed(void)
&& (backsector->floorheight <= frontsector->floorheight || curline->sidedef->bottomtexture);
}
static UINT8 R_FloorLightLevel(sector_t *sector, INT16 base_lightlevel)
{
return max(0, min(255, sector->floorlightlevel +
((sector->floorlightabsolute) ? 0 : base_lightlevel)));
}
static UINT8 R_CeilingLightLevel(sector_t *sector, INT16 base_lightlevel)
{
return max(0, min(255, sector->ceilinglightlevel +
((sector->ceilinglightabsolute) ? 0 : base_lightlevel)));
}
//
// If player's view height is underneath fake floor, lower the
// drawn ceiling to be just under the floor height, and replace
......@@ -312,11 +324,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
tempsec->lightlevel = s->lightlevel;
if (floorlightlevel)
*floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel)))
*floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel)))
: sectors[s->floorlightsec].lightlevel;
if (ceilinglightlevel)
*ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel)))
*ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel)))
: sectors[s->ceilinglightsec].lightlevel;
}
else if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight
......@@ -356,11 +368,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
tempsec->lightlevel = s->lightlevel;
if (floorlightlevel)
*floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel)))
*floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel)))
: sectors[s->floorlightsec].lightlevel;
if (ceilinglightlevel)
*ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel)))
*ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel)))
: sectors[s->ceilinglightsec].lightlevel;
}
sec = tempsec;
......@@ -968,11 +980,10 @@ static void R_Subsector(size_t num)
&& ((viewz < heightcheck && (rover->fofflags & FOF_BOTHPLANES || !(rover->fofflags & FOF_INVERTPLANES)))
|| (viewz > heightcheck && (rover->fofflags & FOF_BOTHPLANES || rover->fofflags & FOF_INVERTPLANES))))
{
light = R_GetPlaneLight(frontsector, planecenterz,
viewz < heightcheck);
light = R_GetPlaneLight(frontsector, planecenterz, viewz < heightcheck);
ffloor[numffloors].plane = R_FindPlane(rover->master->frontsector, *rover->bottomheight, *rover->bottompic,
*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs, *rover->bottomyoffs,
R_FloorLightLevel(rover->master->frontsector, *frontsector->lightlist[light].lightlevel), *rover->bottomxoffs, *rover->bottomyoffs,
*rover->bottomxscale, *rover->bottomyscale, *rover->bottomangle,
*frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->b_slope, NULL);
......@@ -1002,7 +1013,7 @@ static void R_Subsector(size_t num)
light = R_GetPlaneLight(frontsector, planecenterz, viewz < heightcheck);
ffloor[numffloors].plane = R_FindPlane(rover->master->frontsector, *rover->topheight, *rover->toppic,
*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs,
R_CeilingLightLevel(rover->master->frontsector, *frontsector->lightlist[light].lightlevel), *rover->topxoffs, *rover->topyoffs,
*rover->topxscale, *rover->topyscale, *rover->topangle,
*frontsector->lightlist[light].extra_colormap, rover, NULL, *rover->t_slope, NULL);
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -426,9 +426,6 @@ void R_ClearColormaps(void)
{
// Purged by PU_LEVEL, just overwrite the pointer
extra_colormaps = R_CreateDefaultColormap(true);
#ifdef HWRENDER
HWR_ClearLightTables();
#endif
}
//
......@@ -849,6 +846,15 @@ void R_GenerateLightTable(extracolormap_t *extra_colormap, boolean uselookup)
}
}
void R_UpdateLightTable(extracolormap_t *extra_colormap, boolean uselookup)
{
R_GenerateLightTable(extra_colormap, uselookup);
#ifdef HWRENDER
extra_colormap->gl_lighttable.needs_update = true;
#endif
}
extracolormap_t *R_CreateColormapFromLinedef(char *p1, char *p2, char *p3)
{
// default values
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -90,6 +90,7 @@ typedef enum
} textmapcolormapflags_t;
void R_GenerateLightTable(extracolormap_t *extra_colormap, boolean uselookup);
void R_UpdateLightTable(extracolormap_t *extra_colormap, boolean uselookup);
lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap);
extracolormap_t * R_CreateColormapFromLinedef(char *p1, char *p2, char *p3);
extracolormap_t* R_CreateColormap(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, UINT8 flags);
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -60,6 +60,8 @@ typedef UINT8 lighttable_t;
#define CMF_FADEFULLBRIGHTSPRITES 1
#define CMF_FOG 4
#define TEXTURE_255_IS_TRANSPARENT
// ExtraColormap type. Use for extra_colormaps from now on.
typedef struct extracolormap_s
{
......@@ -74,8 +76,11 @@ typedef struct extracolormap_s
lighttable_t *colormap;
#ifdef HWRENDER
// The id of the hardware lighttable. Zero means it does not exist yet.
UINT32 gl_lighttable_id;
struct {
UINT32 id; // The id of the hardware lighttable. Zero means it does not exist yet.
RGBA_t *data; // The texture data of the hardware lighttable.
boolean needs_update; // If the colormap changed recently or not.
} gl_lighttable;
#endif
#ifdef EXTRACOLORMAPLUMPS
......@@ -240,9 +245,8 @@ typedef struct sectorportal_s
struct sector_s *sector;
struct mobj_s *mobj;
};
struct {
fixed_t x, y;
} origin;
struct sector_s *target;
boolean ceiling;
} sectorportal_t;
typedef struct ffloor_s
......@@ -358,7 +362,7 @@ typedef struct pslope_s
double dzdelta;
boolean moved : 1;
boolean moved;
UINT8 flags; // Slope options
} pslope_t;
......@@ -552,6 +556,8 @@ typedef struct sector_s
// portals
UINT32 portal_floor;
UINT32 portal_ceiling;
struct customargs_s* customargs;
} sector_t;
//
......@@ -612,6 +618,9 @@ typedef struct line_s
INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0
UINT32 secportal; // transferred sector portal
struct pslope_s *midtexslope;
struct customargs_s *customargs;
} line_t;
typedef struct
......@@ -629,6 +638,11 @@ typedef struct
fixed_t scalex_top, scalex_mid, scalex_bottom;
fixed_t scaley_top, scaley_mid, scaley_bottom;
// per-wall lighting for UDMF
// TODO: implement per-texture lighting
INT16 light, light_top, light_mid, light_bottom;
boolean lightabsolute, lightabsolute_top, lightabsolute_mid, lightabsolute_bottom;
// Texture indices.
// We do not maintain names here.
INT32 toptexture, bottomtexture, midtexture;
......@@ -643,6 +657,7 @@ typedef struct
INT16 repeatcnt; // # of times to repeat midtexture
extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors.
struct customargs_s* customargs;
} side_t;
//
......@@ -976,6 +991,8 @@ typedef struct
#endif
} spriteframe_t;
#define MAXFRAMENUM 256
//
// A sprite definition: a number of animation frames.
//
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -19,7 +19,6 @@
#include "doomstat.h"
#include "r_local.h"
#include "r_translation.h"
#include "st_stuff.h" // need ST_HEIGHT
#include "i_video.h"
#include "v_video.h"
#include "m_misc.h"
......@@ -74,7 +73,7 @@ UINT8 *dc_transmap; // one of the translucency tables
UINT8 *dc_translation;
struct r_lightlist_s *dc_lightlist = NULL;
INT32 dc_numlights = 0, dc_maxlights, dc_texheight;
INT32 dc_numlights = 0, dc_maxlights, dc_texheight, dc_postlength;
// =========================================================================
// SPAN DRAWING CODE STUFF
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -41,8 +41,7 @@ extern UINT8 *dc_translation;
extern struct r_lightlist_s *dc_lightlist;
extern INT32 dc_numlights, dc_maxlights;
//Fix TUTIFRUTI
extern INT32 dc_texheight;
extern INT32 dc_texheight, dc_postlength;
// -----------------------
// SPAN DRAWING CODE STUFF
......@@ -154,8 +153,12 @@ void R_VideoErase(size_t ofs, INT32 count);
// -----------------
void R_DrawColumn_8(void);
void R_DrawColumnClamped_8(void);
void R_Draw2sMultiPatchColumn_8(void);
void R_DrawShadeColumn_8(void);
void R_DrawTranslucentColumn_8(void);
void R_DrawTranslucentColumnClamped_8(void);
void R_Draw2sMultiPatchTranslucentColumn_8(void);
void R_DrawDropShadowColumn_8(void);
void R_DrawTranslatedColumn_8(void);
void R_DrawTranslatedTranslucentColumn_8(void);
......@@ -170,6 +173,7 @@ void R_DrawTiltedTranslucentSpan_8(void);
void R_DrawSplat_8(void);
void R_DrawTranslucentSplat_8(void);
void R_DrawTiltedSplat_8(void);
void R_DrawTiltedTranslucentSplat_8(void);
void R_DrawFloorSprite_8(void);
void R_DrawTranslucentFloorSprite_8(void);
......@@ -191,6 +195,7 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void);
void R_DrawSplat_NPO2_8(void);
void R_DrawTranslucentSplat_NPO2_8(void);
void R_DrawTiltedSplat_NPO2_8(void);
void R_DrawTiltedTranslucentSplat_NPO2_8(void);
void R_DrawFloorSprite_NPO2_8(void);
void R_DrawTranslucentFloorSprite_NPO2_8(void);
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -100,6 +100,281 @@ void R_DrawColumn_8(void)
}
}
/** \brief The R_DrawColumnClamped_8 function
Same as R_DrawColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions)
*/
void R_DrawColumnClamped_8(void)
{
INT32 count;
UINT8 *dest;
fixed_t frac;
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0) // Zero length, column does not exceed a pixel.
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
return;
#endif
// Framebuffer destination address.
dest = &topleft[dc_yl*vid.width + dc_x];
count++;
// Determine scaling, which is the only mapping to be done.
fracstep = dc_iscale;
frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
// This is as fast as it gets.
{
const UINT8 *source = dc_source;
const lighttable_t *colormap = dc_colormap;
INT32 heightmask = dc_texheight-1;
INT32 idx;
if (dc_texheight & heightmask) // not a power of 2 -- killough
{
heightmask++;
heightmask <<= FRACBITS;
if (frac < 0)
while ((frac += heightmask) < 0);
else
while (frac >= heightmask)
frac -= heightmask;
do
{
// Re-map color indices from wall texture column
// using a lighting/special effects LUT.
// heightmask is the Tutti-Frutti fix
idx = frac>>FRACBITS;
if (idx >= 0 && idx < dc_postlength)
*dest = colormap[source[idx]];
dest += vid.width;
// Avoid overflow.
if (fracstep > 0x7FFFFFFF - frac)
frac += fracstep - heightmask;
else
frac += fracstep;
while (frac >= heightmask)
frac -= heightmask;
} while (--count);
}
else
{
while ((count -= 2) >= 0) // texture height is a power of 2
{
idx = (frac>>FRACBITS) & heightmask;
if (idx >= 0 && idx < dc_postlength)
*dest = colormap[source[idx]];
dest += vid.width;
frac += fracstep;
idx = (frac>>FRACBITS) & heightmask;
if (idx >= 0 && idx < dc_postlength)
*dest = colormap[source[idx]];
dest += vid.width;
frac += fracstep;
}
if (count & 1)
{
idx = (frac>>FRACBITS) & heightmask;
if (idx >= 0 && idx < dc_postlength)
*dest = colormap[source[idx]];
}
}
}
}
void R_Draw2sMultiPatchColumn_8(void)
{
INT32 count;
register UINT8 *dest;
register fixed_t frac;
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0) // Zero length, column does not exceed a pixel.
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
return;
#endif
// Framebuffer destination address.
dest = &topleft[dc_yl*vid.width + dc_x];
count++;
// Determine scaling, which is the only mapping to be done.
fracstep = dc_iscale;
frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
// This is as fast as it gets.
{
register const UINT8 *source = dc_source;
register const lighttable_t *colormap = dc_colormap;
register INT32 heightmask = dc_texheight-1;
register UINT8 val;
if (dc_texheight & heightmask) // not a power of 2 -- killough
{
heightmask++;
heightmask <<= FRACBITS;
if (frac < 0)
while ((frac += heightmask) < 0);
else
while (frac >= heightmask)
frac -= heightmask;
do
{
// Re-map color indices from wall texture column
// using a lighting/special effects LUT.
// heightmask is the Tutti-Frutti fix
val = source[frac>>FRACBITS];
if (val != TRANSPARENTPIXEL)
*dest = colormap[val];
dest += vid.width;
// Avoid overflow.
if (fracstep > 0x7FFFFFFF - frac)
frac += fracstep - heightmask;
else
frac += fracstep;
while (frac >= heightmask)
frac -= heightmask;
} while (--count);
}
else
{
while ((count -= 2) >= 0) // texture height is a power of 2
{
val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL)
*dest = colormap[val];
dest += vid.width;
frac += fracstep;
val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL)
*dest = colormap[val];
dest += vid.width;
frac += fracstep;
}
if (count & 1)
{
val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL)
*dest = colormap[val];
}
}
}
}
void R_Draw2sMultiPatchTranslucentColumn_8(void)
{
INT32 count;
register UINT8 *dest;
register fixed_t frac;
fixed_t fracstep;
count = dc_yh - dc_yl;
if (count < 0) // Zero length, column does not exceed a pixel.
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
return;
#endif
// Framebuffer destination address.
dest = &topleft[dc_yl*vid.width + dc_x];
count++;
// Determine scaling, which is the only mapping to be done.
fracstep = dc_iscale;
frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
// This is as fast as it gets.
{
register const UINT8 *source = dc_source;
register const UINT8 *transmap = dc_transmap;
register const lighttable_t *colormap = dc_colormap;
register INT32 heightmask = dc_texheight-1;
register UINT8 val;
if (dc_texheight & heightmask) // not a power of 2 -- killough
{
heightmask++;
heightmask <<= FRACBITS;
if (frac < 0)
while ((frac += heightmask) < 0);
else
while (frac >= heightmask)
frac -= heightmask;
do
{
// Re-map color indices from wall texture column
// using a lighting/special effects LUT.
// heightmask is the Tutti-Frutti fix
val = source[frac>>FRACBITS];
if (val != TRANSPARENTPIXEL)
*dest = *(transmap + (colormap[val]<<8) + (*dest));
dest += vid.width;
// Avoid overflow.
if (fracstep > 0x7FFFFFFF - frac)
frac += fracstep - heightmask;
else
frac += fracstep;
while (frac >= heightmask)
frac -= heightmask;
} while (--count);
}
else
{
while ((count -= 2) >= 0) // texture height is a power of 2
{
val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL)
*dest = *(transmap + (colormap[val]<<8) + (*dest));
dest += vid.width;
frac += fracstep;
val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL)
*dest = *(transmap + (colormap[val]<<8) + (*dest));
dest += vid.width;
frac += fracstep;
}
if (count & 1)
{
val = source[(frac>>FRACBITS) & heightmask];
if (val != TRANSPARENTPIXEL)
*dest = *(transmap + (colormap[val]<<8) + (*dest));
}
}
}
}
/** \brief The R_DrawShadeColumn_8 function
Experiment to make software go faster. Taken from the Boom source
*/
......@@ -212,6 +487,90 @@ void R_DrawTranslucentColumn_8(void)
}
}
/** \brief The R_DrawTranslucentColumnClamped_8 function
Same as R_DrawTranslucentColumn_8, but prevents artifacts from showing up (caused by fixed-point imprecisions)
*/
void R_DrawTranslucentColumnClamped_8(void)
{
INT32 count;
UINT8 *dest;
fixed_t frac, fracstep;
count = dc_yh - dc_yl + 1;
if (count <= 0) // Zero length, column does not exceed a pixel.
return;
#ifdef RANGECHECK
if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height)
I_Error("R_DrawTranslucentColumnClamped_8: %d to %d at %d", dc_yl, dc_yh, dc_x);
#endif
dest = &topleft[dc_yl*vid.width + dc_x];
// Looks familiar.
fracstep = dc_iscale;
frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep);
// Inner loop that does the actual texture mapping, e.g. a DDA-like scaling.
// This is as fast as it gets.
{
const UINT8 *source = dc_source;
const UINT8 *transmap = dc_transmap;
const lighttable_t *colormap = dc_colormap;
INT32 heightmask = dc_texheight - 1;
INT32 idx;
if (dc_texheight & heightmask)
{
heightmask++;
heightmask <<= FRACBITS;
if (frac < 0)
while ((frac += heightmask) < 0)
;
else
while (frac >= heightmask)
frac -= heightmask;
do
{
// Re-map color indices from wall texture column
// using a lighting/special effects LUT.
// heightmask is the Tutti-Frutti fix
idx = frac>>FRACBITS;
if (idx >= 0 && idx < dc_postlength)
*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
dest += vid.width;
if ((frac += fracstep) >= heightmask)
frac -= heightmask;
}
while (--count);
}
else
{
while ((count -= 2) >= 0) // texture height is a power of 2
{
idx = (frac>>FRACBITS)&heightmask;
if (idx >= 0 && idx < dc_postlength)
*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
dest += vid.width;
frac += fracstep;
idx = (frac>>FRACBITS)&heightmask;
if (idx >= 0 && idx < dc_postlength)
*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
dest += vid.width;
frac += fracstep;
}
if (count & 1)
{
idx = (frac>>FRACBITS)&heightmask;
if (idx >= 0 && idx < dc_postlength)
*dest = *(transmap + (colormap[source[idx]]<<8) + (*dest));
}
}
}
}
// Hack: A cut-down copy of R_DrawTranslucentColumn_8 that does not read texture
// data since something about calculating the texture reading address for drop shadows is broken.
// dc_texturemid and dc_iscale get wrong values for drop shadows, however those are not strictly
......@@ -942,6 +1301,136 @@ void R_DrawTiltedSplat_8(void)
#endif
}
void R_DrawTiltedTranslucentSplat_8(void)
{
// x1, x2 = ds_x1, ds_x2
int width = ds_x2 - ds_x1;
double iz, uz, vz;
UINT32 u, v;
int i;
UINT8 *source;
UINT8 *colormap;
UINT8 *dest;
UINT8 val;
double startz, startu, startv;
double izstep, uzstep, vzstep;
double endz, endu, endv;
UINT32 stepu, stepv;
iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
R_CalcSlopeLight();
dest = &topleft[ds_y*vid.width + ds_x1];
source = ds_source;
//colormap = ds_colormap;
#if 0 // The "perfect" reference version of this routine. Pretty slow.
// Use it only to see how things are supposed to look.
i = 0;
do
{
double z = 1.f/iz;
u = (INT64)(uz*z);
v = (INT64)(vz*z);
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
dest++;
iz += ds_sz.x;
uz += ds_su.x;
vz += ds_sv.x;
} while (--width >= 0);
#else
startz = 1.f/iz;
startu = uz*startz;
startv = vz*startz;
izstep = ds_sz.x * SPANSIZE;
uzstep = ds_su.x * SPANSIZE;
vzstep = ds_sv.x * SPANSIZE;
//x1 = 0;
width++;
while (width >= SPANSIZE)
{
iz += izstep;
uz += uzstep;
vz += vzstep;
endz = 1.f/iz;
endu = uz*endz;
endv = vz*endz;
stepu = (INT64)((endu - startu) * INVSPAN);
stepv = (INT64)((endv - startv) * INVSPAN);
u = (INT64)(startu);
v = (INT64)(startv);
for (i = SPANSIZE-1; i >= 0; i--)
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
dest++;
u += stepu;
v += stepv;
}
startu = endu;
startv = endv;
width -= SPANSIZE;
}
if (width > 0)
{
if (width == 1)
{
u = (INT64)(startu);
v = (INT64)(startv);
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
}
else
{
double left = width;
iz += ds_sz.x * left;
uz += ds_su.x * left;
vz += ds_sv.x * left;
endz = 1.f/iz;
endu = uz*endz;
endv = vz*endz;
left = 1.f/left;
stepu = (INT64)((endu - startu) * left);
stepv = (INT64)((endv - startv) * left);
u = (INT64)(startu);
v = (INT64)(startv);
for (; width != 0; width--)
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
dest++;
u += stepu;
v += stepv;
}
}
}
#endif
}
/** \brief The R_DrawSplat_8 function
Just like R_DrawSpan_8, but skips transparent pixels.
*/
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -666,6 +666,204 @@ void R_DrawTiltedSplat_NPO2_8(void)
#endif
}
void R_DrawTiltedTranslucentSplat_NPO2_8(void)
{
// x1, x2 = ds_x1, ds_x2
int width = ds_x2 - ds_x1;
double iz, uz, vz;
UINT32 u, v;
int i;
UINT8 *source;
UINT8 *colormap;
UINT8 *dest;
UINT8 val;
double startz, startu, startv;
double izstep, uzstep, vzstep;
double endz, endu, endv;
UINT32 stepu, stepv;
struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth);
struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight);
iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
R_CalcSlopeLight();
dest = &topleft[ds_y*vid.width + ds_x1];
source = ds_source;
//colormap = ds_colormap;
#if 0 // The "perfect" reference version of this routine. Pretty slow.
// Use it only to see how things are supposed to look.
i = 0;
do
{
double z = 1.f/iz;
u = (INT64)(uz*z);
v = (INT64)(vz*z);
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
// Lactozilla: Non-powers-of-two
{
fixed_t x = (((fixed_t)u) >> FRACBITS);
fixed_t y = (((fixed_t)v) >> FRACBITS);
// Carefully align all of my Friends.
if (x < 0)
x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth;
else
x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth;
if (y < 0)
y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight;
else
y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight;
val = source[((y * ds_flatwidth) + x)];
}
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
dest++;
iz += ds_sz.x;
uz += ds_su.x;
vz += ds_sv.x;
} while (--width >= 0);
#else
startz = 1.f/iz;
startu = uz*startz;
startv = vz*startz;
izstep = ds_sz.x * SPANSIZE;
uzstep = ds_su.x * SPANSIZE;
vzstep = ds_sv.x * SPANSIZE;
//x1 = 0;
width++;
while (width >= SPANSIZE)
{
iz += izstep;
uz += uzstep;
vz += vzstep;
endz = 1.f/iz;
endu = uz*endz;
endv = vz*endz;
stepu = (INT64)((endu - startu) * INVSPAN);
stepv = (INT64)((endv - startv) * INVSPAN);
u = (INT64)(startu);
v = (INT64)(startv);
for (i = SPANSIZE-1; i >= 0; i--)
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
// Lactozilla: Non-powers-of-two
{
fixed_t x = (((fixed_t)u) >> FRACBITS);
fixed_t y = (((fixed_t)v) >> FRACBITS);
// Carefully align all of my Friends.
if (x < 0)
x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth;
else
x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth;
if (y < 0)
y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight;
else
y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight;
val = source[((y * ds_flatwidth) + x)];
}
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
dest++;
u += stepu;
v += stepv;
}
startu = endu;
startv = endv;
width -= SPANSIZE;
}
if (width > 0)
{
if (width == 1)
{
u = (INT64)(startu);
v = (INT64)(startv);
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
// Lactozilla: Non-powers-of-two
{
fixed_t x = (((fixed_t)u) >> FRACBITS);
fixed_t y = (((fixed_t)v) >> FRACBITS);
// Carefully align all of my Friends.
if (x < 0)
x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth;
else
x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth;
if (y < 0)
y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight;
else
y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight;
val = source[((y * ds_flatwidth) + x)];
}
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
}
else
{
double left = width;
iz += ds_sz.x * left;
uz += ds_su.x * left;
vz += ds_sv.x * left;
endz = 1.f/iz;
endu = uz*endz;
endv = vz*endz;
left = 1.f/left;
stepu = (INT64)((endu - startu) * left);
stepv = (INT64)((endv - startv) * left);
u = (INT64)(startu);
v = (INT64)(startv);
for (; width != 0; width--)
{
colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
// Lactozilla: Non-powers-of-two
{
fixed_t x = (((fixed_t)u) >> FRACBITS);
fixed_t y = (((fixed_t)v) >> FRACBITS);
// Carefully align all of my Friends.
if (x < 0)
x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth;
else
x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth;
if (y < 0)
y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight;
else
y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight;
val = source[((y * ds_flatwidth) + x)];
}
if (val != TRANSPARENTPIXEL)
*dest = *(ds_transmap + (colormap[val] << 8) + *dest);
dest++;
u += stepu;
v += stepv;
}
}
}
#endif
}
/** \brief The R_DrawSplat_NPO2_8 function
Just like R_DrawSpan_NPO2_8, but skips transparent pixels.
*/
......
......@@ -3,7 +3,7 @@
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2000 by Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko (prboom)
// Copyright (C) 1999-2019 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -120,6 +120,19 @@ static vector3_t *R_LerpVector3(const vector3_t *from, const vector3_t *to, fixe
return out;
}
static double R_LerpDouble(double from, double to, double frac)
{
return from + (frac * (to - from));
}
static dvector3_t *R_LerpDVector3(const dvector3_t *from, const dvector3_t *to, double frac, dvector3_t *out)
{
DVector3_Subtract(to, from, out);
DVector3_Multiply(out, frac, out);
DVector3_Add(from, out, out);
return out;
}
// recalc necessary stuff for mouseaiming
// slopes are already calculated for the full possible view (which is 4*viewheight).
// 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out)
......@@ -497,6 +510,14 @@ void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope)
FV2_Copy(&interp->dynslope.bakd, &slope->d);
interp->dynslope.oldzdelta = interp->dynslope.bakzdelta = slope->zdelta;
DVector3_Copy(&interp->dynslope.oldorigin, &slope->dorigin);
DVector3_Copy(&interp->dynslope.bakorigin, &slope->dorigin);
DVector3_Copy(&interp->dynslope.oldnormdir, &slope->dnormdir);
DVector3_Copy(&interp->dynslope.baknormdir, &slope->dnormdir);
interp->dynslope.olddzdelta = interp->dynslope.bakdzdelta = slope->dzdelta;
}
void R_InitializeLevelInterpolators(void)
......@@ -561,6 +582,21 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
FV3_Copy(&interp->dynslope.bako, &interp->dynslope.slope->o);
FV2_Copy(&interp->dynslope.bakd, &interp->dynslope.slope->d);
interp->dynslope.bakzdelta = interp->dynslope.slope->zdelta;
DVector3_Copy(&interp->dynslope.oldorigin, &interp->dynslope.bakorigin);
DVector3_Copy(&interp->dynslope.oldnormdir, &interp->dynslope.baknormdir);
interp->dynslope.olddzdelta = interp->dynslope.bakdzdelta;
if (interp->dynslope.slope->moved)
{
P_CalculateSlopeVectors(interp->dynslope.slope);
interp->dynslope.slope->moved = false;
}
DVector3_Copy(&interp->dynslope.bakorigin, &interp->dynslope.slope->dorigin);
DVector3_Copy(&interp->dynslope.baknormdir, &interp->dynslope.slope->dnormdir);
interp->dynslope.bakdzdelta = interp->dynslope.slope->dzdelta;
break;
}
}
......@@ -646,7 +682,13 @@ void R_ApplyLevelInterpolators(fixed_t frac)
R_LerpVector3(&interp->dynslope.oldo, &interp->dynslope.bako, frac, &interp->dynslope.slope->o);
R_LerpVector2(&interp->dynslope.oldd, &interp->dynslope.bakd, frac, &interp->dynslope.slope->d);
interp->dynslope.slope->zdelta = R_LerpFixed(interp->dynslope.oldzdelta, interp->dynslope.bakzdelta, frac);
interp->dynslope.slope->moved = true;
if (rendermode == render_soft)
{
double dfrac = FixedToDouble(frac);
R_LerpDVector3(&interp->dynslope.oldorigin, &interp->dynslope.bakorigin, dfrac, &interp->dynslope.slope->dorigin);
R_LerpDVector3(&interp->dynslope.oldnormdir, &interp->dynslope.baknormdir, dfrac, &interp->dynslope.slope->dnormdir);
interp->dynslope.slope->dzdelta = R_LerpDouble(interp->dynslope.olddzdelta, interp->dynslope.bakdzdelta, dfrac);
}
break;
}
}
......@@ -704,6 +746,10 @@ void R_RestoreLevelInterpolators(void)
FV3_Copy(&interp->dynslope.slope->o, &interp->dynslope.bako);
FV2_Copy(&interp->dynslope.slope->d, &interp->dynslope.bakd);
interp->dynslope.slope->zdelta = interp->dynslope.bakzdelta;
DVector3_Copy(&interp->dynslope.slope->dorigin, &interp->dynslope.bakorigin);
DVector3_Copy(&interp->dynslope.slope->dnormdir, &interp->dynslope.baknormdir);
interp->dynslope.slope->dzdelta = interp->dynslope.bakdzdelta;
break;
}
}
......
......@@ -3,7 +3,7 @@
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2000 by Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko (prboom)
// Copyright (C) 1999-2019 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -115,6 +115,9 @@ typedef struct levelinterpolator_s {
vector3_t oldo, bako;
vector2_t oldd, bakd;
fixed_t oldzdelta, bakzdelta;
dvector3_t oldorigin, bakorigin;
dvector3_t oldnormdir, baknormdir;
double olddzdelta, bakdzdelta;
} dynslope;
};
} levelinterpolator_t;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -161,7 +161,7 @@ consvar_t cv_translucency = CVAR_INIT ("translucency", "On", CV_SAVE, CV_OnOff,
consvar_t cv_drawdist = CVAR_INIT ("drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL);
consvar_t cv_drawdist_nights = CVAR_INIT ("drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL);
consvar_t cv_drawdist_precip = CVAR_INIT ("drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL);
consvar_t cv_fov = CVAR_INIT ("fov", "90", CV_SAVE|CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange);
consvar_t cv_fov = CVAR_INIT ("fov", "100", CV_SAVE|CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange);
consvar_t cv_fovchange = CVAR_INIT ("fovchange", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons_t, NULL);
......@@ -390,22 +390,22 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
return R_PointToDist2(viewx, viewy, x, y);
}
line_t *R_GetFFloorLine(const seg_t *seg, const ffloor_t *pfloor)
line_t *R_GetFFloorLine(const line_t *line, const ffloor_t *pfloor, const sector_t *sector)
{
if (pfloor->master->flags & ML_TFERLINE)
{
size_t linenum = seg->linedef - pfloor->target->lines[0];
size_t linenum = min((size_t)(line - sector->lines[0]), pfloor->master->frontsector->linecount);
return pfloor->master->frontsector->lines[0] + linenum;
}
else
return pfloor->master;
}
side_t *R_GetFFloorSide(const seg_t *seg, const ffloor_t *pfloor)
side_t *R_GetFFloorSide(const line_t *line, const ffloor_t *pfloor, const sector_t *sector)
{
if (pfloor->master->flags & ML_TFERLINE)
{
line_t *newline = R_GetFFloorLine(seg, pfloor);
line_t *newline = R_GetFFloorLine(line, pfloor, sector);
return &sides[newline->sidenum[0]];
}
else
......@@ -1095,7 +1095,7 @@ void R_SetupFrame(player_t *player)
camera_t *thiscam;
boolean chasecam = R_ViewpointHasChasecam(player);
boolean ispaused = paused || P_AutoPause();
if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
thiscam = &camera2;
else
......@@ -1152,8 +1152,14 @@ void R_SetupFrame(player_t *player)
if (quake.epicenter) {
// Calculate 3D distance from epicenter, using the camera.
fixed_t xydist = R_PointToDist2(thiscam->x, thiscam->y, quake.epicenter->x, quake.epicenter->y);
fixed_t dist = R_PointToDist2(0, thiscam->z, xydist, quake.epicenter->z);
fixed_t xydist, dist;
if (P_MobjWasRemoved(r_viewmobj)) {
xydist = R_PointToDist2(thiscam->x, thiscam->y, quake.epicenter->x, quake.epicenter->y);
dist = R_PointToDist2(0, thiscam->z, xydist, quake.epicenter->z);
} else {
xydist = R_PointToDist2(r_viewmobj->x, r_viewmobj->y, quake.epicenter->x, quake.epicenter->y);
dist = R_PointToDist2(0, r_viewmobj->z, xydist, quake.epicenter->z);
}
// More effect closer to epicenter, outside of radius = no effect
if (!quake.radius || dist > quake.radius)
......@@ -1369,7 +1375,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
chasecam = true; // force chasecam on
else if (player->spectator) // no spectator chasecam
chasecam = false; // force chasecam off
if (chasecam && !thiscam->chase)
{
P_ResetCamera(player, thiscam);
......@@ -1380,7 +1386,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
P_ResetCamera(player, thiscam);
thiscam->chase = false;
}
if (isplayer2)
{
R_SetViewContext(VIEWCONTEXT_PLAYER2);
......@@ -1428,6 +1434,9 @@ static void R_PortalFrame(portal_t *portal)
viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
if (!P_MobjWasRemoved(portal->viewmobj))
r_viewmobj = portal->viewmobj;
portalclipstart = portal->start;
portalclipend = portal->end;
......
......@@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
// Copyright (C) 1999-2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......@@ -86,8 +86,8 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y);
boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph);
line_t *R_GetFFloorLine(const seg_t *seg, const ffloor_t *pfloor);
side_t *R_GetFFloorSide(const seg_t *seg, const ffloor_t *pfloor);
line_t *R_GetFFloorLine(const line_t *line, const ffloor_t *pfloor, const sector_t *sector);
side_t *R_GetFFloorSide(const line_t *line, const ffloor_t *pfloor, const sector_t *sector);
// Render stats
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos.
// Copyright (C) 2020-2023 by Lactozilla.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
......