mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'battle-fuckers-thursday' into 'master'
Battle Fuckers Thursday Night Funkin' (but it's Monday-Sunday) Closes #941, #950, #928, #951, #953, and #948 See merge request KartKrew/Kart!1863
This commit is contained in:
commit
a4c6b3a077
29 changed files with 913 additions and 209 deletions
|
|
@ -157,6 +157,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
||||||
k_dialogue.cpp
|
k_dialogue.cpp
|
||||||
k_tally.cpp
|
k_tally.cpp
|
||||||
k_bans.cpp
|
k_bans.cpp
|
||||||
|
k_endcam.cpp
|
||||||
music.cpp
|
music.cpp
|
||||||
music_manager.cpp
|
music_manager.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
133
src/archive_wrapper.hpp
Normal file
133
src/archive_wrapper.hpp
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
// DR. ROBOTNIK'S RING RACERS
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2024 by James Robert Roman
|
||||||
|
//
|
||||||
|
// This program is free software distributed under the
|
||||||
|
// terms of the GNU General Public License, version 2.
|
||||||
|
// See the 'LICENSE' file for more details.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef archive_wrapper_hpp
|
||||||
|
#define archive_wrapper_hpp
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "typedef.h"
|
||||||
|
|
||||||
|
#include "cxxutil.hpp"
|
||||||
|
#include "byteptr.h"
|
||||||
|
#include "doomdef.h" // p_saveg.h
|
||||||
|
#include "doomtype.h"
|
||||||
|
#include "m_fixed.h"
|
||||||
|
#include "p_mobj.h" // p_saveg.h
|
||||||
|
#include "p_saveg.h"
|
||||||
|
|
||||||
|
namespace srb2
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ArchiveWrapperBase
|
||||||
|
{
|
||||||
|
explicit ArchiveWrapperBase(savebuffer_t* save) : p_(save->p) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename T, typename U>
|
||||||
|
void read(U& n) = delete;
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
void write(const U& n) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UINT8*& p_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define READ_SPEC(T, arg) \
|
||||||
|
template <> void ArchiveWrapperBase::read<T, T>(T& arg)
|
||||||
|
|
||||||
|
#define WRITE_SPEC(T, arg) \
|
||||||
|
template <> void ArchiveWrapperBase::write<T, T>(const T& arg)
|
||||||
|
|
||||||
|
#define MACRO_PAIR(T) \
|
||||||
|
READ_SPEC(T, n) { n = READ ## T(p_); } \
|
||||||
|
WRITE_SPEC(T, n) { WRITE ## T(p_, n); }
|
||||||
|
|
||||||
|
MACRO_PAIR(UINT8)
|
||||||
|
MACRO_PAIR(SINT8)
|
||||||
|
MACRO_PAIR(UINT16)
|
||||||
|
MACRO_PAIR(INT16)
|
||||||
|
MACRO_PAIR(UINT32)
|
||||||
|
MACRO_PAIR(INT32)
|
||||||
|
|
||||||
|
READ_SPEC(vector2_t, n)
|
||||||
|
{
|
||||||
|
read<fixed_t>(n.x);
|
||||||
|
read<fixed_t>(n.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_SPEC(vector2_t, n)
|
||||||
|
{
|
||||||
|
write<fixed_t>(n.x);
|
||||||
|
write<fixed_t>(n.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
READ_SPEC(vector3_t, n)
|
||||||
|
{
|
||||||
|
read<fixed_t>(n.x);
|
||||||
|
read<fixed_t>(n.y);
|
||||||
|
read<fixed_t>(n.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_SPEC(vector3_t, n)
|
||||||
|
{
|
||||||
|
write<fixed_t>(n.x);
|
||||||
|
write<fixed_t>(n.y);
|
||||||
|
write<fixed_t>(n.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specializations for boolean, so it can stored as char
|
||||||
|
// instead of int.
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void ArchiveWrapperBase::read<bool, boolean>(boolean& n)
|
||||||
|
{
|
||||||
|
SRB2_ASSERT(n == true || n == false);
|
||||||
|
n = READUINT8(p_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void ArchiveWrapperBase::write<bool, boolean>(const boolean& n)
|
||||||
|
{
|
||||||
|
SRB2_ASSERT(n == true || n == false);
|
||||||
|
WRITEUINT8(p_, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef MACRO_PAIR
|
||||||
|
#undef WRITE_SPEC
|
||||||
|
#undef READ_SPEC
|
||||||
|
|
||||||
|
struct ArchiveWrapper : ArchiveWrapperBase
|
||||||
|
{
|
||||||
|
using ArchiveWrapperBase::ArchiveWrapperBase;
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
void operator()(const U& n) { write<T, U>(n); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UnArchiveWrapper : ArchiveWrapperBase
|
||||||
|
{
|
||||||
|
using ArchiveWrapperBase::ArchiveWrapperBase;
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
void operator()(U& n) { read<T, U>(n); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_archive_wrapper : std::is_base_of<ArchiveWrapperBase, T> {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline constexpr bool is_archive_wrapper_v = is_archive_wrapper<T>::value;
|
||||||
|
|
||||||
|
#define SRB2_ARCHIVE_WRAPPER_CALL(ar, T, var) ((ar). template operator()<T>(var))
|
||||||
|
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
#endif/*archive_wrapper_hpp*/
|
||||||
26
src/g_game.c
26
src/g_game.c
|
|
@ -1975,7 +1975,7 @@ void G_Ticker(boolean run)
|
||||||
{
|
{
|
||||||
Music_Play("intermission");
|
Music_Play("intermission");
|
||||||
}
|
}
|
||||||
else if (musiccountdown == MUSIC_COUNTDOWN_MAX - TALLY_TIME)
|
else if (musiccountdown == MUSIC_COUNTDOWN_MAX - K_TallyDelay())
|
||||||
{
|
{
|
||||||
P_EndingMusic();
|
P_EndingMusic();
|
||||||
}
|
}
|
||||||
|
|
@ -2607,22 +2607,12 @@ mapthing_t *G_FindBattleStart(INT32 playernum)
|
||||||
|
|
||||||
if (numdmstarts)
|
if (numdmstarts)
|
||||||
{
|
{
|
||||||
extern consvar_t cv_battlespawn;
|
for (j = 0; j < 64; j++)
|
||||||
if (cv_battlespawn.value)
|
|
||||||
{
|
{
|
||||||
i = cv_battlespawn.value - 1;
|
i = P_RandomKey(PR_PLAYERSTARTS, numdmstarts);
|
||||||
if (i < numdmstarts)
|
if (G_CheckSpot(playernum, deathmatchstarts[i]))
|
||||||
return deathmatchstarts[i];
|
return deathmatchstarts[i];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
for (j = 0; j < 64; j++)
|
|
||||||
{
|
|
||||||
i = P_RandomKey(PR_PLAYERSTARTS, numdmstarts);
|
|
||||||
if (G_CheckSpot(playernum, deathmatchstarts[i]))
|
|
||||||
return deathmatchstarts[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (doprints)
|
if (doprints)
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n"));
|
CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n"));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -2796,14 +2786,20 @@ static inline mapthing_t *G_FindTeamStartOrFallback(INT32 playernum)
|
||||||
|
|
||||||
mapthing_t *G_FindMapStart(INT32 playernum)
|
mapthing_t *G_FindMapStart(INT32 playernum)
|
||||||
{
|
{
|
||||||
|
extern consvar_t cv_battlespawn;
|
||||||
mapthing_t *spawnpoint;
|
mapthing_t *spawnpoint;
|
||||||
|
|
||||||
if (!playeringame[playernum])
|
if (!playeringame[playernum])
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
// -- battlespawn cheat --
|
||||||
|
// Everyone spawns at the same spot
|
||||||
|
if ((gametyperules & GTR_BATTLESTARTS) && cv_battlespawn.value > 0 && cv_battlespawn.value <= numdmstarts)
|
||||||
|
spawnpoint = deathmatchstarts[cv_battlespawn.value - 1];
|
||||||
|
|
||||||
// -- Podium --
|
// -- Podium --
|
||||||
// Single special behavior
|
// Single special behavior
|
||||||
if (K_PodiumSequence() == true)
|
else if (K_PodiumSequence() == true)
|
||||||
spawnpoint = G_FindPodiumStart(playernum);
|
spawnpoint = G_FindPodiumStart(playernum);
|
||||||
|
|
||||||
// -- Time Attack / Battle duels --
|
// -- Time Attack / Battle duels --
|
||||||
|
|
|
||||||
|
|
@ -327,6 +327,9 @@ void HU_Init(void)
|
||||||
PR ("TMFNT");
|
PR ("TMFNT");
|
||||||
REG;
|
REG;
|
||||||
|
|
||||||
|
PR ("TMFNS");
|
||||||
|
REG;
|
||||||
|
|
||||||
ADIM (LT);
|
ADIM (LT);
|
||||||
PR ("GAMEM");
|
PR ("GAMEM");
|
||||||
REG;
|
REG;
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ enum
|
||||||
|
|
||||||
X (KART),
|
X (KART),
|
||||||
X (TIMER),
|
X (TIMER),
|
||||||
|
X (TINYTIMER),
|
||||||
X (GM),
|
X (GM),
|
||||||
X (LSHI),
|
X (LSHI),
|
||||||
X (LSLOW),
|
X (LSLOW),
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,90 @@
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "../v_draw.hpp"
|
#include "../v_draw.hpp"
|
||||||
|
|
||||||
#include "../doomdef.h"
|
#include "../doomdef.h"
|
||||||
#include "../i_time.h"
|
#include "../i_time.h"
|
||||||
|
#include "../k_battle.h"
|
||||||
#include "../k_hud.h"
|
#include "../k_hud.h"
|
||||||
|
#include "../m_easing.h"
|
||||||
|
#include "../m_fixed.h"
|
||||||
|
#include "../p_tick.h"
|
||||||
#include "../screen.h"
|
#include "../screen.h"
|
||||||
|
|
||||||
using srb2::Draw;
|
using srb2::Draw;
|
||||||
|
|
||||||
void K_drawEmeraldWin(void)
|
namespace
|
||||||
{
|
{
|
||||||
constexpr float kScale = 0.25;
|
|
||||||
constexpr int kH = 72 * kScale;
|
|
||||||
constexpr int kYPad = 12;
|
|
||||||
constexpr int kWidth = 34 + 4;
|
|
||||||
|
|
||||||
if (I_GetTime() % 3)
|
fixed_t interval(tic_t t, tic_t s, tic_t d)
|
||||||
|
{
|
||||||
|
return (std::min(std::max(t, s) - s, d) * FRACUNIT) / d;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
void K_drawEmeraldWin(boolean overlay)
|
||||||
|
{
|
||||||
|
if (leveltime < g_emeraldWin)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw row = Draw(BASEVIDWIDTH / 2, BASEVIDHEIGHT / 2).scale(kScale).flags(V_ADD);
|
constexpr float kScale = 0.5;
|
||||||
|
constexpr int kWidth = (69 + 4) * 2 * kScale;
|
||||||
|
constexpr int kMid = (72 * kScale) / 2;
|
||||||
|
constexpr int kYOffset = (68 * kScale) - kMid;
|
||||||
|
|
||||||
|
constexpr int kTop = 86;
|
||||||
|
constexpr int kBot = 129;
|
||||||
|
|
||||||
|
constexpr tic_t kDelay = 24;
|
||||||
|
constexpr tic_t kSlide = 12;
|
||||||
|
|
||||||
|
constexpr tic_t kFlashStart = (6 * kDelay) + kSlide;
|
||||||
|
constexpr tic_t kFlash = 10;
|
||||||
|
|
||||||
|
INT32 flags = 0;
|
||||||
|
|
||||||
|
tic_t t = leveltime - g_emeraldWin;
|
||||||
|
|
||||||
|
if (overlay)
|
||||||
|
{
|
||||||
|
if (t >= kFlashStart && t - kFlashStart <= kFlash)
|
||||||
|
{
|
||||||
|
flags = V_ADD | (Easing_InOutSine(interval(t, kFlashStart, kFlash), 0, 9) << V_ALPHASHIFT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags = (I_GetTime() & 1) ? V_ADD : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_t* emer = Draw::cache_patch("EMRCA0");
|
||||||
|
Draw row = Draw(BASEVIDWIDTH / 2, kYOffset).scale(kScale).flags(flags);
|
||||||
//Draw(0, row.y()).size(BASEVIDWIDTH, 1).fill(35);
|
//Draw(0, row.y()).size(BASEVIDWIDTH, 1).fill(35);
|
||||||
|
|
||||||
Draw top = row.y(-kYPad);
|
Draw top = row.y(kTop);
|
||||||
Draw bot = row.xy(-kWidth / 2, kH + kYPad);
|
Draw bot = row.xy(-kWidth / 2, kBot);
|
||||||
|
|
||||||
auto put = [](Draw& row, int x, int n)
|
auto put = [&](Draw& row, int offscreen, int x, int n)
|
||||||
{
|
{
|
||||||
row.x(x * kWidth).colormap(static_cast<skincolornum_t>(SKINCOLOR_CHAOSEMERALD1 + n)).patch("EMRCA0");
|
row
|
||||||
|
.xy(x * kWidth, Easing_OutSine(interval(t, kDelay * n, kSlide), offscreen, 0))
|
||||||
|
.colormap(static_cast<skincolornum_t>(SKINCOLOR_CHAOSEMERALD1 + n))
|
||||||
|
.patch(emer);
|
||||||
};
|
};
|
||||||
|
|
||||||
put(top, -1, 3);
|
put(top, -kTop - kMid, -1, 3);
|
||||||
put(top, 0, 0);
|
put(top, -kTop - kMid, 0, 0);
|
||||||
put(top, 1, 4);
|
put(top, -kTop - kMid, 1, 4);
|
||||||
|
|
||||||
put(bot, -1, 5);
|
put(bot, 200 - kBot + kMid, -1, 5);
|
||||||
put(bot, 0, 1);
|
put(bot, 200 - kBot + kMid, 0, 1);
|
||||||
put(bot, 1, 2);
|
put(bot, 200 - kBot + kMid, 1, 2);
|
||||||
put(bot, 2, 6);
|
put(bot, 200 - kBot + kMid, 2, 6);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "hu_stuff.h"
|
#include "hu_stuff.h"
|
||||||
#include "m_easing.h"
|
#include "m_easing.h"
|
||||||
|
#include "k_endcam.h"
|
||||||
|
#include "p_tick.h"
|
||||||
|
|
||||||
#define BARRIER_MIN_RADIUS (768 * mapobjectscale)
|
#define BARRIER_MIN_RADIUS (768 * mapobjectscale)
|
||||||
|
|
||||||
|
|
@ -43,7 +45,7 @@ UINT8 maptargets = 0; // Capsules in map
|
||||||
UINT8 numtargets = 0; // Capsules busted
|
UINT8 numtargets = 0; // Capsules busted
|
||||||
|
|
||||||
// Battle: someone won by collecting all 7 Chaos Emeralds
|
// Battle: someone won by collecting all 7 Chaos Emeralds
|
||||||
boolean g_emeraldWin = false;
|
tic_t g_emeraldWin = 0;
|
||||||
|
|
||||||
INT32 K_StartingBumperCount(void)
|
INT32 K_StartingBumperCount(void)
|
||||||
{
|
{
|
||||||
|
|
@ -207,10 +209,32 @@ void K_CheckEmeralds(player_t *player)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (player->exiting)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
player->roundscore = 100; // lmao
|
player->roundscore = 100; // lmao
|
||||||
|
|
||||||
P_DoAllPlayersExit(0, false);
|
P_DoAllPlayersExit(0, false);
|
||||||
g_emeraldWin = true;
|
|
||||||
|
// TODO: this would be better if the timing lived in
|
||||||
|
// Tally code. But I didn't do it that, so this just
|
||||||
|
// shittily approximates syncing up with Tally.
|
||||||
|
g_emeraldWin = leveltime + (3*TICRATE);
|
||||||
|
|
||||||
|
if (!P_MobjWasRemoved(player->mo))
|
||||||
|
{
|
||||||
|
K_StartRoundWinCamera(
|
||||||
|
player->mo,
|
||||||
|
player->angleturn + ANGLE_180,
|
||||||
|
400*mapobjectscale,
|
||||||
|
6*TICRATE,
|
||||||
|
FRACUNIT/16
|
||||||
|
);
|
||||||
|
|
||||||
|
g_emeraldWin += g_endcam.swirlDuration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT16 K_GetChaosEmeraldColor(UINT32 emeraldType)
|
UINT16 K_GetChaosEmeraldColor(UINT32 emeraldType)
|
||||||
|
|
@ -540,7 +564,11 @@ void K_RunPaperItemSpawners(void)
|
||||||
|
|
||||||
//CONS_Printf("leveltime = %d ", leveltime);
|
//CONS_Printf("leveltime = %d ", leveltime);
|
||||||
|
|
||||||
if (spotAvailable > 0 && monitorsSpawned < BATTLE_MONITOR_SPAWN_LIMIT)
|
// Duel = 2 + 1 = 3 / 2 = 1
|
||||||
|
// Small = 5 + 1 = 6 / 2 = 3
|
||||||
|
// Medium = 10 + 1 = 11 / 2 = 5
|
||||||
|
// Large = 16 + 1 = 17 / 2 = 8
|
||||||
|
if (spotAvailable > 0 && monitorsSpawned < (mapheaderinfo[gamemap - 1]->playerLimit + 1) / 2)
|
||||||
{
|
{
|
||||||
const UINT8 r = spotMap[P_RandomKey(PR_ITEM_ROULETTE, spotAvailable)];
|
const UINT8 r = spotMap[P_RandomKey(PR_ITEM_ROULETTE, spotAvailable)];
|
||||||
|
|
||||||
|
|
@ -700,6 +728,36 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void K_SpawnOvertimeBarrier(void)
|
||||||
|
{
|
||||||
|
if (battleovertime.radius <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const INT32 orbs = 32;
|
||||||
|
const angle_t angoff = ANGLE_MAX / orbs;
|
||||||
|
const UINT8 spriteSpacing = 128;
|
||||||
|
|
||||||
|
fixed_t circumference = FixedMul(M_PI_FIXED, battleovertime.radius * 2);
|
||||||
|
fixed_t scale = max(circumference / spriteSpacing / orbs, mapobjectscale);
|
||||||
|
|
||||||
|
fixed_t size = FixedMul(mobjinfo[MT_OVERTIME_PARTICLE].radius, scale);
|
||||||
|
fixed_t posOffset = max(battleovertime.radius - size, 0);
|
||||||
|
|
||||||
|
INT32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < orbs; i++)
|
||||||
|
{
|
||||||
|
angle_t ang = (i * angoff) + FixedAngle((leveltime * FRACUNIT) / 4);
|
||||||
|
|
||||||
|
fixed_t x = battleovertime.x + P_ReturnThrustX(NULL, ang, posOffset);
|
||||||
|
fixed_t y = battleovertime.y + P_ReturnThrustY(NULL, ang, posOffset);
|
||||||
|
|
||||||
|
K_SpawnOvertimeLaser(x, y, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void K_RunBattleOvertime(void)
|
void K_RunBattleOvertime(void)
|
||||||
{
|
{
|
||||||
if (battleovertime.enabled < 10*TICRATE)
|
if (battleovertime.enabled < 10*TICRATE)
|
||||||
|
|
@ -757,29 +815,9 @@ void K_RunBattleOvertime(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (battleovertime.radius > 0)
|
if (!P_LevelIsFrozen())
|
||||||
{
|
{
|
||||||
const INT32 orbs = 32;
|
K_SpawnOvertimeBarrier();
|
||||||
const angle_t angoff = ANGLE_MAX / orbs;
|
|
||||||
const UINT8 spriteSpacing = 128;
|
|
||||||
|
|
||||||
fixed_t circumference = FixedMul(M_PI_FIXED, battleovertime.radius * 2);
|
|
||||||
fixed_t scale = max(circumference / spriteSpacing / orbs, mapobjectscale);
|
|
||||||
|
|
||||||
fixed_t size = FixedMul(mobjinfo[MT_OVERTIME_PARTICLE].radius, scale);
|
|
||||||
fixed_t posOffset = max(battleovertime.radius - size, 0);
|
|
||||||
|
|
||||||
INT32 i;
|
|
||||||
|
|
||||||
for (i = 0; i < orbs; i++)
|
|
||||||
{
|
|
||||||
angle_t ang = (i * angoff) + FixedAngle((leveltime * FRACUNIT) / 4);
|
|
||||||
|
|
||||||
fixed_t x = battleovertime.x + P_ReturnThrustX(NULL, ang, posOffset);
|
|
||||||
fixed_t y = battleovertime.y + P_ReturnThrustY(NULL, ang, posOffset);
|
|
||||||
|
|
||||||
K_SpawnOvertimeLaser(x, y, scale);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -880,7 +918,7 @@ void K_BattleInit(boolean singleplayercontext)
|
||||||
g_battleufo.due = starttime;
|
g_battleufo.due = starttime;
|
||||||
g_battleufo.previousId = Obj_RandomBattleUFOSpawnerID() - 1;
|
g_battleufo.previousId = Obj_RandomBattleUFOSpawnerID() - 1;
|
||||||
|
|
||||||
g_emeraldWin = false;
|
g_emeraldWin = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 K_Bumpers(player_t *player)
|
UINT8 K_Bumpers(player_t *player)
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,6 @@ extern "C" {
|
||||||
#define BATTLE_POWERUP_TIME (30*TICRATE)
|
#define BATTLE_POWERUP_TIME (30*TICRATE)
|
||||||
#define BATTLE_UFO_TIME (20*TICRATE)
|
#define BATTLE_UFO_TIME (20*TICRATE)
|
||||||
|
|
||||||
#define BATTLE_MONITOR_SPAWN_LIMIT (3)
|
|
||||||
|
|
||||||
extern struct battleovertime
|
extern struct battleovertime
|
||||||
{
|
{
|
||||||
UINT16 enabled; ///< Has this been initalized yet?
|
UINT16 enabled; ///< Has this been initalized yet?
|
||||||
|
|
@ -33,7 +31,7 @@ extern struct battleufo
|
||||||
extern boolean battleprisons;
|
extern boolean battleprisons;
|
||||||
extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items
|
extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items
|
||||||
extern UINT8 maptargets, numtargets;
|
extern UINT8 maptargets, numtargets;
|
||||||
extern boolean g_emeraldWin;
|
extern tic_t g_emeraldWin;
|
||||||
|
|
||||||
INT32 K_StartingBumperCount(void);
|
INT32 K_StartingBumperCount(void);
|
||||||
boolean K_IsPlayerWanted(player_t *player);
|
boolean K_IsPlayerWanted(player_t *player);
|
||||||
|
|
@ -47,6 +45,7 @@ mobj_t *K_SpawnSphereBox(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 f
|
||||||
void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType);
|
void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType);
|
||||||
UINT8 K_NumEmeralds(player_t *player);
|
UINT8 K_NumEmeralds(player_t *player);
|
||||||
void K_RunPaperItemSpawners(void);
|
void K_RunPaperItemSpawners(void);
|
||||||
|
void K_SpawnOvertimeBarrier(void);
|
||||||
void K_RunBattleOvertime(void);
|
void K_RunBattleOvertime(void);
|
||||||
void K_SetupMovingCapsule(mapthing_t *mt, mobj_t *mobj);
|
void K_SetupMovingCapsule(mapthing_t *mt, mobj_t *mobj);
|
||||||
void K_SpawnPlayerBattleBumpers(player_t *p);
|
void K_SpawnPlayerBattleBumpers(player_t *p);
|
||||||
|
|
|
||||||
|
|
@ -744,6 +744,49 @@ void K_LightningShieldAttack(mobj_t *actor, fixed_t size)
|
||||||
P_BlockThingsIterator(bx, by, PIT_LightningShieldAttack);
|
P_BlockThingsIterator(bx, by, PIT_LightningShieldAttack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean K_BubbleShieldCanReflect(mobj_t *t1, mobj_t *t2)
|
||||||
|
{
|
||||||
|
return (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_GACHABOM
|
||||||
|
|| t2->type == MT_BANANA || t2->type == MT_EGGMANITEM || t2->type == MT_BALLHOG
|
||||||
|
|| t2->type == MT_SSMINE || t2->type == MT_LANDMINE || t2->type == MT_SINK
|
||||||
|
|| t2->type == MT_GARDENTOP
|
||||||
|
|| t2->type == MT_DROPTARGET
|
||||||
|
|| t2->type == MT_KART_LEFTOVER
|
||||||
|
|| (t2->type == MT_PLAYER && t1->target != t2));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2)
|
||||||
|
{
|
||||||
|
mobj_t *owner = t1->player ? t1 : t1->target;
|
||||||
|
|
||||||
|
if (t2->target != owner || !t2->threshold || t2->type == MT_DROPTARGET)
|
||||||
|
{
|
||||||
|
if (t1->player && K_PlayerGuard(t1->player))
|
||||||
|
{
|
||||||
|
K_KartSolidBounce(t1, t2);
|
||||||
|
K_DoPowerClash(t1, t2);
|
||||||
|
}
|
||||||
|
if (!t2->momx && !t2->momy)
|
||||||
|
{
|
||||||
|
t2->momz += (24*t2->scale) * P_MobjFlip(t2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t2->momx = -6*t2->momx;
|
||||||
|
t2->momy = -6*t2->momy;
|
||||||
|
t2->momz = -6*t2->momz;
|
||||||
|
t2->angle += ANGLE_180;
|
||||||
|
}
|
||||||
|
if (t2->type == MT_JAWZ)
|
||||||
|
P_SetTarget(&t2->tracer, t2->target); // Back to the source!
|
||||||
|
P_SetTarget(&t2->target, owner); // Let the source reflect it back again!
|
||||||
|
t2->threshold = 10;
|
||||||
|
S_StartSound(t1, sfx_s3k44);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
||||||
{
|
{
|
||||||
if (t2->type == MT_PLAYER)
|
if (t2->type == MT_PLAYER)
|
||||||
|
|
@ -767,38 +810,20 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
||||||
// Don't play from t1 else it gets cut out... for some reason.
|
// Don't play from t1 else it gets cut out... for some reason.
|
||||||
S_StartSound(t2, sfx_s3k44);
|
S_StartSound(t2, sfx_s3k44);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (K_BubbleShieldCanReflect(t1, t2))
|
||||||
{
|
{
|
||||||
mobj_t *owner = t1->player ? t1 : t1->target;
|
return K_BubbleShieldReflect(t1, t2);
|
||||||
|
}
|
||||||
if (t2->target != owner || !t2->threshold || t2->type == MT_DROPTARGET)
|
|
||||||
{
|
if (t2->flags & MF_SHOOTABLE)
|
||||||
if (t1->player && K_PlayerGuard(t1->player))
|
{
|
||||||
{
|
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
|
||||||
K_KartSolidBounce(t1, t2);
|
|
||||||
K_DoPowerClash(t1, t2);
|
|
||||||
}
|
|
||||||
if (!t2->momx && !t2->momy)
|
|
||||||
{
|
|
||||||
t2->momz += (24*t2->scale) * P_MobjFlip(t2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t2->momx = -6*t2->momx;
|
|
||||||
t2->momy = -6*t2->momy;
|
|
||||||
t2->momz = -6*t2->momz;
|
|
||||||
t2->angle += ANGLE_180;
|
|
||||||
}
|
|
||||||
if (t2->type == MT_JAWZ)
|
|
||||||
P_SetTarget(&t2->tracer, t2->target); // Back to the source!
|
|
||||||
P_SetTarget(&t2->target, owner); // Let the source reflect it back again!
|
|
||||||
t2->threshold = 10;
|
|
||||||
S_StartSound(t1, sfx_s3k44);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no interaction
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -838,8 +863,8 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
||||||
attacker->renderflags &= ~RF_DONTDRAW;
|
attacker->renderflags &= ~RF_DONTDRAW;
|
||||||
|
|
||||||
angle_t thrangle = R_PointToAngle2(attacker->x, attacker->y, victim->x, victim->y);
|
angle_t thrangle = R_PointToAngle2(attacker->x, attacker->y, victim->x, victim->y);
|
||||||
P_Thrust(victim, thrangle, FRACUNIT*7);
|
P_Thrust(victim, thrangle, mapobjectscale*28);
|
||||||
P_Thrust(attacker, ANGLE_180 + thrangle, FRACUNIT*7);
|
P_Thrust(attacker, ANGLE_180 + thrangle, mapobjectscale*28);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -907,7 +932,7 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
||||||
K_DropPowerUps(victimPlayer);
|
K_DropPowerUps(victimPlayer);
|
||||||
|
|
||||||
angle_t thrangle = ANGLE_180 + R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
|
angle_t thrangle = ANGLE_180 + R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
|
||||||
P_Thrust(victim, thrangle, FRACUNIT*10);
|
P_Thrust(victim, thrangle, mapobjectscale*40);
|
||||||
|
|
||||||
K_AddHitLag(victim, victimHitlag, true);
|
K_AddHitLag(victim, victimHitlag, true);
|
||||||
K_AddHitLag(attacker, attackerHitlag, false);
|
K_AddHitLag(attacker, attackerHitlag, false);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2);
|
||||||
boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2);
|
boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2);
|
||||||
|
|
||||||
void K_LightningShieldAttack(mobj_t *actor, fixed_t size);
|
void K_LightningShieldAttack(mobj_t *actor, fixed_t size);
|
||||||
|
|
||||||
|
boolean K_BubbleShieldCanReflect(mobj_t *t1, mobj_t *t2);
|
||||||
|
boolean K_BubbleShieldReflect(mobj_t *t1, mobj_t *t2);
|
||||||
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
|
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
|
||||||
|
|
||||||
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim);
|
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim);
|
||||||
|
|
|
||||||
225
src/k_endcam.cpp
Normal file
225
src/k_endcam.cpp
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
// DR. ROBOTNIK'S RING RACERS
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2024 by James Robert Roman
|
||||||
|
//
|
||||||
|
// This program is free software distributed under the
|
||||||
|
// terms of the GNU General Public License, version 2.
|
||||||
|
// See the 'LICENSE' file for more details.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "archive_wrapper.hpp"
|
||||||
|
|
||||||
|
#include "byteptr.h"
|
||||||
|
#include "doomdef.h"
|
||||||
|
#include "doomstat.h"
|
||||||
|
#include "doomtype.h"
|
||||||
|
#include "g_game.h"
|
||||||
|
#include "k_battle.h"
|
||||||
|
#include "k_endcam.h"
|
||||||
|
#include "m_easing.h"
|
||||||
|
#include "p_local.h"
|
||||||
|
#include "p_mobj.h"
|
||||||
|
#include "p_saveg.h"
|
||||||
|
#include "p_tick.h"
|
||||||
|
#include "r_fps.h"
|
||||||
|
#include "r_main.h"
|
||||||
|
|
||||||
|
endcam_t g_endcam;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
fixed_t interval(tic_t t, tic_t d)
|
||||||
|
{
|
||||||
|
return (std::min(t, d) * FRACUNIT) / std::max(d, 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed_t interval(tic_t t, tic_t s, tic_t d)
|
||||||
|
{
|
||||||
|
return interval(std::max(t, s) - s, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 lerp(fixed_t f, INT32 a, INT32 b)
|
||||||
|
{
|
||||||
|
return a + FixedMul(f, b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Camera : camera_t
|
||||||
|
{
|
||||||
|
void pos(const vector3_t& p)
|
||||||
|
{
|
||||||
|
x = p.x;
|
||||||
|
y = p.y;
|
||||||
|
z = p.z;
|
||||||
|
subsector = R_PointInSubsector(x, y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EndCam : endcam_t
|
||||||
|
{
|
||||||
|
tic_t Time() const { return leveltime - begin; }
|
||||||
|
bool Freezing() const { return Time() <= swirlDuration; }
|
||||||
|
|
||||||
|
void GC()
|
||||||
|
{
|
||||||
|
if (P_MobjWasRemoved(panMobj))
|
||||||
|
{
|
||||||
|
P_SetTarget(&panMobj, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
active = true;
|
||||||
|
begin = leveltime;
|
||||||
|
|
||||||
|
// Reset all viewpoints
|
||||||
|
for (int i = 0; i < MAXSPLITSCREENPLAYERS; ++i)
|
||||||
|
{
|
||||||
|
Move(static_cast<Camera&>(camera[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
R_ResetViewInterpolation(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move(Camera& cam)
|
||||||
|
{
|
||||||
|
tic_t t = Time();
|
||||||
|
fixed_t pan = Easing_OutQuint(interval(t, swirlDuration, panDuration), FRACUNIT, 0);
|
||||||
|
|
||||||
|
auto aim = [&](vector3_t& p, vector3_t& q)
|
||||||
|
{
|
||||||
|
cam.aiming = lerp(pan, cam.aiming, R_PointToAngle2(0, p.z, FixedHypot(q.x - p.x, q.y - p.y), q.z));
|
||||||
|
cam.pos(p);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (t <= swirlDuration)
|
||||||
|
{
|
||||||
|
fixed_t swirl = interval(t, swirlDuration);
|
||||||
|
|
||||||
|
angle_t ang = FixedAngle(swirl < FRACUNIT/2 ?
|
||||||
|
Easing_InOutQuint(swirl, startAngle, endAngle) :
|
||||||
|
Easing_InOutQuad(swirl, startAngle, endAngle));
|
||||||
|
|
||||||
|
fixed_t hDist = Easing_OutQuad(swirl, startRadius.x, endRadius.x);
|
||||||
|
|
||||||
|
vector3_t p = {
|
||||||
|
origin.x - FixedMul(FCOS(ang), hDist),
|
||||||
|
origin.y - FixedMul(FSIN(ang), hDist),
|
||||||
|
origin.z + Easing_OutQuad(swirl, startRadius.y, endRadius.y)
|
||||||
|
};
|
||||||
|
|
||||||
|
aim(p, origin);
|
||||||
|
cam.angle = ang;
|
||||||
|
}
|
||||||
|
else if (!P_MobjWasRemoved(panMobj))
|
||||||
|
{
|
||||||
|
vector3_t q = {panMobj->x, panMobj->y, P_GetMobjHead(panMobj)};
|
||||||
|
vector3_t p = {cam.x, cam.y, cam.z};
|
||||||
|
Follow(FixedMul(pan, panSpeed), p, q); // modifies p
|
||||||
|
|
||||||
|
aim(p, q);
|
||||||
|
cam.angle = lerp(
|
||||||
|
Easing_Linear(pan, FRACUNIT/4, FRACUNIT),
|
||||||
|
cam.angle,
|
||||||
|
R_PointToAngle2(p.x, p.y, q.x, q.y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Archive(T&& ar)
|
||||||
|
{
|
||||||
|
static_assert(srb2::is_archive_wrapper_v<T>);
|
||||||
|
#define X(T, var) SRB2_ARCHIVE_WRAPPER_CALL(ar, T, var)
|
||||||
|
X(vector3_t, origin);
|
||||||
|
X(vector2_t, startRadius);
|
||||||
|
X(vector2_t, endRadius);
|
||||||
|
X(tic_t, swirlDuration);
|
||||||
|
X(fixed_t, startAngle);
|
||||||
|
X(fixed_t, endAngle);
|
||||||
|
// panMobj is handled in p_saveg.c
|
||||||
|
X(tic_t, panDuration);
|
||||||
|
X(fixed_t, panSpeed);
|
||||||
|
X(bool, active);
|
||||||
|
X(tic_t, begin);
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Follow(fixed_t f, vector3_t& p, vector3_t q) const
|
||||||
|
{
|
||||||
|
FV3_Sub(&q, &p);
|
||||||
|
q.x = FixedMul(q.x, f);
|
||||||
|
q.y = FixedMul(q.y, f);
|
||||||
|
q.z = FixedMul(q.z, f);
|
||||||
|
|
||||||
|
FV3_Add(&p, &q);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EndCam& endcam_cast()
|
||||||
|
{
|
||||||
|
return static_cast<EndCam&>(g_endcam);
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
void K_CommitEndCamera(void)
|
||||||
|
{
|
||||||
|
// Level will be frozen, so make sure the lasers are
|
||||||
|
// spawned before that happens.
|
||||||
|
K_SpawnOvertimeBarrier();
|
||||||
|
|
||||||
|
endcam_cast().Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_MoveEndCamera(camera_t *thiscam)
|
||||||
|
{
|
||||||
|
endcam_cast().Move(static_cast<Camera&>(*thiscam));
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_EndCameraGC(void)
|
||||||
|
{
|
||||||
|
endcam_cast().GC();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean K_EndCameraIsFreezing(void)
|
||||||
|
{
|
||||||
|
return endcam_cast().Freezing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_SaveEndCamera(savebuffer_t *save)
|
||||||
|
{
|
||||||
|
endcam_cast().Archive(srb2::ArchiveWrapper(save));
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_LoadEndCamera(savebuffer_t *save)
|
||||||
|
{
|
||||||
|
endcam_cast().Archive(srb2::UnArchiveWrapper(save));
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_StartRoundWinCamera(mobj_t *origin, angle_t focusAngle, fixed_t finalRadius, tic_t panDuration, fixed_t panSpeed)
|
||||||
|
{
|
||||||
|
const fixed_t angF = AngleFixed(focusAngle);
|
||||||
|
|
||||||
|
g_endcam.origin = {origin->x, origin->y, P_GetMobjHead(origin)};
|
||||||
|
g_endcam.startRadius = {2400*mapobjectscale, 800*mapobjectscale};
|
||||||
|
g_endcam.endRadius = {finalRadius, finalRadius / 2};
|
||||||
|
|
||||||
|
g_endcam.swirlDuration = 3*TICRATE;
|
||||||
|
g_endcam.startAngle = angF + (90*FRACUNIT);
|
||||||
|
g_endcam.endAngle = angF + (720*FRACUNIT);
|
||||||
|
|
||||||
|
P_SetTarget(&g_endcam.panMobj, origin);
|
||||||
|
g_endcam.panDuration = panDuration;
|
||||||
|
g_endcam.panSpeed = panSpeed;
|
||||||
|
|
||||||
|
K_CommitEndCamera();
|
||||||
|
|
||||||
|
g_darkness.start = leveltime;
|
||||||
|
g_darkness.end = leveltime + g_endcam.swirlDuration + DARKNESS_FADE_TIME;
|
||||||
|
}
|
||||||
77
src/k_endcam.h
Normal file
77
src/k_endcam.h
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
// DR. ROBOTNIK'S RING RACERS
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2024 by James Robert Roman
|
||||||
|
//
|
||||||
|
// This program is free software distributed under the
|
||||||
|
// terms of the GNU General Public License, version 2.
|
||||||
|
// See the 'LICENSE' file for more details.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef k_endcam_h
|
||||||
|
#define k_endcam_h
|
||||||
|
|
||||||
|
#include "typedef.h"
|
||||||
|
|
||||||
|
#include "doomtype.h"
|
||||||
|
#include "m_fixed.h"
|
||||||
|
#include "tables.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct endcam_t
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Configurable properties
|
||||||
|
//
|
||||||
|
|
||||||
|
vector3_t origin; // center point
|
||||||
|
vector2_t startRadius; // X = horizontal, Y = vertical
|
||||||
|
vector2_t endRadius;
|
||||||
|
|
||||||
|
tic_t swirlDuration;
|
||||||
|
fixed_t startAngle; // 180*FRACUNIT, NOT ANGLE_180
|
||||||
|
fixed_t endAngle;
|
||||||
|
|
||||||
|
// 1) Camera pans vertically to keep this object centered
|
||||||
|
// 2) After swirling ends, pan horizontally too
|
||||||
|
mobj_t *panMobj;
|
||||||
|
tic_t panDuration; // dropoff after swirling ends
|
||||||
|
fixed_t panSpeed; // 0-FRACUNIT
|
||||||
|
|
||||||
|
/// ...
|
||||||
|
|
||||||
|
// You should not set these yourself.
|
||||||
|
// Use K_CommitEndCamera.
|
||||||
|
boolean active;
|
||||||
|
tic_t begin; // leveltime
|
||||||
|
};
|
||||||
|
|
||||||
|
extern endcam_t g_endcam;
|
||||||
|
|
||||||
|
// Sets endcam_t.active and endcam_t.begin.
|
||||||
|
//
|
||||||
|
// VERY IMPORTANT:
|
||||||
|
//
|
||||||
|
// Set the OTHER fields in endcam_t BEFORE calling this
|
||||||
|
// function, so the camera can cut away cleanly.
|
||||||
|
void K_CommitEndCamera(void);
|
||||||
|
|
||||||
|
// Automatically set up a cool camera in one-shot.
|
||||||
|
void K_StartRoundWinCamera(mobj_t *origin, angle_t focusAngle, fixed_t finalRadius, tic_t panDuration, fixed_t panSpeed);
|
||||||
|
|
||||||
|
/// ...
|
||||||
|
|
||||||
|
// Low-level functions
|
||||||
|
void K_MoveEndCamera(camera_t *thiscam);
|
||||||
|
void K_EndCameraGC(void);
|
||||||
|
boolean K_EndCameraIsFreezing(void);
|
||||||
|
void K_SaveEndCamera(savebuffer_t *save);
|
||||||
|
void K_LoadEndCamera(savebuffer_t *save);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif/*k_endcam_h*/
|
||||||
|
|
@ -260,6 +260,12 @@ void K_SetHitLagForObjects(mobj_t *victim, mobj_t *inflictor, mobj_t *source, IN
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (P_MobjWasRemoved(inflictor) == false && inflictor->type == MT_BUBBLESHIELD)
|
||||||
|
{
|
||||||
|
// Bubble blow-up: hitlag is based on player's speed
|
||||||
|
inflictor = source;
|
||||||
|
}
|
||||||
|
|
||||||
if (P_MobjWasRemoved(victim) == false && P_MobjWasRemoved(inflictor) == false)
|
if (P_MobjWasRemoved(victim) == false && P_MobjWasRemoved(inflictor) == false)
|
||||||
{
|
{
|
||||||
const fixed_t speedTicFactor = (mapobjectscale * 8);
|
const fixed_t speedTicFactor = (mapobjectscale * 8);
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ static patch_t *kp_rankcapsule;
|
||||||
static patch_t *kp_rankemerald;
|
static patch_t *kp_rankemerald;
|
||||||
static patch_t *kp_rankemeraldflash;
|
static patch_t *kp_rankemeraldflash;
|
||||||
static patch_t *kp_rankemeraldback;
|
static patch_t *kp_rankemeraldback;
|
||||||
|
static patch_t *kp_pts[2];
|
||||||
|
|
||||||
static patch_t *kp_goal[2][2]; // [skull][4p]
|
static patch_t *kp_goal[2][2]; // [skull][4p]
|
||||||
static patch_t *kp_goalrod[2]; // [4p]
|
static patch_t *kp_goalrod[2]; // [4p]
|
||||||
|
|
@ -451,7 +452,7 @@ void K_LoadKartHUDGraphics(void)
|
||||||
|
|
||||||
// Extra ranking icons
|
// Extra ranking icons
|
||||||
HU_UpdatePatch(&kp_rankbumper, "K_BLNICO");
|
HU_UpdatePatch(&kp_rankbumper, "K_BLNICO");
|
||||||
HU_UpdatePatch(&kp_bigbumper, "K_BLNBIG");
|
HU_UpdatePatch(&kp_bigbumper, "K_BLNREG");
|
||||||
HU_UpdatePatch(&kp_tinybumper[0], "K_BLNA");
|
HU_UpdatePatch(&kp_tinybumper[0], "K_BLNA");
|
||||||
HU_UpdatePatch(&kp_tinybumper[1], "K_BLNB");
|
HU_UpdatePatch(&kp_tinybumper[1], "K_BLNB");
|
||||||
HU_UpdatePatch(&kp_ranknobumpers, "K_NOBLNS");
|
HU_UpdatePatch(&kp_ranknobumpers, "K_NOBLNS");
|
||||||
|
|
@ -459,6 +460,8 @@ void K_LoadKartHUDGraphics(void)
|
||||||
HU_UpdatePatch(&kp_rankemerald, "K_EMERC");
|
HU_UpdatePatch(&kp_rankemerald, "K_EMERC");
|
||||||
HU_UpdatePatch(&kp_rankemeraldflash, "K_EMERW");
|
HU_UpdatePatch(&kp_rankemeraldflash, "K_EMERW");
|
||||||
HU_UpdatePatch(&kp_rankemeraldback, "K_EMERBK");
|
HU_UpdatePatch(&kp_rankemeraldback, "K_EMERBK");
|
||||||
|
HU_UpdatePatch(&kp_pts[0], "K_POINTS");
|
||||||
|
HU_UpdatePatch(&kp_pts[1], "K_POINT4");
|
||||||
|
|
||||||
// Battle goal
|
// Battle goal
|
||||||
HU_UpdatePatch(&kp_goal[0][0], "K_ST1GLA");
|
HU_UpdatePatch(&kp_goal[0][0], "K_ST1GLA");
|
||||||
|
|
@ -3356,7 +3359,22 @@ static void K_drawKartBumpersOrKarma(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|V_SLIDEIN|splitflags|flipflag, kp_ringstickersplit[0]);
|
{
|
||||||
|
using srb2::Draw;
|
||||||
|
int width = 39;
|
||||||
|
if (!battleprisons)
|
||||||
|
{
|
||||||
|
constexpr int kPad = 16;
|
||||||
|
if (flipflag)
|
||||||
|
fx -= kPad;
|
||||||
|
width += kPad;
|
||||||
|
}
|
||||||
|
Draw(fx-1 + (flipflag ? width + 3 : 0), fy+1)
|
||||||
|
.flags(V_HUDTRANS|V_SLIDEIN|splitflags)
|
||||||
|
.align(flipflag ? Draw::Align::kRight : Draw::Align::kLeft)
|
||||||
|
.width(width)
|
||||||
|
.small_sticker();
|
||||||
|
}
|
||||||
|
|
||||||
fx += 2;
|
fx += 2;
|
||||||
|
|
||||||
|
|
@ -3392,12 +3410,18 @@ static void K_drawKartBumpersOrKarma(void)
|
||||||
|
|
||||||
V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap);
|
V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap);
|
||||||
|
|
||||||
UINT8 ln[2];
|
using srb2::Draw;
|
||||||
ln[0] = (bumpers / 10 % 10);
|
Draw row = Draw(fx+12, fy).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kPing);
|
||||||
ln[1] = (bumpers % 10);
|
row.text("{:02}", bumpers);
|
||||||
|
if (g_pointlimit <= stplyr->roundscore && leveltime % 8 < 4)
|
||||||
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[ln[0]]);
|
{
|
||||||
V_DrawScaledPatch(fx+19, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[ln[1]]);
|
row = row.colorize(SKINCOLOR_TANGERINE);
|
||||||
|
}
|
||||||
|
row.xy(10, -2).patch(kp_pts[1]);
|
||||||
|
row
|
||||||
|
.x(31)
|
||||||
|
.flags(g_pointlimit <= stplyr->roundscore ? V_STRINGDANCE : 0)
|
||||||
|
.text("{:02}", stplyr->roundscore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -3421,9 +3445,21 @@ static void K_drawKartBumpersOrKarma(void)
|
||||||
fy += 2;
|
fy += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
K_DrawSticker(LAPS_X+12, fy+5, bumpers > 9 ? 64 : 52, V_HUDTRANS|V_SLIDEIN|splitflags, false);
|
K_DrawSticker(LAPS_X+12, fy+5, 75, V_HUDTRANS|V_SLIDEIN|splitflags, false);
|
||||||
V_DrawMappedPatch(LAPS_X+15, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bigbumper, colormap);
|
V_DrawMappedPatch(LAPS_X+12, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bigbumper, colormap);
|
||||||
V_DrawTimerString(LAPS_X+47, fy+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d", bumpers));
|
|
||||||
|
using srb2::Draw;
|
||||||
|
Draw row = Draw(LAPS_X+12+23+1, fy+3).flags(V_HUDTRANS|V_SLIDEIN|splitflags).font(Draw::Font::kThinTimer);
|
||||||
|
row.text("{:02}", bumpers);
|
||||||
|
if (g_pointlimit <= stplyr->roundscore && leveltime % 8 < 4)
|
||||||
|
{
|
||||||
|
row = row.colorize(SKINCOLOR_TANGERINE);
|
||||||
|
}
|
||||||
|
row.xy(12, -2).patch(kp_pts[0]);
|
||||||
|
row
|
||||||
|
.x(12+27)
|
||||||
|
.flags(g_pointlimit <= stplyr->roundscore ? V_STRINGDANCE : 0)
|
||||||
|
.text("{:02}", stplyr->roundscore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5851,10 +5887,16 @@ void K_drawKartHUD(void)
|
||||||
K_drawKartFirstPerson();
|
K_drawKartFirstPerson();
|
||||||
|
|
||||||
// Draw full screen stuff that turns off the rest of the HUD
|
// Draw full screen stuff that turns off the rest of the HUD
|
||||||
if (mapreset && R_GetViewNumber() == 0)
|
if (R_GetViewNumber() == 0)
|
||||||
{
|
{
|
||||||
K_drawChallengerScreen();
|
if (mapreset)
|
||||||
return;
|
{
|
||||||
|
K_drawChallengerScreen();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_emeraldWin)
|
||||||
|
K_drawEmeraldWin(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!demo.title)
|
if (!demo.title)
|
||||||
|
|
@ -6069,15 +6111,15 @@ void K_drawKartHUD(void)
|
||||||
K_drawSpectatorHUD(false);
|
K_drawSpectatorHUD(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (R_GetViewNumber() == 0 && g_emeraldWin)
|
||||||
|
K_drawEmeraldWin(true);
|
||||||
|
|
||||||
if (modeattacking || freecam) // everything after here is MP and debug only
|
if (modeattacking || freecam) // everything after here is MP and debug only
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((gametyperules & GTR_KARMA) && !r_splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM *
|
if ((gametyperules & GTR_KARMA) && !r_splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM *
|
||||||
V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem);
|
V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem);
|
||||||
|
|
||||||
if (g_emeraldWin)
|
|
||||||
K_drawEmeraldWin();
|
|
||||||
|
|
||||||
// Draw FREE PLAY.
|
// Draw FREE PLAY.
|
||||||
K_drawKartFreePlay();
|
K_drawKartFreePlay();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ void K_drawSpectatorHUD(boolean director);
|
||||||
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode);
|
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode);
|
||||||
void K_drawKart2PTimestamp(void);
|
void K_drawKart2PTimestamp(void);
|
||||||
void K_drawKart4PTimestamp(void);
|
void K_drawKart4PTimestamp(void);
|
||||||
void K_drawEmeraldWin(void);
|
void K_drawEmeraldWin(boolean overlay);
|
||||||
void K_DrawMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap);
|
void K_DrawMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, UINT16 map, const UINT8 *colormap);
|
||||||
void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap);
|
void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, patch_t *patch, const UINT8 *colormap);
|
||||||
void K_drawTargetHUD(const vector3_t *origin, player_t *player);
|
void K_drawTargetHUD(const vector3_t *origin, player_t *player);
|
||||||
|
|
|
||||||
34
src/k_kart.c
34
src/k_kart.c
|
|
@ -50,6 +50,7 @@
|
||||||
#include "k_tally.h"
|
#include "k_tally.h"
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "m_easing.h"
|
#include "m_easing.h"
|
||||||
|
#include "k_endcam.h"
|
||||||
|
|
||||||
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
|
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
|
||||||
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
|
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
|
||||||
|
|
@ -3851,7 +3852,7 @@ void K_DoGuardBreak(mobj_t *t1, mobj_t *t2) {
|
||||||
K_AddMessageForPlayer(t2->player, "Smashed 'em!", false, false);
|
K_AddMessageForPlayer(t2->player, "Smashed 'em!", false, false);
|
||||||
K_AddMessageForPlayer(t1->player, "BARRIER BREAK!!", false, false);
|
K_AddMessageForPlayer(t1->player, "BARRIER BREAK!!", false, false);
|
||||||
|
|
||||||
angle_t thrangle = R_PointToAngle2(t1->x, t1->y, t2->x, t2->y);
|
angle_t thrangle = R_PointToAngle2(t2->x, t2->y, t1->x, t1->y);
|
||||||
P_Thrust(t1, thrangle, 7*mapobjectscale);
|
P_Thrust(t1, thrangle, 7*mapobjectscale);
|
||||||
|
|
||||||
P_DamageMobj(t1, t2, t2, 1, DMG_TUMBLE);
|
P_DamageMobj(t1, t2, t2, 1, DMG_TUMBLE);
|
||||||
|
|
@ -3918,6 +3919,16 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN
|
||||||
{
|
{
|
||||||
player->roundscore = 100; // Make sure you win!
|
player->roundscore = 100; // Make sure you win!
|
||||||
P_DoAllPlayersExit(0, false);
|
P_DoAllPlayersExit(0, false);
|
||||||
|
|
||||||
|
mobj_t *source = !P_MobjWasRemoved(inflictor) ? inflictor : player->mo;
|
||||||
|
|
||||||
|
K_StartRoundWinCamera(
|
||||||
|
victim->mo,
|
||||||
|
R_PointToAngle2(source->x, source->y, victim->mo->x, victim->mo->y) + ANGLE_135,
|
||||||
|
200*mapobjectscale,
|
||||||
|
8*TICRATE,
|
||||||
|
FRACUNIT/512
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
P_AddPlayerScore(player, points);
|
P_AddPlayerScore(player, points);
|
||||||
|
|
@ -8910,19 +8921,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
||||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER);
|
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leveltime < player->darkness_end)
|
if (!player->exiting && !(player->pflags & PF_ELIMINATED))
|
||||||
{
|
{
|
||||||
if (leveltime > player->darkness_end - DARKNESS_FADE_TIME)
|
if (leveltime < player->darkness_end)
|
||||||
{
|
{
|
||||||
player->darkness_start = leveltime - (player->darkness_end - leveltime);
|
if (leveltime > player->darkness_end - DARKNESS_FADE_TIME)
|
||||||
|
{
|
||||||
|
player->darkness_start = leveltime - (player->darkness_end - leveltime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player->darkness_start = leveltime;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
player->darkness_start = leveltime;
|
|
||||||
}
|
|
||||||
|
|
||||||
player->darkness_end = leveltime + (2 * DARKNESS_FADE_TIME);
|
player->darkness_end = leveltime + (2 * DARKNESS_FADE_TIME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -525,7 +525,7 @@ void level_tally_t::Init(player_t *player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delay = TALLY_TIME; // sync up with musiccountdown
|
delay = K_TallyDelay(); // sync up with musiccountdown
|
||||||
|
|
||||||
if (game_over == true)
|
if (game_over == true)
|
||||||
{
|
{
|
||||||
|
|
@ -1404,3 +1404,8 @@ boolean K_PlayerTallyActive(player_t *player)
|
||||||
{
|
{
|
||||||
return player->tally.active; //(player->exiting || (player->pflags & PF_NOCONTEST));
|
return player->tally.active; //(player->exiting || (player->pflags & PF_NOCONTEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tic_t K_TallyDelay(void)
|
||||||
|
{
|
||||||
|
return ((gametyperules & GTR_BUMPERS) ? 4 : 3) * TICRATE;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@
|
||||||
|
|
||||||
#define TALLY_WINDOW_SIZE (2)
|
#define TALLY_WINDOW_SIZE (2)
|
||||||
|
|
||||||
#define TALLY_TIME (3*TICRATE)
|
#define MUSIC_COUNTDOWN_MAX (K_TallyDelay() + 8*TICRATE)
|
||||||
#define MUSIC_COUNTDOWN_MAX (TALLY_TIME + 8*TICRATE)
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
|
@ -119,6 +118,7 @@ void K_InitPlayerTally(player_t *player);
|
||||||
void K_TickPlayerTally(player_t *player);
|
void K_TickPlayerTally(player_t *player);
|
||||||
void K_DrawPlayerTally(void);
|
void K_DrawPlayerTally(void);
|
||||||
boolean K_PlayerTallyActive(player_t *player);
|
boolean K_PlayerTallyActive(player_t *player);
|
||||||
|
tic_t K_TallyDelay(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
||||||
|
|
@ -560,6 +560,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
||||||
Obj_SetEmeraldAwardee(special, toucher);
|
Obj_SetEmeraldAwardee(special, toucher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// You have 6 emeralds and you touch the 7th: win instantly!
|
||||||
|
if (ALLCHAOSEMERALDS((player->emeralds | special->extravalue1)))
|
||||||
|
{
|
||||||
|
player->emeralds |= special->extravalue1;
|
||||||
|
K_CheckEmeralds(player);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
case MT_SPECIAL_UFO:
|
case MT_SPECIAL_UFO:
|
||||||
if (Obj_UFOEmeraldCollect(special, toucher) == false)
|
if (Obj_UFOEmeraldCollect(special, toucher) == false)
|
||||||
|
|
@ -1757,7 +1764,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
||||||
|
|
||||||
target->flags &= ~(MF_SOLID|MF_SHOOTABLE); // does not block
|
target->flags &= ~(MF_SOLID|MF_SHOOTABLE); // does not block
|
||||||
P_UnsetThingPosition(target);
|
P_UnsetThingPosition(target);
|
||||||
target->flags |= MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY;
|
target->flags |= MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_NOGRAVITY;
|
||||||
P_SetThingPosition(target);
|
P_SetThingPosition(target);
|
||||||
target->standingslope = NULL;
|
target->standingslope = NULL;
|
||||||
target->terrain = NULL;
|
target->terrain = NULL;
|
||||||
|
|
@ -1792,6 +1799,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
||||||
if (battleovertime.enabled >= 10*TICRATE) // Overtime Barrier is armed
|
if (battleovertime.enabled >= 10*TICRATE) // Overtime Barrier is armed
|
||||||
{
|
{
|
||||||
target->player->pflags |= PF_ELIMINATED;
|
target->player->pflags |= PF_ELIMINATED;
|
||||||
|
if (target->player->darkness_end < leveltime)
|
||||||
|
{
|
||||||
|
target->player->darkness_start = leveltime;
|
||||||
|
}
|
||||||
|
target->player->darkness_end = INFTICS;
|
||||||
}
|
}
|
||||||
|
|
||||||
K_CheckBumpers();
|
K_CheckBumpers();
|
||||||
|
|
@ -1960,6 +1972,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
||||||
case MT_PLAYER:
|
case MT_PLAYER:
|
||||||
if (damagetype != DMG_SPECTATOR)
|
if (damagetype != DMG_SPECTATOR)
|
||||||
{
|
{
|
||||||
|
fixed_t flingSpeed = FixedHypot(target->momx, target->momy);
|
||||||
angle_t flingAngle;
|
angle_t flingAngle;
|
||||||
mobj_t *kart;
|
mobj_t *kart;
|
||||||
|
|
||||||
|
|
@ -2012,8 +2025,18 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
||||||
// so make sure that this draws at the correct angle.
|
// so make sure that this draws at the correct angle.
|
||||||
target->rollangle = 0;
|
target->rollangle = 0;
|
||||||
|
|
||||||
P_InstaThrust(target, flingAngle, 14 * target->scale);
|
fixed_t inflictorSpeed = 0;
|
||||||
P_SetObjectMomZ(target, 14*FRACUNIT, false);
|
if (!P_MobjWasRemoved(inflictor))
|
||||||
|
{
|
||||||
|
inflictorSpeed = FixedHypot(inflictor->momx, inflictor->momy);
|
||||||
|
if (inflictorSpeed > flingSpeed)
|
||||||
|
{
|
||||||
|
flingSpeed = inflictorSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
P_InstaThrust(target, flingAngle, max(flingSpeed, 14 * target->scale));
|
||||||
|
P_SetObjectMomZ(target, 20*FRACUNIT, false);
|
||||||
|
|
||||||
P_PlayDeathSound(target);
|
P_PlayDeathSound(target);
|
||||||
}
|
}
|
||||||
|
|
@ -2331,7 +2354,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
||||||
P_Thrust(target, R_PointToAngle2(owner->x, owner->y, target->x, target->y), 4 * target->scale);
|
P_Thrust(target, R_PointToAngle2(owner->x, owner->y, target->x, target->y), 4 * target->scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
target->momz += (24 * target->scale) * P_MobjFlip(target);
|
target->momz += (18 * target->scale) * P_MobjFlip(target);
|
||||||
target->fuse = 8;
|
target->fuse = 8;
|
||||||
|
|
||||||
overlay = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_OVERLAY);
|
overlay = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_OVERLAY);
|
||||||
|
|
@ -2830,6 +2853,15 @@ static boolean P_FlashingException(const player_t *player, const mobj_t *inflict
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inflictor->type == MT_SSMINE)
|
||||||
|
{
|
||||||
|
// Mine's first hit is DMG_EXPLODE.
|
||||||
|
// Afterward, it leaves a spinout hitbox which remains for a short period.
|
||||||
|
// If the spinout hitbox ignored flashing tics, you would be combod every tic and die instantly.
|
||||||
|
// DMG_EXPLODE already ignores flashing tics (correct behavior).
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!P_IsKartItem(inflictor->type) && inflictor->type != MT_PLAYER)
|
if (!P_IsKartItem(inflictor->type) && inflictor->type != MT_PLAYER)
|
||||||
{
|
{
|
||||||
// Exception only applies to player items.
|
// Exception only applies to player items.
|
||||||
|
|
|
||||||
102
src/p_map.c
102
src/p_map.c
|
|
@ -522,17 +522,6 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean P_BubbleCanReflect(mobj_t *t1, mobj_t *t2)
|
|
||||||
{
|
|
||||||
return (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_GACHABOM
|
|
||||||
|| t2->type == MT_BANANA || t2->type == MT_EGGMANITEM || t2->type == MT_BALLHOG
|
|
||||||
|| t2->type == MT_SSMINE || t2->type == MT_LANDMINE || t2->type == MT_SINK
|
|
||||||
|| t2->type == MT_GARDENTOP
|
|
||||||
|| t2->type == MT_DROPTARGET
|
|
||||||
|| t2->type == MT_KART_LEFTOVER
|
|
||||||
|| (t2->type == MT_PLAYER && t1->target != t2));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// PIT_CheckThing
|
// PIT_CheckThing
|
||||||
//
|
//
|
||||||
|
|
@ -779,13 +768,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
||||||
return BMIT_CONTINUE;
|
return BMIT_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thing->type == MT_BATTLEUFO)
|
if (thing->type == MT_BATTLEUFO && tm.thing->player)
|
||||||
{
|
{
|
||||||
if (!tm.thing->player)
|
|
||||||
{
|
|
||||||
return BMIT_CONTINUE; // not a player
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thing->health <= 0)
|
if (thing->health <= 0)
|
||||||
{
|
{
|
||||||
return BMIT_CONTINUE; // dead
|
return BMIT_CONTINUE; // dead
|
||||||
|
|
@ -1009,7 +993,29 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
||||||
if (tm.thing->type == MT_RANDOMITEM)
|
if (tm.thing->type == MT_RANDOMITEM)
|
||||||
return BMIT_CONTINUE;
|
return BMIT_CONTINUE;
|
||||||
|
|
||||||
if (tm.thing->type != MT_PLAYER && thing->player && K_PlayerGuard(thing->player) && P_BubbleCanReflect(thing, tm.thing))
|
if (tm.thing->type != MT_PLAYER && thing->player && K_PlayerGuard(thing->player) && K_BubbleShieldCanReflect(thing, tm.thing))
|
||||||
|
{
|
||||||
|
// see if it went over / under
|
||||||
|
if (tm.thing->z > thing->z + thing->height)
|
||||||
|
return BMIT_CONTINUE; // overhead
|
||||||
|
if (tm.thing->z + tm.thing->height < thing->z)
|
||||||
|
return BMIT_CONTINUE; // underneath
|
||||||
|
|
||||||
|
return K_BubbleShieldReflect(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||||
|
}
|
||||||
|
else if (thing->type != MT_PLAYER && tm.thing->player && K_PlayerGuard(tm.thing->player) && K_BubbleShieldCanReflect(tm.thing, thing))
|
||||||
|
{
|
||||||
|
// see if it went over / under
|
||||||
|
if (tm.thing->z > thing->z + thing->height)
|
||||||
|
return BMIT_CONTINUE; // overhead
|
||||||
|
if (tm.thing->z + tm.thing->height < thing->z)
|
||||||
|
return BMIT_CONTINUE; // underneath
|
||||||
|
|
||||||
|
return K_BubbleShieldReflect(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bubble Shield reflect
|
||||||
|
if (thing->type == MT_BUBBLESHIELD && !P_MobjWasRemoved(thing->target) && thing->target->player && thing->target->player->bubbleblowup)
|
||||||
{
|
{
|
||||||
// see if it went over / under
|
// see if it went over / under
|
||||||
if (tm.thing->z > thing->z + thing->height)
|
if (tm.thing->z > thing->z + thing->height)
|
||||||
|
|
@ -1019,7 +1025,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
||||||
|
|
||||||
return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||||
}
|
}
|
||||||
else if (thing->type != MT_PLAYER && tm.thing->player && K_PlayerGuard(tm.thing->player) && P_BubbleCanReflect(tm.thing, thing))
|
else if (tm.thing->type == MT_BUBBLESHIELD && !P_MobjWasRemoved(tm.thing->target) && tm.thing->target->player && tm.thing->target->player->bubbleblowup)
|
||||||
{
|
{
|
||||||
// see if it went over / under
|
// see if it went over / under
|
||||||
if (tm.thing->z > thing->z + thing->height)
|
if (tm.thing->z > thing->z + thing->height)
|
||||||
|
|
@ -1030,52 +1036,6 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
||||||
return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bubble Shield reflect
|
|
||||||
if ((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->bubbleblowup)
|
|
||||||
|| (thing->player && thing->player->bubbleblowup))
|
|
||||||
{
|
|
||||||
// see if it went over / under
|
|
||||||
if (tm.thing->z > thing->z + thing->height)
|
|
||||||
return BMIT_CONTINUE; // overhead
|
|
||||||
if (tm.thing->z + tm.thing->height < thing->z)
|
|
||||||
return BMIT_CONTINUE; // underneath
|
|
||||||
|
|
||||||
if (P_BubbleCanReflect(thing, tm.thing))
|
|
||||||
{
|
|
||||||
// don't let player hitbox touch it too
|
|
||||||
if (thing->player)
|
|
||||||
return BMIT_CONTINUE;
|
|
||||||
return K_BubbleShieldCollide(thing, tm.thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
|
||||||
}
|
|
||||||
else if ((tm.thing->flags & MF_SHOOTABLE) && !thing->player)
|
|
||||||
{
|
|
||||||
P_DamageMobj(tm.thing, thing, thing->target, 1, DMG_NORMAL);
|
|
||||||
return BMIT_CONTINUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((tm.thing->type == MT_BUBBLESHIELD && tm.thing->target->player && tm.thing->target->player->bubbleblowup)
|
|
||||||
|| (tm.thing->player && tm.thing->player->bubbleblowup))
|
|
||||||
{
|
|
||||||
// see if it went over / under
|
|
||||||
if (tm.thing->z > thing->z + thing->height)
|
|
||||||
return BMIT_CONTINUE; // overhead
|
|
||||||
if (tm.thing->z + tm.thing->height < thing->z)
|
|
||||||
return BMIT_CONTINUE; // underneath
|
|
||||||
|
|
||||||
if (P_BubbleCanReflect(tm.thing, thing))
|
|
||||||
{
|
|
||||||
// don't let player hitbox touch it too
|
|
||||||
if (tm.thing->player)
|
|
||||||
return BMIT_CONTINUE;
|
|
||||||
return K_BubbleShieldCollide(tm.thing, thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
|
||||||
}
|
|
||||||
else if ((thing->flags & MF_SHOOTABLE) && !tm.thing->player)
|
|
||||||
{
|
|
||||||
P_DamageMobj(thing, tm.thing, tm.thing->target, 1, DMG_NORMAL);
|
|
||||||
return BMIT_CONTINUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// double make sure bubbles won't collide with anything else
|
// double make sure bubbles won't collide with anything else
|
||||||
if (thing->type == MT_BUBBLESHIELD || tm.thing->type == MT_BUBBLESHIELD)
|
if (thing->type == MT_BUBBLESHIELD || tm.thing->type == MT_BUBBLESHIELD)
|
||||||
return BMIT_CONTINUE;
|
return BMIT_CONTINUE;
|
||||||
|
|
@ -4180,7 +4140,12 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mo->eflags & MFE_JUSTBOUNCEDWALL) // Stronger push-out
|
if (mo->health <= 0)
|
||||||
|
{
|
||||||
|
tmxmove = mo->momx;
|
||||||
|
tmymove = mo->momy;
|
||||||
|
}
|
||||||
|
else if (mo->eflags & MFE_JUSTBOUNCEDWALL) // Stronger push-out
|
||||||
{
|
{
|
||||||
tmxmove = mmomx;
|
tmxmove = mmomx;
|
||||||
tmymove = mmomy;
|
tmymove = mmomy;
|
||||||
|
|
@ -4217,6 +4182,11 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
||||||
mo->player->cmomx = tmxmove;
|
mo->player->cmomx = tmxmove;
|
||||||
mo->player->cmomy = tmymove;
|
mo->player->cmomy = tmymove;
|
||||||
|
|
||||||
|
if (mo->health <= 0)
|
||||||
|
{
|
||||||
|
mo->momz = 16 * mapobjectscale;
|
||||||
|
}
|
||||||
|
|
||||||
if (!bestslideline || !P_IsLineTripWire(bestslideline))
|
if (!bestslideline || !P_IsLineTripWire(bestslideline))
|
||||||
{
|
{
|
||||||
if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true, NULL))
|
if (!P_TryMove(mo, mo->x + tmxmove, mo->y + tmymove, true, NULL))
|
||||||
|
|
|
||||||
|
|
@ -1969,7 +1969,7 @@ void P_XYMovement(mobj_t *mo)
|
||||||
return;
|
return;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz))
|
if (((!(mo->eflags & MFE_VERTICALFLIP) && (mo->momz > 0 || mo->z > mo->floorz)) || (mo->eflags & MFE_VERTICALFLIP && (mo->momz < 0 || mo->z+mo->height < mo->ceilingz)))
|
||||||
&& !(player && player->carry == CR_SLIDING))
|
&& !(player && player->carry == CR_SLIDING))
|
||||||
return; // no friction when airborne
|
return; // no friction when airborne
|
||||||
|
|
||||||
|
|
@ -2501,6 +2501,11 @@ boolean P_ZMovement(mobj_t *mo)
|
||||||
mom.x = mom.y = 0;
|
mom.x = mom.y = 0;
|
||||||
mom.z = -mom.z/2;
|
mom.z = -mom.z/2;
|
||||||
}
|
}
|
||||||
|
else if (mo->type == MT_PLAYER) // only DEAD players
|
||||||
|
{
|
||||||
|
mom.z = -mom.z;
|
||||||
|
mo->flags |= MF_NOCLIP | MF_NOCLIPHEIGHT; // fall through floor next time
|
||||||
|
}
|
||||||
else if (mo->flags & MF_MISSILE)
|
else if (mo->flags & MF_MISSILE)
|
||||||
{
|
{
|
||||||
if (!(mo->flags & MF_NOCLIP))
|
if (!(mo->flags & MF_NOCLIP))
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
#include "g_party.h"
|
#include "g_party.h"
|
||||||
#include "k_vote.h"
|
#include "k_vote.h"
|
||||||
#include "k_zvote.h"
|
#include "k_zvote.h"
|
||||||
|
#include "k_endcam.h"
|
||||||
|
|
||||||
#include <tracy/tracy/TracyC.h>
|
#include <tracy/tracy/TracyC.h>
|
||||||
|
|
||||||
|
|
@ -5745,6 +5746,12 @@ static void P_RelinkPointers(void)
|
||||||
|
|
||||||
P_LoadMobjPointers(RelinkMobjVoid);
|
P_LoadMobjPointers(RelinkMobjVoid);
|
||||||
|
|
||||||
|
if (g_endcam.panMobj)
|
||||||
|
{
|
||||||
|
if (!RelinkMobj(&g_endcam.panMobj))
|
||||||
|
CONS_Debug(DBG_GAMELOGIC, "g_endcam.panMobj not found\n");
|
||||||
|
}
|
||||||
|
|
||||||
// use info field (value = oldposition) to relink mobjs
|
// use info field (value = oldposition) to relink mobjs
|
||||||
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
|
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
|
||||||
currentthinker = currentthinker->next)
|
currentthinker = currentthinker->next)
|
||||||
|
|
@ -6471,7 +6478,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
|
||||||
WRITEINT32(save->p, numgotboxes);
|
WRITEINT32(save->p, numgotboxes);
|
||||||
WRITEUINT8(save->p, numtargets);
|
WRITEUINT8(save->p, numtargets);
|
||||||
WRITEUINT8(save->p, battleprisons);
|
WRITEUINT8(save->p, battleprisons);
|
||||||
WRITEUINT8(save->p, g_emeraldWin);
|
WRITEUINT32(save->p, g_emeraldWin);
|
||||||
|
|
||||||
WRITEUINT8(save->p, gamespeed);
|
WRITEUINT8(save->p, gamespeed);
|
||||||
WRITEUINT8(save->p, numlaps);
|
WRITEUINT8(save->p, numlaps);
|
||||||
|
|
@ -6657,7 +6664,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
|
||||||
numgotboxes = READINT32(save->p);
|
numgotboxes = READINT32(save->p);
|
||||||
numtargets = READUINT8(save->p);
|
numtargets = READUINT8(save->p);
|
||||||
battleprisons = (boolean)READUINT8(save->p);
|
battleprisons = (boolean)READUINT8(save->p);
|
||||||
g_emeraldWin = (boolean)READUINT8(save->p);
|
g_emeraldWin = (tic_t)READUINT32(save->p);
|
||||||
|
|
||||||
gamespeed = READUINT8(save->p);
|
gamespeed = READUINT8(save->p);
|
||||||
numlaps = READUINT8(save->p);
|
numlaps = READUINT8(save->p);
|
||||||
|
|
@ -6868,6 +6875,9 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
K_SaveEndCamera(save);
|
||||||
|
WriteMobjPointer(g_endcam.panMobj);
|
||||||
|
|
||||||
P_NetArchivePlayers(save);
|
P_NetArchivePlayers(save);
|
||||||
P_NetArchiveParties(save);
|
P_NetArchiveParties(save);
|
||||||
P_NetArchiveRoundQueue(save);
|
P_NetArchiveRoundQueue(save);
|
||||||
|
|
@ -6933,6 +6943,9 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
|
||||||
if (!P_NetUnArchiveMisc(save, reloading))
|
if (!P_NetUnArchiveMisc(save, reloading))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
K_LoadEndCamera(save);
|
||||||
|
ReadMobjPointer(&g_endcam.panMobj);
|
||||||
|
|
||||||
P_NetUnArchivePlayers(save);
|
P_NetUnArchivePlayers(save);
|
||||||
P_NetUnArchiveParties(save);
|
P_NetUnArchiveParties(save);
|
||||||
P_NetUnArchiveRoundQueue(save);
|
P_NetUnArchiveRoundQueue(save);
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "k_dialogue.h"
|
#include "k_dialogue.h"
|
||||||
#include "k_hud.h" // K_ClearPersistentMessages
|
#include "k_hud.h" // K_ClearPersistentMessages
|
||||||
|
#include "k_endcam.h"
|
||||||
|
|
||||||
// Replay names have time
|
// Replay names have time
|
||||||
#if !defined (UNDER_CE)
|
#if !defined (UNDER_CE)
|
||||||
|
|
@ -7696,6 +7697,8 @@ static void P_InitLevelSettings(void)
|
||||||
|
|
||||||
K_ResetSpecialStage();
|
K_ResetSpecialStage();
|
||||||
K_ResetBossInfo();
|
K_ResetBossInfo();
|
||||||
|
|
||||||
|
memset(&g_endcam, 0, sizeof g_endcam);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
||||||
12
src/p_tick.c
12
src/p_tick.c
|
|
@ -48,6 +48,7 @@
|
||||||
#include "k_dialogue.h"
|
#include "k_dialogue.h"
|
||||||
#include "m_easing.h"
|
#include "m_easing.h"
|
||||||
#include "k_hud.h" // messagetimer
|
#include "k_hud.h" // messagetimer
|
||||||
|
#include "k_endcam.h"
|
||||||
|
|
||||||
#include "lua_profile.h"
|
#include "lua_profile.h"
|
||||||
|
|
||||||
|
|
@ -65,12 +66,12 @@ static boolean g_freezeLevel;
|
||||||
|
|
||||||
boolean P_LevelIsFrozen(void)
|
boolean P_LevelIsFrozen(void)
|
||||||
{
|
{
|
||||||
return (g_freezeLevel || g_freezeCheat);
|
return (g_freezeLevel || g_freezeCheat || K_EndCameraIsFreezing());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean P_FreezeCheat(void)
|
boolean P_FreezeCheat(void)
|
||||||
{
|
{
|
||||||
return (g_freezeLevel || g_freezeCheat);
|
return (g_freezeLevel || g_freezeCheat || K_EndCameraIsFreezing());
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_SetFreezeCheat(boolean value)
|
void P_SetFreezeCheat(boolean value)
|
||||||
|
|
@ -101,7 +102,7 @@ boolean P_MobjIsFrozen(mobj_t *mobj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_freezeLevel == true)
|
if (g_freezeLevel == true || K_EndCameraIsFreezing())
|
||||||
{
|
{
|
||||||
// level totally frozen
|
// level totally frozen
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -767,6 +768,8 @@ void P_RunChaseCameras(void)
|
||||||
P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false);
|
P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
K_EndCameraGC();
|
||||||
}
|
}
|
||||||
|
|
||||||
static fixed_t P_GetDarkness(tic_t start, tic_t end)
|
static fixed_t P_GetDarkness(tic_t start, tic_t end)
|
||||||
|
|
@ -786,7 +789,8 @@ static fixed_t P_GetDarkness(tic_t start, tic_t end)
|
||||||
t = end - leveltime;
|
t = end - leveltime;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Easing_Linear((t * FRACUNIT) / DARKNESS_FADE_TIME, 0, FRACUNIT/7);
|
return Easing_Linear((t * FRACUNIT) / DARKNESS_FADE_TIME, 0,
|
||||||
|
(gametyperules & GTR_BUMPERS) ? FRACUNIT/3 : FRACUNIT/7);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
16
src/p_user.c
16
src/p_user.c
|
|
@ -67,6 +67,7 @@
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "k_tally.h"
|
#include "k_tally.h"
|
||||||
#include "k_objects.h"
|
#include "k_objects.h"
|
||||||
|
#include "k_endcam.h"
|
||||||
|
|
||||||
#ifdef HWRENDER
|
#ifdef HWRENDER
|
||||||
#include "hardware/hw_light.h"
|
#include "hardware/hw_light.h"
|
||||||
|
|
@ -2837,7 +2838,7 @@ static void P_DeathThink(player_t *player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((player->pflags & PF_ELIMINATED) /*&& (gametyperules & GTR_BUMPERS)*/)
|
if ((player->pflags & PF_ELIMINATED) || exitcountdown)
|
||||||
{
|
{
|
||||||
playerGone = true;
|
playerGone = true;
|
||||||
}
|
}
|
||||||
|
|
@ -3062,6 +3063,11 @@ void P_ToggleDemoCamera(UINT8 viewnum)
|
||||||
|
|
||||||
void P_ResetCamera(player_t *player, camera_t *thiscam)
|
void P_ResetCamera(player_t *player, camera_t *thiscam)
|
||||||
{
|
{
|
||||||
|
if (g_endcam.active)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tic_t tries = 0;
|
tic_t tries = 0;
|
||||||
fixed_t x, y, z;
|
fixed_t x, y, z;
|
||||||
|
|
||||||
|
|
@ -3155,7 +3161,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
||||||
num = 0;
|
num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thiscam->freecam || player->spectator)
|
if ((thiscam->freecam || player->spectator) && !g_endcam.active)
|
||||||
{
|
{
|
||||||
P_DemoCameraMovement(thiscam, num);
|
P_DemoCameraMovement(thiscam, num);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -3164,6 +3170,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
||||||
if (paused || P_AutoPause())
|
if (paused || P_AutoPause())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (g_endcam.active)
|
||||||
|
{
|
||||||
|
K_MoveEndCamera(thiscam);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
playerScale = FixedDiv(player->mo->scale, mapobjectscale);
|
playerScale = FixedDiv(player->mo->scale, mapobjectscale);
|
||||||
scaleDiff = playerScale - FRACUNIT;
|
scaleDiff = playerScale - FRACUNIT;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,9 @@ TYPEDEF (botcontroller_t);
|
||||||
// k_brightmap.h
|
// k_brightmap.h
|
||||||
TYPEDEF (brightmapStorage_t);
|
TYPEDEF (brightmapStorage_t);
|
||||||
|
|
||||||
|
// k_endcam.h
|
||||||
|
TYPEDEF (endcam_t);
|
||||||
|
|
||||||
// k_follower.h
|
// k_follower.h
|
||||||
TYPEDEF (follower_t);
|
TYPEDEF (follower_t);
|
||||||
TYPEDEF (followercategory_t);
|
TYPEDEF (followercategory_t);
|
||||||
|
|
|
||||||
|
|
@ -132,11 +132,6 @@ void Chain::patch(patch_t* patch) const
|
||||||
V_DrawStretchyFixedPatch(FloatToFixed(x_), FloatToFixed(y_), h * scale_, v * scale_, flags_, patch, colormap_);
|
V_DrawStretchyFixedPatch(FloatToFixed(x_), FloatToFixed(y_), h * scale_, v * scale_, flags_, patch, colormap_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chain::patch(const char* name) const
|
|
||||||
{
|
|
||||||
patch(static_cast<patch_t*>(W_CachePatchName(name, PU_CACHE)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Chain::thumbnail(UINT16 mapnum) const
|
void Chain::thumbnail(UINT16 mapnum) const
|
||||||
{
|
{
|
||||||
const auto _ = Clipper(*this);
|
const auto _ = Clipper(*this);
|
||||||
|
|
@ -224,6 +219,36 @@ void Chain::button_(Button type, int ver, std::optional<bool> press) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chain::sticker(patch_t* end_graphic, UINT8 color) const
|
||||||
|
{
|
||||||
|
const auto _ = Clipper(*this);
|
||||||
|
|
||||||
|
INT32 x = x_;
|
||||||
|
INT32 y = y_;
|
||||||
|
INT32 width = width_;
|
||||||
|
INT32 flags = flags_ | V_FLIP;
|
||||||
|
|
||||||
|
auto fill = [&](int x, int width) { V_DrawFill(x, y, width, SHORT(end_graphic->height), color | (flags_ & ~0xFF)); };
|
||||||
|
|
||||||
|
if (align_ == Align::kRight)
|
||||||
|
{
|
||||||
|
width = -(width);
|
||||||
|
flags ^= V_FLIP;
|
||||||
|
fill(x + width, -(width));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fill(x, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
V_DrawScaledPatch(x + width, y, flags, end_graphic);
|
||||||
|
|
||||||
|
if (align_ == Align::kCenter)
|
||||||
|
{
|
||||||
|
V_DrawScaledPatch(x, y, flags ^ V_FLIP, end_graphic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Chain::Clipper::Clipper(const Chain& chain)
|
Chain::Clipper::Clipper(const Chain& chain)
|
||||||
{
|
{
|
||||||
V_SetClipRect(
|
V_SetClipRect(
|
||||||
|
|
@ -240,6 +265,11 @@ Chain::Clipper::~Clipper()
|
||||||
V_ClearClipRect();
|
V_ClearClipRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
patch_t* Draw::cache_patch(const char* name)
|
||||||
|
{
|
||||||
|
return static_cast<patch_t*>(W_CachePatchName(name, PU_CACHE));
|
||||||
|
}
|
||||||
|
|
||||||
int Draw::font_to_fontno(Font font)
|
int Draw::font_to_fontno(Font font)
|
||||||
{
|
{
|
||||||
switch (font)
|
switch (font)
|
||||||
|
|
@ -265,6 +295,9 @@ int Draw::font_to_fontno(Font font)
|
||||||
case Font::kTimer:
|
case Font::kTimer:
|
||||||
return TIMER_FONT;
|
return TIMER_FONT;
|
||||||
|
|
||||||
|
case Font::kThinTimer:
|
||||||
|
return TINYTIMER_FONT;
|
||||||
|
|
||||||
case Font::kMenu:
|
case Font::kMenu:
|
||||||
return MENU_FONT;
|
return MENU_FONT;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ public:
|
||||||
kZVote,
|
kZVote,
|
||||||
kPing,
|
kPing,
|
||||||
kTimer,
|
kTimer,
|
||||||
|
kThinTimer,
|
||||||
kMenu,
|
kMenu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -171,7 +172,7 @@ public:
|
||||||
TextElement text() const { return TextElement().font(font_).flags(flags_); }
|
TextElement text() const { return TextElement().font(font_).flags(flags_); }
|
||||||
|
|
||||||
void patch(patch_t* patch) const;
|
void patch(patch_t* patch) const;
|
||||||
void patch(const char* name) const;
|
void patch(const char* name) const { patch(Draw::cache_patch(name)); }
|
||||||
|
|
||||||
void thumbnail(UINT16 mapnum) const;
|
void thumbnail(UINT16 mapnum) const;
|
||||||
|
|
||||||
|
|
@ -180,6 +181,10 @@ public:
|
||||||
void button(Button type, std::optional<bool> press = {}) const { button_(type, 0, press); }
|
void button(Button type, std::optional<bool> press = {}) const { button_(type, 0, press); }
|
||||||
void small_button(Button type, std::optional<bool> press = {}) const { button_(type, 1, press); }
|
void small_button(Button type, std::optional<bool> press = {}) const { button_(type, 1, press); }
|
||||||
|
|
||||||
|
void sticker(patch_t* end_graphic, UINT8 color) const;
|
||||||
|
void sticker() const { sticker(Draw::cache_patch("K_STIKEN"), 24); }
|
||||||
|
void small_sticker() const { sticker(Draw::cache_patch("K_STIKE2"), 24); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr Chain() {}
|
constexpr Chain() {}
|
||||||
explicit Chain(float x, float y) : x_(x), y_(y) {}
|
explicit Chain(float x, float y) : x_(x), y_(y) {}
|
||||||
|
|
@ -217,6 +222,8 @@ public:
|
||||||
friend Draw;
|
friend Draw;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static patch_t* cache_patch(const char* name);
|
||||||
|
|
||||||
constexpr Draw() {}
|
constexpr Draw() {}
|
||||||
explicit Draw(float x, float y) : chain_(x, y) {}
|
explicit Draw(float x, float y) : chain_(x, y) {}
|
||||||
Draw(const Chain& chain) : chain_(chain) {}
|
Draw(const Chain& chain) : chain_(chain) {}
|
||||||
|
|
@ -259,6 +266,8 @@ public:
|
||||||
VOID_METHOD(fill);
|
VOID_METHOD(fill);
|
||||||
VOID_METHOD(button);
|
VOID_METHOD(button);
|
||||||
VOID_METHOD(small_button);
|
VOID_METHOD(small_button);
|
||||||
|
VOID_METHOD(sticker);
|
||||||
|
VOID_METHOD(small_sticker);
|
||||||
|
|
||||||
#undef VOID_METHOD
|
#undef VOID_METHOD
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2273,6 +2273,7 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TINY_FONT:
|
case TINY_FONT:
|
||||||
|
case TINYTIMER_FONT:
|
||||||
result->spacew = 2;
|
result->spacew = 2;
|
||||||
switch (spacing)
|
switch (spacing)
|
||||||
{
|
{
|
||||||
|
|
@ -2331,6 +2332,7 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result)
|
||||||
case HU_FONT:
|
case HU_FONT:
|
||||||
case MENU_FONT:
|
case MENU_FONT:
|
||||||
case TINY_FONT:
|
case TINY_FONT:
|
||||||
|
case TINYTIMER_FONT:
|
||||||
case KART_FONT:
|
case KART_FONT:
|
||||||
result->lfh = 12;
|
result->lfh = 12;
|
||||||
break;
|
break;
|
||||||
|
|
@ -2381,6 +2383,7 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result)
|
||||||
result->dim_fn = BunchedCharacterDim;
|
result->dim_fn = BunchedCharacterDim;
|
||||||
break;
|
break;
|
||||||
case TINY_FONT:
|
case TINY_FONT:
|
||||||
|
case TINYTIMER_FONT:
|
||||||
if (result->chw)
|
if (result->chw)
|
||||||
result->dim_fn = FixedCharacterDim;
|
result->dim_fn = FixedCharacterDim;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue