mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-02 14:12:47 +00:00
All my work thus far on solving the drawflag/renderflag/additive/subtractive conundrum. Outstandng problems: * Bad additive/subtractive tables means that they appear opaque except under certain conditions. * No support for FOFs, Polyobjects, or linedefs in OpenGL yet. * All OpenGL support mostly done blind, may or may not function in practice. If nothing else, the hard engineering problems are solved and it's just bug hammering...
421 lines
10 KiB
C
421 lines
10 KiB
C
// SONIC ROBO BLAST 2 KART
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2018-2020 by Kart Krew
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file k_race.c
|
|
/// \brief Race Mode specific code.
|
|
|
|
#include "k_race.h"
|
|
|
|
#include "k_kart.h"
|
|
#include "k_battle.h"
|
|
#include "k_pwrlv.h"
|
|
#include "k_color.h"
|
|
#include "k_respawn.h"
|
|
#include "doomdef.h"
|
|
#include "hu_stuff.h"
|
|
#include "g_game.h"
|
|
#include "m_random.h"
|
|
#include "p_local.h"
|
|
#include "p_slopes.h"
|
|
#include "p_setup.h"
|
|
#include "r_draw.h"
|
|
#include "r_local.h"
|
|
#include "s_sound.h"
|
|
#include "st_stuff.h"
|
|
#include "v_video.h"
|
|
#include "z_zone.h"
|
|
#include "m_misc.h"
|
|
#include "m_cond.h"
|
|
#include "f_finale.h"
|
|
#include "lua_hud.h" // For Lua hud checks
|
|
#include "lua_hook.h" // For MobjDamage and ShouldDamage
|
|
#include "m_cheat.h" // objectplacing
|
|
#include "p_spec.h"
|
|
|
|
#include "k_waypoint.h"
|
|
#include "k_bot.h"
|
|
#include "k_hud.h"
|
|
|
|
line_t *finishBeamLine = NULL;
|
|
|
|
static mobj_t *beamPoints[2];
|
|
static UINT8 numBeamPoints = 0;
|
|
|
|
/*--------------------------------------------------
|
|
void K_ClearFinishBeamLine(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_ClearFinishBeamLine(void)
|
|
{
|
|
size_t i;
|
|
|
|
finishBeamLine = NULL;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
beamPoints[i] = NULL;
|
|
}
|
|
|
|
numBeamPoints = 0;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_FreeFinishBeamLine(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
static void K_FreeFinishBeamLine(void)
|
|
{
|
|
if (finishBeamLine != NULL)
|
|
{
|
|
if (finishBeamLine->v1 != NULL)
|
|
{
|
|
Z_Free(finishBeamLine->v1);
|
|
}
|
|
|
|
if (finishBeamLine->v2 != NULL)
|
|
{
|
|
Z_Free(finishBeamLine->v2);
|
|
}
|
|
|
|
Z_Free(finishBeamLine);
|
|
}
|
|
|
|
K_ClearFinishBeamLine();
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_CreateFinishLineFromPoints(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
static void K_CreateFinishLineFromPoints(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
|
|
{
|
|
I_Assert(finishBeamLine == NULL); // Needs to be NULL
|
|
|
|
finishBeamLine = Z_Calloc(sizeof (*finishBeamLine), PU_LEVEL, NULL);
|
|
|
|
finishBeamLine->v1 = Z_Calloc(sizeof (*finishBeamLine->v1), PU_LEVEL, NULL);
|
|
finishBeamLine->v1->x = x1;
|
|
finishBeamLine->v1->y = y1;
|
|
|
|
finishBeamLine->v2 = Z_Calloc(sizeof (*finishBeamLine->v2), PU_LEVEL, NULL);
|
|
finishBeamLine->v2->x = x2;
|
|
finishBeamLine->v2->y = y2;
|
|
|
|
finishBeamLine->dx = x2 - x1;
|
|
finishBeamLine->dy = y2 - y1;
|
|
|
|
finishBeamLine->flags = 0;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
boolean K_GenerateFinishBeamLine(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
boolean K_GenerateFinishBeamLine(void)
|
|
{
|
|
mapthing_t *mt;
|
|
|
|
INT64 bounds[4];
|
|
angle_t angle;
|
|
|
|
boolean valid = false;
|
|
size_t i;
|
|
|
|
// Ensure everything's freed by this time.
|
|
K_FreeFinishBeamLine();
|
|
|
|
// First: attempt to create from beam point objects
|
|
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
|
|
{
|
|
if (numBeamPoints >= 2)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (mt->type == mobjinfo[MT_BEAMPOINT].doomednum)
|
|
{
|
|
beamPoints[numBeamPoints] = mt->mobj;
|
|
numBeamPoints++;
|
|
}
|
|
}
|
|
|
|
if (numBeamPoints == 2)
|
|
{
|
|
// Found 'em! Really easy to generate a line out of these :)
|
|
|
|
K_CreateFinishLineFromPoints(
|
|
beamPoints[0]->x, beamPoints[0]->y,
|
|
beamPoints[1]->x, beamPoints[1]->y
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
bounds[0] = INT64_MAX; // min x
|
|
bounds[1] = INT64_MIN; // max x
|
|
bounds[2] = INT64_MAX; // min y
|
|
bounds[3] = INT64_MIN; // max y
|
|
|
|
for (i = 0; i < numlines; i++)
|
|
{
|
|
angle_t thisAngle;
|
|
|
|
if (lines[i].special != 2001)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
thisAngle = R_PointToAngle2(0, 0, lines[i].dx, lines[i].dy);
|
|
|
|
bounds[0] = min(bounds[0], min(lines[i].v1->x, lines[i].v2->x)); // min x
|
|
bounds[1] = max(bounds[1], max(lines[i].v1->x, lines[i].v2->x)); // max x
|
|
bounds[2] = min(bounds[2], min(lines[i].v1->y, lines[i].v2->y)); // min y
|
|
bounds[3] = max(bounds[3], max(lines[i].v1->y, lines[i].v2->y)); // max y
|
|
|
|
if (valid == false)
|
|
{
|
|
angle = thisAngle;
|
|
valid = true;
|
|
}
|
|
else if (angle != thisAngle)
|
|
{
|
|
// Do not even attempt to bother with curved finish lines.
|
|
// Will likely just crash.
|
|
valid = false;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (valid == true)
|
|
{
|
|
fixed_t span = P_AproxDistance(bounds[1] - bounds[0], bounds[3] - bounds[2]) / 2;
|
|
|
|
fixed_t cx = (bounds[0] + bounds[1]) / 2;
|
|
fixed_t cy = (bounds[2] + bounds[3]) / 2;
|
|
|
|
fixed_t spanC = FixedMul(span, FINECOSINE(angle >> ANGLETOFINESHIFT));
|
|
fixed_t spanS = FixedMul(span, FINESINE(angle >> ANGLETOFINESHIFT));
|
|
|
|
K_CreateFinishLineFromPoints(
|
|
cx - spanC, cy - spanS,
|
|
cx + spanC, cy + spanS
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *line, boolean reverse)
|
|
|
|
Draws a helix out of rainbow colored orbs along a line, unique for each display player.
|
|
Called twice for the finish line beam effect.
|
|
|
|
Input Arguments:-
|
|
offset - Offset value for positioning. Changed every tick to make it animate.
|
|
aiming - Starting vertical angle value. Changed every tick to make it animate.
|
|
line - Linedef to draw along.
|
|
reverse - Draw in reverse. Call twice with this toggled to make a double helix.
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
|
|
static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *line, boolean reverse)
|
|
{
|
|
const fixed_t linelength = P_AproxDistance(line->dx, line->dy);
|
|
const fixed_t xstep = FixedDiv(line->dx, linelength);
|
|
const fixed_t ystep = FixedDiv(line->dy, linelength);
|
|
|
|
fixed_t linex = line->v1->x;
|
|
fixed_t liney = line->v1->y;
|
|
angle_t lineangle = R_PointToAngle2(0, 0, line->dx, line->dy) + ANGLE_90;
|
|
|
|
UINT8 i;
|
|
|
|
if (line->flags & ML_NOCLIMB)
|
|
{
|
|
// Line is flipped
|
|
lineangle += ANGLE_180;
|
|
}
|
|
|
|
linex += FixedMul(offset, xstep);
|
|
liney += FixedMul(offset, ystep);
|
|
|
|
while (offset < linelength)
|
|
{
|
|
#define COLORCYCLELEN 10
|
|
const UINT8 colorcycle[COLORCYCLELEN] = {
|
|
SKINCOLOR_PERIWINKLE,
|
|
SKINCOLOR_SLATE,
|
|
SKINCOLOR_BLOSSOM,
|
|
SKINCOLOR_RASPBERRY,
|
|
SKINCOLOR_ORANGE,
|
|
SKINCOLOR_YELLOW,
|
|
SKINCOLOR_LIME,
|
|
SKINCOLOR_TURTLE,
|
|
SKINCOLOR_ROBIN,
|
|
SKINCOLOR_JAWZ
|
|
};
|
|
|
|
const UINT8 numframes = 5;
|
|
const angle_t framethreshold = ANGLE_180 / (numframes-1);
|
|
const angle_t frameaim = aiming + (framethreshold / 2);
|
|
|
|
fixed_t x, y, z;
|
|
UINT8 spriteframe = 0;
|
|
|
|
x = linex + FixedMul(FixedMul(FINISHLINEBEAM_SPACING, FINECOSINE(lineangle >> ANGLETOFINESHIFT)), FINECOSINE(aiming >> ANGLETOFINESHIFT));
|
|
y = liney + FixedMul(FixedMul(FINISHLINEBEAM_SPACING, FINESINE(lineangle >> ANGLETOFINESHIFT)), FINECOSINE(aiming >> ANGLETOFINESHIFT));
|
|
z = FINISHLINEBEAM_SPACING + FixedMul(FINISHLINEBEAM_SPACING, FINESINE(aiming >> ANGLETOFINESHIFT));
|
|
|
|
if (leveltime >= starttime)
|
|
{
|
|
spriteframe = 4; // Weakest sprite when passable
|
|
}
|
|
else if (frameaim > ANGLE_180)
|
|
{
|
|
spriteframe = (ANGLE_MAX - frameaim) / framethreshold;
|
|
}
|
|
else
|
|
{
|
|
spriteframe = frameaim / framethreshold;
|
|
}
|
|
|
|
for (i = 0; i <= r_splitscreen; i++)
|
|
{
|
|
if (playeringame[displayplayers[i]] && players[displayplayers[i]].mo && !P_MobjWasRemoved(players[displayplayers[i]].mo))
|
|
{
|
|
mobj_t *beam;
|
|
|
|
beam = P_SpawnMobj(x, y, players[displayplayers[i]].mo->z + z, MT_THOK);
|
|
P_SetMobjState(beam, S_FINISHBEAM1 + spriteframe);
|
|
|
|
beam->colorized = true;
|
|
beam->renderflags = RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(&players[displayplayers[i]]);
|
|
|
|
if (reverse)
|
|
{
|
|
beam->color = colorcycle[((leveltime / 4) + (COLORCYCLELEN/2)) % COLORCYCLELEN];
|
|
}
|
|
else
|
|
{
|
|
beam->color = colorcycle[(leveltime / 4) % COLORCYCLELEN];
|
|
}
|
|
}
|
|
}
|
|
|
|
offset += FINISHLINEBEAM_SPACING;
|
|
linex += FixedMul(FINISHLINEBEAM_SPACING, xstep);
|
|
liney += FixedMul(FINISHLINEBEAM_SPACING, ystep);
|
|
|
|
if (reverse)
|
|
{
|
|
aiming -= ANGLE_45;
|
|
}
|
|
else
|
|
{
|
|
aiming += ANGLE_45;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i <= r_splitscreen; i++)
|
|
{
|
|
if (playeringame[displayplayers[i]] && players[displayplayers[i]].mo && !P_MobjWasRemoved(players[displayplayers[i]].mo))
|
|
{
|
|
UINT8 j;
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
vertex_t *v = line->v1;
|
|
mobj_t *end1, *end2;
|
|
angle_t a = R_PointToAngle2(0, 0, line->dx, line->dy);
|
|
fixed_t sx;
|
|
fixed_t sy;
|
|
|
|
/*
|
|
if (line->flags & ML_NOCLIMB)
|
|
{
|
|
a += ANGLE_180;
|
|
}
|
|
*/
|
|
|
|
sx = FixedMul(3*mapobjectscale, FINECOSINE(a >> ANGLETOFINESHIFT));
|
|
sy = FixedMul(3*mapobjectscale, FINESINE(a >> ANGLETOFINESHIFT));
|
|
|
|
if (j == 1)
|
|
{
|
|
v = line->v2;
|
|
sx = -sx;
|
|
sy = -sy;
|
|
}
|
|
|
|
end1 = P_SpawnMobj(
|
|
v->x + sx,
|
|
v->y + sy,
|
|
players[displayplayers[i]].mo->z + FINISHLINEBEAM_SPACING,
|
|
MT_THOK
|
|
);
|
|
|
|
P_SetMobjState(end1, S_FINISHBEAMEND1);
|
|
end1->renderflags = RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(&players[displayplayers[i]]);
|
|
end1->angle = lineangle;
|
|
|
|
end2 = P_SpawnMobj(
|
|
v->x + (8*sx),
|
|
v->y + (8*sy),
|
|
players[displayplayers[i]].mo->z + FINISHLINEBEAM_SPACING,
|
|
MT_THOK
|
|
);
|
|
|
|
P_SetMobjState(end2, S_FINISHBEAMEND2);
|
|
end2->renderflags = RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(&players[displayplayers[i]]);
|
|
end2->angle = lineangle;
|
|
|
|
P_SetTarget(&end2->tracer, end1);
|
|
end2->flags2 |= MF2_LINKDRAW;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_RunFinishLineBeam(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
|
|
void K_RunFinishLineBeam(void)
|
|
{
|
|
if (!(leveltime < starttime || rainbowstartavailable == true))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (finishBeamLine != NULL)
|
|
{
|
|
const angle_t angoffset = ANGLE_45;
|
|
const angle_t angadd = ANGLE_11hh;
|
|
const fixed_t speed = 6 * mapobjectscale;
|
|
|
|
fixed_t offseta = (leveltime * speed) % FINISHLINEBEAM_SPACING;
|
|
angle_t aiminga = (angoffset * -((leveltime * speed) / FINISHLINEBEAM_SPACING)) + (angadd * leveltime);
|
|
|
|
fixed_t offsetb = FINISHLINEBEAM_SPACING - offseta;
|
|
angle_t aimingb = (angoffset * -((leveltime * speed) / FINISHLINEBEAM_SPACING)) - (angadd * leveltime);
|
|
|
|
K_DrawFinishLineBeamForLine(offseta, aiminga, finishBeamLine, false);
|
|
K_DrawFinishLineBeamForLine(offsetb, aimingb, finishBeamLine, true);
|
|
}
|
|
}
|