mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
201 lines
4 KiB
C
201 lines
4 KiB
C
// SONIC ROBO BLAST 2 KART
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2023 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 p_loop.c
|
|
/// \brief Sonic loop physics
|
|
|
|
#include "doomdef.h"
|
|
#include "d_player.h"
|
|
#include "k_kart.h"
|
|
#include "p_local.h"
|
|
#include "p_setup.h"
|
|
#include "p_slopes.h"
|
|
#include "r_main.h"
|
|
|
|
static inline angle_t
|
|
get_pitch (fixed_t revolution)
|
|
{
|
|
return FixedAngle((revolution & FRACMASK) * 360);
|
|
}
|
|
|
|
static inline fixed_t
|
|
normal_revolution (const sonicloopvars_t *s)
|
|
{
|
|
return FixedDiv(
|
|
s->revolution - s->min_revolution,
|
|
s->max_revolution - s->min_revolution);
|
|
}
|
|
|
|
void P_HaltPlayerOrbit(player_t *player)
|
|
{
|
|
// see P_PlayerOrbit
|
|
player->mo->flags &= ~(MF_NOCLIPHEIGHT);
|
|
|
|
player->loop.radius = 0;
|
|
player->loop.camera.exit_tic = leveltime;
|
|
}
|
|
|
|
void P_ExitPlayerOrbit(player_t *player)
|
|
{
|
|
sonicloopvars_t *s = &player->loop;
|
|
|
|
angle_t pitch = get_pitch(s->revolution);
|
|
angle_t yaw = s->yaw;
|
|
|
|
fixed_t co, si;
|
|
fixed_t speed;
|
|
|
|
if (s->radius < 0)
|
|
{
|
|
pitch += ANGLE_180;
|
|
}
|
|
|
|
co = FCOS(pitch);
|
|
si = FSIN(pitch);
|
|
|
|
speed = FixedMul(co, player->speed);
|
|
|
|
P_InstaThrust(player->mo, yaw, speed);
|
|
|
|
player->mo->momz = FixedMul(si, player->speed);
|
|
|
|
if (speed < 0)
|
|
{
|
|
yaw += ANGLE_180;
|
|
}
|
|
|
|
// excludes only extremely vertical angles
|
|
if (abs(co) * 4 > abs(si))
|
|
{
|
|
P_SetPlayerAngle(player, yaw);
|
|
}
|
|
|
|
if (s->flip)
|
|
{
|
|
player->mo->eflags ^= MFE_VERTICALFLIP;
|
|
player->mo->flags2 ^= MF2_OBJECTFLIP;
|
|
|
|
P_SetPitchRoll(player->mo,
|
|
pitch + ANGLE_180, s->yaw);
|
|
}
|
|
|
|
// tiregrease gives less friction, extends momentum
|
|
K_SetTireGrease(player, 3*TICRATE);
|
|
|
|
P_HaltPlayerOrbit(player);
|
|
}
|
|
|
|
boolean P_PlayerOrbit(player_t *player)
|
|
{
|
|
sonicloopvars_t *s = &player->loop;
|
|
|
|
angle_t pitch;
|
|
angle_t pitch_normal;
|
|
|
|
fixed_t r, xy, z;
|
|
fixed_t xs, ys;
|
|
|
|
fixed_t step, th, left;
|
|
|
|
fixed_t grav;
|
|
|
|
if (s->radius == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
grav = abs(P_GetMobjGravity(player->mo));
|
|
|
|
// Lose speed on the way up. revolution = 0.5 always
|
|
// points straight up.
|
|
if (abs(s->revolution & FRACMASK) < FRACUNIT/2)
|
|
{
|
|
player->speed -= grav;
|
|
}
|
|
else
|
|
{
|
|
player->speed += 4 * grav;
|
|
}
|
|
|
|
pitch = get_pitch(s->revolution);
|
|
pitch_normal = get_pitch(normal_revolution(s) / 2);
|
|
|
|
r = abs(s->radius) -
|
|
FixedMul(player->mo->radius, abs(FSIN(pitch)));
|
|
|
|
xy = FixedMul(r, FSIN(pitch));
|
|
|
|
z = FixedMul(abs(s->radius), -(FCOS(pitch))) -
|
|
FixedMul(player->mo->height, FSIN(pitch / 2));
|
|
|
|
// XY shift is transformed on wave scale; less movement
|
|
// at start and end of rotation, more halfway.
|
|
th = FSIN(pitch_normal - ANGLE_90);
|
|
|
|
xs = FixedMul(s->shift.x, th);
|
|
ys = FixedMul(s->shift.y, th);
|
|
|
|
// Interpolate 0-1 over entire rotation.
|
|
th = FSIN(pitch_normal / 2);
|
|
|
|
xs += FixedMul(s->origin_shift.x, th);
|
|
ys += FixedMul(s->origin_shift.y, th);
|
|
|
|
xs += FixedMul(xy, FCOS(s->yaw));
|
|
ys += FixedMul(xy, FSIN(s->yaw));
|
|
|
|
P_MoveOrigin(player->mo,
|
|
s->origin.x + xs,
|
|
s->origin.y + ys,
|
|
s->origin.z + z);
|
|
|
|
// Match rollangle to revolution
|
|
P_SetPitchRoll(player->mo,
|
|
s->radius < 0 ? (ANGLE_180 + pitch) : pitch,
|
|
s->yaw);
|
|
|
|
// circumfrence = (2r)PI
|
|
step = FixedDiv(player->speed,
|
|
FixedMul(s->radius, M_TAU_FIXED));
|
|
|
|
left = (s->max_revolution - s->revolution);
|
|
|
|
if (left == 0)
|
|
{
|
|
P_ExitPlayerOrbit(player);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (abs(left) < abs(step))
|
|
{
|
|
step = left;
|
|
}
|
|
|
|
// If player slows down by too much, throw them
|
|
// out of the loop and reset them.
|
|
// (markedfordeath will kill the player on their
|
|
// first ground contact!)
|
|
if (player->speed < player->mo->scale)
|
|
{
|
|
P_HaltPlayerOrbit(player);
|
|
player->markedfordeath = true;
|
|
K_PlayPainSound(player->mo, NULL);
|
|
K_StumblePlayer(player);
|
|
|
|
return false;
|
|
}
|
|
|
|
s->revolution += step;
|
|
|
|
// We need to not clip the ground. It sucks but setting
|
|
// this flag is the only way to do that.
|
|
player->mo->flags |= (MF_NOCLIPHEIGHT);
|
|
|
|
return true;
|
|
}
|