mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'splitscreen-timer' into 'master'
Splitscreen level timer HUD See merge request KartKrew/Kart!1309
This commit is contained in:
commit
da2e745bf7
34 changed files with 1124 additions and 98 deletions
|
|
@ -581,6 +581,7 @@ add_subdirectory(menus)
|
|||
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
|
||||
add_subdirectory(media)
|
||||
endif()
|
||||
add_subdirectory(hud)
|
||||
|
||||
# strip debug symbols into separate file when using gcc.
|
||||
# to be consistent with Makefile, don't generate for OS X.
|
||||
|
|
|
|||
|
|
@ -189,6 +189,9 @@ typedef enum
|
|||
POWERUP_BUMPER,
|
||||
POWERUP_BADGE,
|
||||
POWERUP_SUPERFLICKY,
|
||||
ENDOFPOWERUPS,
|
||||
LASTPOWERUP = ENDOFPOWERUPS - 1,
|
||||
NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP,
|
||||
} kartitems_t;
|
||||
|
||||
typedef enum
|
||||
|
|
@ -463,6 +466,9 @@ typedef struct {
|
|||
|
||||
// player_t struct for power-ups
|
||||
struct powerupvars_t {
|
||||
UINT16 superTimer;
|
||||
UINT16 barrierTimer;
|
||||
UINT16 rhythmBadgeTimer;
|
||||
mobj_t *flickyController;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4586,6 +4586,14 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_GACHABOM_RETURNING",
|
||||
|
||||
"S_SUPER_FLICKY",
|
||||
|
||||
"S_BATTLEUFO",
|
||||
"S_BATTLEUFO_LEG",
|
||||
"S_BATTLEUFO_DIE",
|
||||
"S_BATTLEUFO_BEAM1",
|
||||
"S_BATTLEUFO_BEAM2",
|
||||
|
||||
"S_POWERUP_AURA",
|
||||
};
|
||||
|
||||
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
|
||||
|
|
@ -5351,7 +5359,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_MONITOR_PART",
|
||||
"MT_MONITOR_SHARD",
|
||||
"MT_MAGICIANBOX",
|
||||
|
||||
|
||||
"MT_SLIPTIDEZIP",
|
||||
|
||||
"MT_INSTAWHIP",
|
||||
|
|
@ -5534,7 +5542,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
|
||||
"MT_POWERCLASH", // Invinc/Grow no damage clash VFX
|
||||
"MT_GUARDBREAK", // Guard break
|
||||
|
||||
|
||||
"MT_PLAYERARROW",
|
||||
"MT_PLAYERWANTED",
|
||||
|
||||
|
|
@ -5717,6 +5725,13 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
|
||||
"MT_SUPER_FLICKY",
|
||||
"MT_SUPER_FLICKY_CONTROLLER",
|
||||
|
||||
"MT_BATTLEUFO_SPAWNER",
|
||||
"MT_BATTLEUFO",
|
||||
"MT_BATTLEUFO_LEG",
|
||||
"MT_BATTLEUFO_BEAM",
|
||||
|
||||
"MT_POWERUP_AURA",
|
||||
};
|
||||
|
||||
const char *const MOBJFLAG_LIST[] = {
|
||||
|
|
@ -6160,7 +6175,7 @@ const char *COLOR_ENUMS[] = {
|
|||
"POSNUM_BEST4",
|
||||
"POSNUM_BEST5",
|
||||
"POSNUM_BEST6",
|
||||
|
||||
|
||||
"INTERMISSION",
|
||||
};
|
||||
|
||||
|
|
@ -6880,6 +6895,9 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"POWERUP_BUMPER",POWERUP_BUMPER},
|
||||
{"POWERUP_BADGE",POWERUP_BADGE},
|
||||
{"POWERUP_SUPERFLICKY",POWERUP_SUPERFLICKY},
|
||||
{"ENDOFPOWERUPS",ENDOFPOWERUPS},
|
||||
{"LASTPOWERUP",LASTPOWERUP},
|
||||
{"NUMPOWERUPS",NUMPOWERUPS},
|
||||
|
||||
// kartshields_t
|
||||
{"KSHIELD_NONE",KSHIELD_NONE},
|
||||
|
|
|
|||
4
src/hud/CMakeLists.txt
Normal file
4
src/hud/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
target_sources(SRB2SDL2 PRIVATE
|
||||
powerup.cpp
|
||||
timer.cpp
|
||||
)
|
||||
133
src/hud/powerup.cpp
Normal file
133
src/hud/powerup.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "../core/static_vec.hpp"
|
||||
|
||||
#include "../doomstat.h"
|
||||
#include "../g_game.h"
|
||||
#include "../k_hud.h"
|
||||
#include "../k_powerup.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_fps.h"
|
||||
#include "../v_draw.hpp"
|
||||
|
||||
using srb2::Draw;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Icon
|
||||
{
|
||||
kartitems_t powerup;
|
||||
tic_t time;
|
||||
|
||||
Icon() {}
|
||||
|
||||
explicit Icon(int k) :
|
||||
powerup(static_cast<kartitems_t>(k)),
|
||||
time(K_PowerUpRemaining(stplyr, powerup))
|
||||
{
|
||||
}
|
||||
|
||||
int letter() const { return 'A' + (powerup - FIRSTPOWERUP); }
|
||||
|
||||
bool operator <(const Icon& b) const { return time < b.time; }
|
||||
bool operator >(const Icon& b) const { return time > b.time; }
|
||||
};
|
||||
|
||||
srb2::StaticVec<Icon, NUMPOWERUPS> get_powerup_list(bool ascending)
|
||||
{
|
||||
srb2::StaticVec<Icon, NUMPOWERUPS> v;
|
||||
|
||||
for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k)
|
||||
{
|
||||
Icon ico(k);
|
||||
|
||||
if (ico.time)
|
||||
{
|
||||
v.push_back(ico);
|
||||
}
|
||||
}
|
||||
|
||||
if (ascending)
|
||||
{
|
||||
std::sort(v.begin(), v.end(), std::less<Icon>());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::sort(v.begin(), v.end(), std::greater<Icon>());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
void K_drawKartPowerUps(void)
|
||||
{
|
||||
struct Offsets
|
||||
{
|
||||
Draw row;
|
||||
const char* sprite;
|
||||
int spr_x;
|
||||
int spr_y;
|
||||
int shift_x;
|
||||
int dir;
|
||||
};
|
||||
|
||||
auto make_offsets = []() -> Offsets
|
||||
{
|
||||
auto make_drawer = [](int x, int y, Draw::Font font) -> Draw
|
||||
{
|
||||
return Draw(x, y).font(font).align(Draw::Align::kRight);
|
||||
};
|
||||
|
||||
const int viewnum = R_GetViewNumber();
|
||||
|
||||
// 1/2P
|
||||
switch (r_splitscreen)
|
||||
{
|
||||
case 0:
|
||||
return { make_drawer(307, 55, Draw::Font::kZVote), "PWRU", -17, 7, -35, -1 };
|
||||
|
||||
case 1:
|
||||
return { make_drawer(318, viewnum == 0 ? 55 : 155, Draw::Font::kPing), "PWRS", -9, 6, -19, -1 };
|
||||
}
|
||||
|
||||
// 3/4P
|
||||
int x = 21;
|
||||
int y = 47;
|
||||
|
||||
int dir = 1;
|
||||
|
||||
switch (viewnum)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
x = 318;
|
||||
dir = -1;
|
||||
}
|
||||
|
||||
switch (viewnum)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
y += 100;
|
||||
}
|
||||
|
||||
return { make_drawer(x, y, Draw::Font::kPing), "PWRS", -9, 5, 19 * dir, dir };
|
||||
};
|
||||
|
||||
Offsets i = make_offsets();
|
||||
|
||||
for (const Icon& ico : get_powerup_list(i.dir == -1))
|
||||
{
|
||||
i.row.xy(i.spr_x, i.spr_y)
|
||||
.colormap(static_cast<skincolornum_t>(stplyr->skincolor))
|
||||
.patch(fmt::format("{0}{1:c}L{1:c}R", i.sprite, ico.letter()).c_str());
|
||||
i.row.text("{}", (ico.time + (TICRATE / 2)) / TICRATE);
|
||||
i.row = i.row.x(i.shift_x);
|
||||
}
|
||||
}
|
||||
57
src/hud/timer.cpp
Normal file
57
src/hud/timer.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "../doomstat.h"
|
||||
#include "../g_game.h"
|
||||
#include "../k_hud.h"
|
||||
#include "../p_local.h"
|
||||
#include "../v_draw.hpp"
|
||||
|
||||
using srb2::Draw;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr INT32 kHudFlags = V_HUDTRANS | V_SLIDEIN;
|
||||
|
||||
tic_t player_timer(const player_t* player)
|
||||
{
|
||||
return K_TranslateTimer(player->realtime, 0, nullptr);
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
void K_drawKart2PTimestamp(void)
|
||||
{
|
||||
auto get_row = []
|
||||
{
|
||||
if (stplyr == &players[displayplayers[0]])
|
||||
{
|
||||
return Draw(286, 31).flags(V_SNAPTOTOP);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Draw(286, 163).flags(V_SNAPTOBOTTOM);
|
||||
}
|
||||
};
|
||||
|
||||
Draw row = get_row().flags(kHudFlags | V_SNAPTORIGHT).font(Draw::Font::kZVote);
|
||||
|
||||
row.patch("K_STTIMS");
|
||||
row.xy(12, 2).text("{:03}", player_timer(stplyr) / TICRATE);
|
||||
}
|
||||
|
||||
void K_drawKart4PTimestamp(void)
|
||||
{
|
||||
Draw row = Draw(154, 0).flags(kHudFlags).font(Draw::Font::kZVote).align(Draw::Align::kCenter);
|
||||
|
||||
auto draw = [](const Draw& row, tic_t time)
|
||||
{
|
||||
row.patch("K_STTIMS");
|
||||
row.xy(5, 12).text("{:03}", time / TICRATE);
|
||||
};
|
||||
|
||||
auto time_of = [](int k) -> tic_t { return k <= r_splitscreen ? player_timer(&players[displayplayers[k]]) : 0u; };
|
||||
|
||||
draw(row.y(1).flags(V_SNAPTOTOP), std::max(time_of(0), time_of(1)));
|
||||
draw(row.y(178).flags(V_SNAPTOBOTTOM), std::max(time_of(2), time_of(3)));
|
||||
}
|
||||
151
src/info.c
151
src/info.c
|
|
@ -652,6 +652,7 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"ITMI",
|
||||
"ITMN",
|
||||
"PWRB",
|
||||
"RBOW", // power-up aura
|
||||
"WANT",
|
||||
|
||||
"PBOM", // player bomb
|
||||
|
|
@ -821,6 +822,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
|
||||
"3DFR",
|
||||
|
||||
"BUFO", // Battle/Power-UP UFO
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
"VIEW",
|
||||
};
|
||||
|
|
@ -5256,6 +5259,15 @@ state_t states[NUMSTATES] =
|
|||
{SPR_GBOM, FF_INVERT, -1, {A_SetScale}, FRACUNIT/2, 1, S_NULL}, // S_GACHABOM_RETURNING
|
||||
|
||||
{SPR_3DFR, 1|FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_SUPER_FLICKY
|
||||
|
||||
// Battle/Power-UP UFO
|
||||
{SPR_BUFO, 0, -1, {A_SetScale}, 3*FRACUNIT/2 , 0, S_NULL}, // S_BATTLEUFO
|
||||
{SPR_BUFO, 1, -1, {A_SetScale}, 2*FRACUNIT/2, 0, S_NULL}, // S_BATTLEUFO_LEG
|
||||
{SPR_BUFO, 0, 4, {A_BossScream}, 0, MT_EXPLODE, S_BATTLEUFO_DIE}, // S_BATTLEUFO_DIE
|
||||
{SPR_DEZL, 1|FF_ANIMATE|FF_FULLBRIGHT, 15, {NULL}, 2, 5, S_BATTLEUFO_BEAM2}, // S_BATTLEUFO_BEAM1
|
||||
{SPR_DEZL, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEUFO_BEAM2
|
||||
|
||||
{SPR_RBOW, FF_PAPERSPRITE|FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_POWERUP_AURA
|
||||
};
|
||||
|
||||
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||
|
|
@ -22871,7 +22883,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
||||
{ // MT_SIGNSPARKLE
|
||||
-1, // doomednum
|
||||
S_SIGNSPARK1, // spawnstate
|
||||
|
|
@ -29896,6 +29908,141 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO_SPAWNER
|
||||
3786, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
55*FRACUNIT, // radius
|
||||
95*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO
|
||||
-1, // doomednum
|
||||
S_BATTLEUFO, // spawnstate
|
||||
1, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_BATTLEUFO_DIE, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_cdfm19, // deathsound
|
||||
0, // speed
|
||||
60*FRACUNIT, // radius
|
||||
104*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO_LEG
|
||||
-1, // doomednum
|
||||
S_BATTLEUFO_LEG, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
-4*FRACUNIT, // speed
|
||||
64*FRACUNIT, // radius
|
||||
55*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO_BEAM
|
||||
-1, // doomednum
|
||||
S_BATTLEUFO_BEAM1, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
-(FRACUNIT/2), // speed
|
||||
64*FRACUNIT, // radius
|
||||
55*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIP|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_POWERUP_AURA
|
||||
-1, // doomednum
|
||||
S_POWERUP_AURA, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
16*FRACUNIT, // radius
|
||||
106*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
};
|
||||
|
||||
skincolor_t skincolors[MAXSKINCOLORS] = {
|
||||
|
|
@ -30080,7 +30227,7 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
|
|||
{"Position Best 4", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST4
|
||||
{"Position Best 5", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST5
|
||||
{"Position Best 6", {181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST6
|
||||
|
||||
|
||||
{"Intermission", {0,80,80,81,81,81,84,85,86,87,246,248,251,26,28,31}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_INTERMISSION
|
||||
};
|
||||
|
||||
|
|
|
|||
18
src/info.h
18
src/info.h
|
|
@ -1203,6 +1203,7 @@ typedef enum sprite
|
|||
SPR_ITMI,
|
||||
SPR_ITMN,
|
||||
SPR_PWRB,
|
||||
SPR_RBOW, // power-up aura
|
||||
SPR_WANT,
|
||||
|
||||
SPR_PBOM, // player bomb
|
||||
|
|
@ -1372,6 +1373,8 @@ typedef enum sprite
|
|||
|
||||
SPR_3DFR,
|
||||
|
||||
SPR_BUFO, // Battle/Power-UP UFO
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
SPR_VIEW,
|
||||
|
||||
|
|
@ -5687,6 +5690,14 @@ typedef enum state
|
|||
|
||||
S_SUPER_FLICKY,
|
||||
|
||||
S_BATTLEUFO,
|
||||
S_BATTLEUFO_LEG,
|
||||
S_BATTLEUFO_DIE,
|
||||
S_BATTLEUFO_BEAM1,
|
||||
S_BATTLEUFO_BEAM2,
|
||||
|
||||
S_POWERUP_AURA,
|
||||
|
||||
S_FIRSTFREESLOT,
|
||||
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
|
||||
NUMSTATES
|
||||
|
|
@ -6837,6 +6848,13 @@ typedef enum mobj_type
|
|||
MT_SUPER_FLICKY,
|
||||
MT_SUPER_FLICKY_CONTROLLER,
|
||||
|
||||
MT_BATTLEUFO_SPAWNER,
|
||||
MT_BATTLEUFO,
|
||||
MT_BATTLEUFO_LEG,
|
||||
MT_BATTLEUFO_BEAM,
|
||||
|
||||
MT_POWERUP_AURA,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
|
||||
NUMMOBJTYPES
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
// Battle overtime info
|
||||
struct battleovertime battleovertime;
|
||||
struct battleufo g_battleufo;
|
||||
|
||||
// Capsules mode enabled for this map?
|
||||
boolean battleprisons = false;
|
||||
|
|
@ -349,6 +350,11 @@ void K_RunPaperItemSpawners(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (leveltime == g_battleufo.due)
|
||||
{
|
||||
Obj_SpawnBattleUFOFromSpawner();
|
||||
}
|
||||
|
||||
if (!IsOnInterval(interval))
|
||||
{
|
||||
return;
|
||||
|
|
@ -411,7 +417,7 @@ void K_RunPaperItemSpawners(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
K_CreatePaperItem(
|
||||
K_FlingPaperItem(
|
||||
battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
0, 0
|
||||
|
|
@ -801,6 +807,9 @@ void K_BattleInit(boolean singleplayercontext)
|
|||
K_SpawnPlayerBattleBumpers(players+i);
|
||||
}
|
||||
}
|
||||
|
||||
g_battleufo.due = starttime;
|
||||
g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID();
|
||||
}
|
||||
|
||||
UINT8 K_Bumpers(player_t *player)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ extern "C" {
|
|||
#define BATTLE_SPAWN_INTERVAL (4*TICRATE)
|
||||
#define BATTLE_DESPAWN_TIME (15*TICRATE)
|
||||
#define BATTLE_POWERUP_TIME (20*TICRATE)
|
||||
#define BATTLE_UFO_TIME (25*TICRATE)
|
||||
|
||||
#define BATTLE_MONITOR_SPAWN_LIMIT (3)
|
||||
|
||||
|
|
@ -21,6 +22,12 @@ extern struct battleovertime
|
|||
fixed_t x, y, z; ///< Position to center on
|
||||
} battleovertime;
|
||||
|
||||
extern struct battleufo
|
||||
{
|
||||
INT32 previousId;
|
||||
tic_t due;
|
||||
} g_battleufo;
|
||||
|
||||
extern boolean battleprisons;
|
||||
extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items
|
||||
extern UINT8 maptargets, numtargets;
|
||||
|
|
|
|||
|
|
@ -920,11 +920,12 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
|||
|| victim->type == MT_BANANA || victim->type == MT_EGGMANITEM || victim->type == MT_BALLHOG
|
||||
|| victim->type == MT_SSMINE || victim->type == MT_LANDMINE || victim->type == MT_SINK
|
||||
|| victim->type == MT_GARDENTOP || victim->type == MT_DROPTARGET || victim->type == MT_BATTLECAPSULE
|
||||
|| victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO)
|
||||
|| victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO || victim->type == MT_BATTLEUFO)
|
||||
{
|
||||
// Monitor hack. We can hit monitors once per instawhip, no multihit shredding!
|
||||
// Damage values in Obj_MonitorGetDamage.
|
||||
if (victim->type == MT_MONITOR)
|
||||
// Apply to UFO also -- steelt 29062023
|
||||
if (victim->type == MT_MONITOR || victim->type == MT_BATTLEUFO)
|
||||
{
|
||||
if (shield->extravalue1 == 1)
|
||||
return false;
|
||||
|
|
|
|||
63
src/k_hud.c
63
src/k_hud.c
|
|
@ -83,6 +83,7 @@ static patch_t *kp_wouldyoustillcatchmeifiwereaworm;
|
|||
static patch_t *kp_catcherminimap;
|
||||
static patch_t *kp_emeraldminimap[2];
|
||||
static patch_t *kp_capsuleminimap[3];
|
||||
static patch_t *kp_battleufominimap;
|
||||
|
||||
static patch_t *kp_ringsticker[2];
|
||||
static patch_t *kp_ringstickersplit[4];
|
||||
|
|
@ -372,6 +373,8 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_capsuleminimap[1], "MINICAP2");
|
||||
HU_UpdatePatch(&kp_capsuleminimap[2], "MINICAP3");
|
||||
|
||||
HU_UpdatePatch(&kp_battleufominimap, "MINIBUFO");
|
||||
|
||||
// Rings & Lives
|
||||
HU_UpdatePatch(&kp_ringsticker[0], "RNGBACKA");
|
||||
HU_UpdatePatch(&kp_ringsticker[1], "RNGBACKB");
|
||||
|
|
@ -1684,12 +1687,8 @@ static void K_drawKartSlotMachine(void)
|
|||
V_ClearClipRect();
|
||||
}
|
||||
|
||||
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode)
|
||||
tic_t K_TranslateTimer(tic_t drawtime, UINT8 mode, INT32 *return_jitter)
|
||||
{
|
||||
// TIME_X = BASEVIDWIDTH-124; // 196
|
||||
// TIME_Y = 6; // 6
|
||||
|
||||
tic_t worktime;
|
||||
INT32 jitter = 0;
|
||||
|
||||
if (!mode)
|
||||
|
|
@ -1725,6 +1724,24 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U
|
|||
}
|
||||
}
|
||||
|
||||
if (return_jitter)
|
||||
{
|
||||
*return_jitter = jitter;
|
||||
}
|
||||
|
||||
return drawtime;
|
||||
}
|
||||
|
||||
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode)
|
||||
{
|
||||
// TIME_X = BASEVIDWIDTH-124; // 196
|
||||
// TIME_Y = 6; // 6
|
||||
|
||||
tic_t worktime;
|
||||
INT32 jitter = 0;
|
||||
|
||||
drawtime = K_TranslateTimer(drawtime, mode, &jitter);
|
||||
|
||||
V_DrawScaledPatch(TX, TY, splitflags, ((mode == 2) ? kp_lapstickerwide : kp_timestickerwide));
|
||||
|
||||
TX += 33;
|
||||
|
|
@ -3998,6 +4015,9 @@ static void K_drawKartMinimap(void)
|
|||
if (battleprisons)
|
||||
workingPic = kp_capsuleminimap[2];
|
||||
break;
|
||||
case MT_BATTLEUFO:
|
||||
workingPic = kp_battleufominimap;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5294,7 +5314,6 @@ void K_drawKartHUD(void)
|
|||
boolean islonesome = false;
|
||||
boolean battlefullscreen = false;
|
||||
boolean freecam = demo.freecam; //disable some hud elements w/ freecam
|
||||
UINT8 i;
|
||||
UINT8 viewnum = R_GetViewNumber();
|
||||
|
||||
// Define the X and Y for each drawn object
|
||||
|
|
@ -5376,27 +5395,19 @@ void K_drawKartHUD(void)
|
|||
|
||||
islonesome = K_drawKartPositionFaces();
|
||||
}
|
||||
else if (viewnum == r_splitscreen
|
||||
&& (gametyperules & GTR_TIMELIMIT)
|
||||
&& timelimitintics > 0)
|
||||
else if (r_splitscreen == 1)
|
||||
{
|
||||
tic_t highestrealtime = players[displayplayers[1]].realtime;
|
||||
|
||||
// Uses the highest time across all players (handles paused timer on exiting)
|
||||
for (i = 1; i <= r_splitscreen; i++)
|
||||
{
|
||||
if (players[displayplayers[i]].realtime <= highestrealtime)
|
||||
continue;
|
||||
highestrealtime = players[displayplayers[i]].realtime;
|
||||
}
|
||||
|
||||
// Draw the timestamp (mostly) CENTERED
|
||||
if (LUA_HudEnabled(hud_time))
|
||||
K_drawKartTimestamp(highestrealtime,
|
||||
(r_splitscreen == 1 ? TIME_X : ((BASEVIDWIDTH/2) - 69)),
|
||||
TIME_Y,
|
||||
V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP|(r_splitscreen == 1 ? V_SNAPTORIGHT : 0),
|
||||
0);
|
||||
{
|
||||
K_drawKart2PTimestamp();
|
||||
}
|
||||
}
|
||||
else if (viewnum == r_splitscreen)
|
||||
{
|
||||
if (LUA_HudEnabled(hud_time))
|
||||
{
|
||||
K_drawKart4PTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
if (!stplyr->spectator && !demo.freecam) // Bottom of the screen elements, don't need in spectate mode
|
||||
|
|
@ -5530,6 +5541,8 @@ void K_drawKartHUD(void)
|
|||
K_drawMiniPing();
|
||||
}
|
||||
|
||||
K_drawKartPowerUps();
|
||||
|
||||
if (G_IsPartyLocal(displayplayers[viewnum]) == false && !demo.playback)
|
||||
{
|
||||
K_drawDirectorHUD();
|
||||
|
|
|
|||
|
|
@ -36,11 +36,16 @@ struct trackingResult_t
|
|||
|
||||
void K_ObjectTracking(trackingResult_t *result, const vector3_t *point, boolean reverse);
|
||||
|
||||
tic_t K_TranslateTimer(tic_t drawtime, UINT8 mode, INT32 *return_jitter);
|
||||
|
||||
const char *K_GetItemPatch(UINT8 item, boolean tiny);
|
||||
void K_LoadKartHUDGraphics(void);
|
||||
void K_drawKartHUD(void);
|
||||
void K_drawKartFreePlay(void);
|
||||
void K_drawKartPowerUps(void);
|
||||
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, UINT8 mode);
|
||||
void K_drawKart2PTimestamp(void);
|
||||
void K_drawKart4PTimestamp(void);
|
||||
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_drawTargetHUD(const vector3_t *origin, player_t *player);
|
||||
|
|
|
|||
124
src/k_kart.c
124
src/k_kart.c
|
|
@ -45,6 +45,7 @@
|
|||
#include "k_specialstage.h"
|
||||
#include "k_roulette.h"
|
||||
#include "k_podium.h"
|
||||
#include "k_powerup.h"
|
||||
|
||||
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
|
||||
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
|
||||
|
|
@ -4482,19 +4483,12 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source)
|
|||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
}
|
||||
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
||||
void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount)
|
||||
{
|
||||
const UINT8 oldPlayerBumpers = K_Bumpers(player);
|
||||
|
||||
UINT8 tookBumpers = 0;
|
||||
|
||||
amount = min(amount, K_Bumpers(victim));
|
||||
|
||||
if (amount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (tookBumpers < amount)
|
||||
{
|
||||
const UINT8 newbumper = (oldPlayerBumpers + tookBumpers);
|
||||
|
|
@ -4520,11 +4514,15 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
|||
newmo = P_SpawnMobj(newx, newy, player->mo->z, MT_BATTLEBUMPER);
|
||||
newmo->threshold = newbumper;
|
||||
|
||||
P_SetTarget(&newmo->tracer, victim->mo);
|
||||
if (victim)
|
||||
{
|
||||
P_SetTarget(&newmo->tracer, victim->mo);
|
||||
}
|
||||
|
||||
P_SetTarget(&newmo->target, player->mo);
|
||||
|
||||
newmo->angle = (diff * (newbumper-1));
|
||||
newmo->color = victim->skincolor;
|
||||
newmo->color = (victim ? victim : player)->skincolor;
|
||||
|
||||
if (newbumper+1 < 2)
|
||||
{
|
||||
|
|
@ -4544,6 +4542,18 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
|||
|
||||
// :jartcookiedance:
|
||||
player->mo->health += tookBumpers;
|
||||
}
|
||||
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount)
|
||||
{
|
||||
amount = min(amount, K_Bumpers(victim));
|
||||
|
||||
if (amount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
K_GiveBumpersToPlayer(player, victim, amount);
|
||||
|
||||
// Play steal sound
|
||||
S_StartSound(player->mo, sfx_3db06);
|
||||
|
|
@ -6603,13 +6613,6 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
drop->destscale = (3*drop->destscale)/2;
|
||||
|
||||
drop->angle = angle;
|
||||
P_Thrust(drop,
|
||||
FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle,
|
||||
16*mapobjectscale);
|
||||
|
||||
drop->momz = flip * 3 * mapobjectscale;
|
||||
if (drop->eflags & MFE_UNDERWATER)
|
||||
drop->momz = (117 * drop->momz) / 200;
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
|
|
@ -6655,6 +6658,21 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
return drop;
|
||||
}
|
||||
|
||||
mobj_t *K_FlingPaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount)
|
||||
{
|
||||
mobj_t *drop = K_CreatePaperItem(x, y, z, angle, flip, type, amount);
|
||||
|
||||
P_Thrust(drop,
|
||||
FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle,
|
||||
16*mapobjectscale);
|
||||
|
||||
drop->momz = flip * 3 * mapobjectscale;
|
||||
if (drop->eflags & MFE_UNDERWATER)
|
||||
drop->momz = (117 * drop->momz) / 200;
|
||||
|
||||
return drop;
|
||||
}
|
||||
|
||||
void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount)
|
||||
{
|
||||
if (!player->mo || P_MobjWasRemoved(player->mo))
|
||||
|
|
@ -6662,7 +6680,7 @@ void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount)
|
|||
return;
|
||||
}
|
||||
|
||||
mobj_t *drop = K_CreatePaperItem(
|
||||
mobj_t *drop = K_FlingPaperItem(
|
||||
player->mo->x, player->mo->y, player->mo->z + player->mo->height/2,
|
||||
player->mo->angle + ANGLE_90, P_MobjFlip(player->mo),
|
||||
itemtype, itemamount
|
||||
|
|
@ -7997,7 +8015,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->spheredigestion = spheredigestion;
|
||||
}
|
||||
|
||||
if (K_PlayerGuard(player) && (player->ebrakefor%6 == 0))
|
||||
if (K_PlayerGuard(player) && !K_PowerUpRemaining(player, POWERUP_BARRIER) && (player->ebrakefor%6 == 0))
|
||||
player->spheres--;
|
||||
}
|
||||
else
|
||||
|
|
@ -8090,6 +8108,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
if (player->powerup.rhythmBadgeTimer > 0)
|
||||
{
|
||||
player->instaShieldCooldown = min(player->instaShieldCooldown, 1);
|
||||
player->powerup.rhythmBadgeTimer--;
|
||||
}
|
||||
|
||||
if (player->powerup.barrierTimer > 0)
|
||||
{
|
||||
player->powerup.barrierTimer--;
|
||||
}
|
||||
|
||||
if (player->powerup.superTimer > 0)
|
||||
{
|
||||
player->powerup.superTimer--;
|
||||
}
|
||||
|
||||
if (player->guardCooldown)
|
||||
player->guardCooldown--;
|
||||
|
||||
|
|
@ -8334,7 +8368,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->pflags &= ~PF_DRIFTINPUT;
|
||||
}
|
||||
|
||||
if (K_PlayerGuard(player))
|
||||
if (K_PlayerGuard(player) && !K_PowerUpRemaining(player, POWERUP_BARRIER))
|
||||
player->instaShieldCooldown = max(player->instaShieldCooldown, INSTAWHIP_DROPGUARD);
|
||||
|
||||
// Roulette Code
|
||||
|
|
@ -10057,7 +10091,17 @@ boolean K_PlayerEBrake(player_t *player)
|
|||
|
||||
boolean K_PlayerGuard(player_t *player)
|
||||
{
|
||||
return (K_PlayerEBrake(player) && player->spheres > 0 && player->guardCooldown == 0);
|
||||
if (player->guardCooldown != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (K_PowerUpRemaining(player, POWERUP_BARRIER))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return (K_PlayerEBrake(player) && player->spheres > 0);
|
||||
}
|
||||
|
||||
SINT8 K_Sliptiding(player_t *player)
|
||||
|
|
@ -10101,26 +10145,6 @@ void K_KartEbrakeVisuals(player_t *p)
|
|||
if (!S_SoundPlaying(p->mo, sfx_s3kd9s))
|
||||
S_ReducedVFXSound(p->mo, sfx_s3kd9s, p);
|
||||
|
||||
// Block visuals
|
||||
// (These objects track whether a player is block-eligible on their own, no worries)
|
||||
if (!p->ebrakefor)
|
||||
{
|
||||
mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING);
|
||||
P_SetTarget(&ring->target, p->mo);
|
||||
P_SetScale(ring, p->mo->scale);
|
||||
K_MatchGenericExtraFlags(ring, p->mo);
|
||||
ring->renderflags &= ~RF_DONTDRAW;
|
||||
|
||||
mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY);
|
||||
P_SetTarget(&body->target, p->mo);
|
||||
P_SetScale(body, p->mo->scale);
|
||||
K_MatchGenericExtraFlags(body, p->mo);
|
||||
body->renderflags |= RF_DONTDRAW;
|
||||
|
||||
if (K_PlayerGuard(p))
|
||||
S_StartSound(body, sfx_s1af);
|
||||
}
|
||||
|
||||
// HOLD! bubble.
|
||||
if (!p->ebrakefor)
|
||||
{
|
||||
|
|
@ -10864,7 +10888,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
else
|
||||
{
|
||||
player->instaShieldCooldown = INSTAWHIP_COOLDOWN;
|
||||
player->guardCooldown = INSTAWHIP_COOLDOWN;
|
||||
|
||||
if (!K_PowerUpRemaining(player, POWERUP_BARRIER))
|
||||
{
|
||||
player->guardCooldown = INSTAWHIP_COOLDOWN;
|
||||
}
|
||||
|
||||
S_StartSound(player->mo, sfx_iwhp);
|
||||
mobj_t *whip = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INSTAWHIP);
|
||||
P_SetTarget(&player->whip, whip);
|
||||
|
|
@ -10876,10 +10905,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->flashing = max(player->flashing, 12);
|
||||
player->mo->momz += 4*mapobjectscale;
|
||||
|
||||
// Spawn in triangle formation
|
||||
Obj_SpawnInstaWhipRecharge(player, 0);
|
||||
Obj_SpawnInstaWhipRecharge(player, ANGLE_120);
|
||||
Obj_SpawnInstaWhipRecharge(player, ANGLE_240);
|
||||
if (!K_PowerUpRemaining(player, POWERUP_BADGE))
|
||||
{
|
||||
// Spawn in triangle formation
|
||||
Obj_SpawnInstaWhipRecharge(player, 0);
|
||||
Obj_SpawnInstaWhipRecharge(player, ANGLE_120);
|
||||
Obj_SpawnInstaWhipRecharge(player, ANGLE_240);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ void K_UpdateStumbleIndicator(player_t *player);
|
|||
void K_UpdateSliptideZipIndicator(player_t *player);
|
||||
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
|
||||
void K_DebtStingPlayer(player_t *player, mobj_t *source);
|
||||
void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount);
|
||||
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
|
||||
void K_MineFlashScreen(mobj_t *source);
|
||||
void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay);
|
||||
|
|
@ -151,6 +152,7 @@ void K_KartUpdatePosition(player_t *player);
|
|||
void K_UpdateAllPlayerPositions(void);
|
||||
SINT8 K_GetTotallyRandomResult(UINT8 useodds);
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount);
|
||||
mobj_t *K_FlingPaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount);
|
||||
void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount);
|
||||
void K_PopPlayerShield(player_t *player);
|
||||
void K_DropItems(player_t *player);
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ void Obj_SpawnSuperFlickySwarm(player_t *owner, tic_t time);
|
|||
void Obj_SuperFlickyControllerThink(mobj_t *controller);
|
||||
void Obj_EndSuperFlickySwarm(mobj_t *controller);
|
||||
void Obj_ExtendSuperFlickySwarm(mobj_t *controller, tic_t time);
|
||||
tic_t Obj_SuperFlickySwarmTime(const mobj_t *controller);
|
||||
tic_t Obj_SuperFlickySwarmTime(mobj_t *controller);
|
||||
|
||||
/* Super Flicky */
|
||||
void Obj_SuperFlickyThink(mobj_t *flicky);
|
||||
|
|
@ -161,6 +161,22 @@ void Obj_SuperFlickyPlayerCollide(mobj_t *flicky, mobj_t *player);
|
|||
void Obj_SuperFlickyLanding(mobj_t *flicky);
|
||||
boolean Obj_IsSuperFlickyWhippable(const mobj_t *flicky);
|
||||
|
||||
/* Battle/Power-UP UFO */
|
||||
void Obj_BattleUFOLegThink(mobj_t *leg);
|
||||
void Obj_BattleUFOThink(mobj_t *ufo);
|
||||
void Obj_SpawnBattleUFOLegs(mobj_t *ufo);
|
||||
void Obj_BattleUFODeath(mobj_t *ufo);
|
||||
void Obj_LinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_SpawnBattleUFOFromSpawner(void);
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void);
|
||||
void Obj_ResetUFOSpawners(void);
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam);
|
||||
|
||||
/* Power-Up Aura */
|
||||
void Obj_SpawnPowerUpAura(player_t* player);
|
||||
void Obj_PowerUpAuraThink(mobj_t* mobj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup)
|
|||
{
|
||||
switch (powerup)
|
||||
{
|
||||
case POWERUP_SMONITOR:
|
||||
return player->powerup.superTimer;
|
||||
|
||||
case POWERUP_BARRIER:
|
||||
return player->powerup.barrierTimer;
|
||||
|
||||
case POWERUP_BADGE:
|
||||
return player->powerup.rhythmBadgeTimer;
|
||||
|
||||
case POWERUP_SUPERFLICKY:
|
||||
return Obj_SuperFlickySwarmTime(player->powerup.flickyController);
|
||||
|
||||
|
|
@ -16,10 +25,45 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup)
|
|||
}
|
||||
}
|
||||
|
||||
boolean K_AnyPowerUpRemaining(const player_t* player)
|
||||
{
|
||||
for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k)
|
||||
{
|
||||
if (K_PowerUpRemaining(player, static_cast<kartitems_t>(k)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
|
||||
{
|
||||
if (!K_AnyPowerUpRemaining(player))
|
||||
{
|
||||
Obj_SpawnPowerUpAura(player);
|
||||
}
|
||||
|
||||
switch (powerup)
|
||||
{
|
||||
case POWERUP_SMONITOR:
|
||||
K_DoInvincibility(player, time);
|
||||
player->powerup.superTimer += time;
|
||||
break;
|
||||
|
||||
case POWERUP_BARRIER:
|
||||
player->powerup.barrierTimer += time;
|
||||
break;
|
||||
|
||||
case POWERUP_BUMPER:
|
||||
K_GiveBumpersToPlayer(player, nullptr, 5);
|
||||
break;
|
||||
|
||||
case POWERUP_BADGE:
|
||||
player->powerup.rhythmBadgeTimer += time;
|
||||
break;
|
||||
|
||||
case POWERUP_SUPERFLICKY:
|
||||
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
|
||||
{
|
||||
|
|
@ -38,6 +82,21 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
|
|||
|
||||
void K_DropPowerUps(player_t* player)
|
||||
{
|
||||
auto simple_drop = [player](kartitems_t powerup, auto& timer)
|
||||
{
|
||||
tic_t remaining = K_PowerUpRemaining(player, powerup);
|
||||
|
||||
if (remaining)
|
||||
{
|
||||
K_DropPaperItem(player, powerup, remaining);
|
||||
timer = 0;
|
||||
}
|
||||
};
|
||||
|
||||
simple_drop(POWERUP_SMONITOR, player->powerup.superTimer);
|
||||
simple_drop(POWERUP_BARRIER, player->powerup.barrierTimer);
|
||||
simple_drop(POWERUP_BADGE, player->powerup.rhythmBadgeTimer);
|
||||
|
||||
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
|
||||
{
|
||||
mobj_t* swarm = player->powerup.flickyController;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
tic_t K_PowerUpRemaining(const player_t *player, kartitems_t powerup);
|
||||
boolean K_AnyPowerUpRemaining(const player_t *player);
|
||||
void K_GivePowerUp(player_t *player, kartitems_t powerup, tic_t timer);
|
||||
void K_DropPowerUps(player_t *player);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ typedef enum
|
|||
|
||||
PR_MOVINGTARGET, // Randomised moving targets
|
||||
|
||||
PR_BATTLEUFO, // Battle UFO spawning
|
||||
|
||||
PR_BOTS, // Bot spawning
|
||||
|
||||
PRNUMCLASS
|
||||
|
|
|
|||
|
|
@ -22,4 +22,6 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
gachabom-rebound.cpp
|
||||
servant-hand.c
|
||||
super-flicky.cpp
|
||||
battle-ufo.cpp
|
||||
powerup-aura.cpp
|
||||
)
|
||||
|
|
|
|||
241
src/objects/battle-ufo.cpp
Normal file
241
src/objects/battle-ufo.cpp
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../k_kart.h"
|
||||
|
||||
#define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body
|
||||
#define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn
|
||||
#define BATTLEUFO_BOB_AMP (4) // UFO bob strength
|
||||
#define BATTLEUFO_BOB_SPEED (TICRATE*2) // UFO bob speed
|
||||
|
||||
#define spawner_id(o) ((o)->args[0])
|
||||
|
||||
#define ufo_spawner(o) ((o)->target)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Spawner : mobj_t
|
||||
{
|
||||
INT32 id() const { return spawner_id(this); }
|
||||
};
|
||||
|
||||
struct UFO : mobj_t
|
||||
{
|
||||
Spawner* spawner() const { return static_cast<Spawner*>(ufo_spawner(this)); }
|
||||
void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); }
|
||||
void spawn_beam()
|
||||
{
|
||||
mobj_t *x;
|
||||
|
||||
x = P_SpawnMobjFromMobj(this, 0, 0, FixedDiv(this->height / 4, this->scale), MT_BATTLEUFO_BEAM);
|
||||
x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE;
|
||||
x->colorized = true;
|
||||
x->color = SKINCOLOR_SAPPHIRE;
|
||||
}
|
||||
};
|
||||
|
||||
struct SpawnerCompare
|
||||
{
|
||||
bool operator()(const Spawner* a, const Spawner* b) const
|
||||
{
|
||||
return a->id() < b->id();
|
||||
}
|
||||
};
|
||||
|
||||
class SpawnerList
|
||||
{
|
||||
private:
|
||||
std::set<Spawner*, SpawnerCompare> set_;
|
||||
|
||||
public:
|
||||
void insert(Spawner* spawner)
|
||||
{
|
||||
auto [it, inserted] = set_.insert(spawner);
|
||||
|
||||
if (inserted)
|
||||
{
|
||||
mobj_t* dummy = nullptr;
|
||||
P_SetTarget(&dummy, spawner);
|
||||
}
|
||||
}
|
||||
|
||||
void erase(Spawner* spawner)
|
||||
{
|
||||
if (set_.erase(spawner))
|
||||
{
|
||||
mobj_t* dummy = spawner;
|
||||
P_SetTarget(&dummy, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Spawner* next(INT32 order) const
|
||||
{
|
||||
auto it = std::upper_bound(
|
||||
set_.begin(),
|
||||
set_.end(),
|
||||
order,
|
||||
[](INT32 a, const Spawner* b) { return a < b->id(); }
|
||||
);
|
||||
|
||||
return it != set_.end() ? *it : *set_.begin();
|
||||
}
|
||||
|
||||
INT32 random_id() const
|
||||
{
|
||||
if (set_.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto it = set_.begin();
|
||||
|
||||
std::advance(it, P_RandomKey(PR_BATTLEUFO, set_.size()));
|
||||
|
||||
return (*std::prev(it == set_.begin() ? set_.end() : it))->id();
|
||||
}
|
||||
|
||||
void spawn_ufo() const
|
||||
{
|
||||
if (set_.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Spawner* spawner = next(g_battleufo.previousId);
|
||||
UFO* ufo = static_cast<UFO*>(P_SpawnMobjFromMobj(spawner, 0, 0, 250*FRACUNIT, MT_BATTLEUFO));
|
||||
|
||||
ufo->spawner(spawner);
|
||||
}
|
||||
};
|
||||
|
||||
SpawnerList g_spawners;
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_BattleUFOThink(mobj_t *mobj)
|
||||
{
|
||||
UFO* ufo = static_cast<UFO*>(mobj);
|
||||
|
||||
// Copied and slightly modified from k_kart.c
|
||||
fixed_t sine = FixedMul(ufo->scale, BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK));
|
||||
fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo);
|
||||
ufo->momz = targz;
|
||||
|
||||
if ((leveltime/2) & 1)
|
||||
{
|
||||
ufo->spawn_beam();
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_BattleUFODeath(mobj_t *mobj)
|
||||
{
|
||||
UFO* ufo = static_cast<UFO*>(mobj);
|
||||
const SINT8 flip = P_MobjFlip(ufo);
|
||||
|
||||
ufo->momz = -(8*mapobjectscale)/2;
|
||||
|
||||
K_CreatePaperItem(
|
||||
ufo->x,
|
||||
ufo->y,
|
||||
ufo->z + (flip),
|
||||
0,
|
||||
flip,
|
||||
P_RandomRange(PR_BATTLEUFO, FIRSTPOWERUP, LASTPOWERUP),
|
||||
BATTLE_POWERUP_TIME
|
||||
);
|
||||
|
||||
if (ufo->spawner())
|
||||
{
|
||||
g_battleufo.previousId = ufo->spawner()->id();
|
||||
g_battleufo.due = leveltime + BATTLE_UFO_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_SpawnBattleUFOLegs(mobj_t *ufo)
|
||||
{
|
||||
INT32 i;
|
||||
angle_t ang = 0;
|
||||
const fixed_t angle_factor = ANGLE_MAX / BATTLEUFO_LEGS;
|
||||
|
||||
for (i = 0; i < BATTLEUFO_LEGS; i++)
|
||||
{
|
||||
mobj_t *leg = P_SpawnMobjFromMobj(ufo, 0, 0, BATTLEUFO_LEG_ZOFFS, MT_BATTLEUFO_LEG);
|
||||
P_SetTarget(&leg->target, ufo);
|
||||
ang += angle_factor;
|
||||
leg->angle = ang;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_BattleUFOLegThink(mobj_t *leg)
|
||||
{
|
||||
if (!leg->target || P_MobjWasRemoved(leg->target))
|
||||
{
|
||||
P_RemoveMobj(leg);
|
||||
return;
|
||||
}
|
||||
|
||||
// Rotate around the UFO
|
||||
if (leg->target->health > 0)
|
||||
{
|
||||
leg->angle += FixedAngle(leg->info->speed);
|
||||
|
||||
const angle_t fa = leg->angle>>ANGLETOFINESHIFT;
|
||||
const fixed_t radius = FixedMul(14*leg->info->speed, leg->target->scale);
|
||||
fixed_t x = leg->target->x + FixedMul(FINECOSINE(fa),radius);
|
||||
fixed_t y = leg->target->y + FixedMul(FINESINE(fa),radius);
|
||||
|
||||
// TODO: Take gravflip into account
|
||||
P_MoveOrigin(leg, x, y, leg->z);
|
||||
}
|
||||
|
||||
leg->momz = leg->target->momz;
|
||||
leg->fuse = leg->target->fuse;
|
||||
|
||||
if (leg->target->hitlag)
|
||||
{
|
||||
leg->hitlag = leg->target->hitlag;
|
||||
leg->eflags |= (leg->target->eflags & MFE_DAMAGEHITLAG);
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_LinkBattleUFOSpawner(mobj_t *spawner)
|
||||
{
|
||||
g_spawners.insert(static_cast<Spawner*>(spawner));
|
||||
}
|
||||
|
||||
void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner)
|
||||
{
|
||||
g_spawners.erase(static_cast<Spawner*>(spawner));
|
||||
}
|
||||
|
||||
void Obj_SpawnBattleUFOFromSpawner(void)
|
||||
{
|
||||
g_spawners.spawn_ufo();
|
||||
}
|
||||
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void)
|
||||
{
|
||||
return g_spawners.random_id();
|
||||
}
|
||||
|
||||
void Obj_ResetUFOSpawners(void)
|
||||
{
|
||||
g_spawners = {};
|
||||
}
|
||||
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam)
|
||||
{
|
||||
P_SetObjectMomZ(beam, beam->info->speed, true);
|
||||
|
||||
if (P_IsObjectOnGround(beam))
|
||||
{
|
||||
P_RemoveMobj(beam);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,10 +3,16 @@
|
|||
#include "../k_objects.h"
|
||||
#include "../p_local.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_powerup.h"
|
||||
|
||||
static INT16 guard_upscale (player_t *player)
|
||||
{
|
||||
return K_PowerUpRemaining(player, POWERUP_BARRIER) ? 40 : player->spheres;
|
||||
}
|
||||
|
||||
void Obj_BlockRingThink (mobj_t *ring)
|
||||
{
|
||||
if (P_MobjWasRemoved(ring->target) || !ring->target->player || !ring->target->player->ebrakefor)
|
||||
if (P_MobjWasRemoved(ring->target) || !ring->target->player)
|
||||
{
|
||||
P_RemoveMobj(ring);
|
||||
}
|
||||
|
|
@ -22,7 +28,7 @@ void Obj_BlockRingThink (mobj_t *ring)
|
|||
ring->color = mo->color;
|
||||
|
||||
fixed_t baseScale = mo->scale / 2;
|
||||
baseScale += (mo->scale / 30) * player->spheres;
|
||||
baseScale += (mo->scale / 30) * guard_upscale(player);
|
||||
P_SetScale(ring, baseScale);
|
||||
|
||||
// Twirl
|
||||
|
|
@ -42,7 +48,7 @@ void Obj_BlockRingThink (mobj_t *ring)
|
|||
|
||||
void Obj_BlockBodyThink (mobj_t *body)
|
||||
{
|
||||
if (P_MobjWasRemoved(body->target) || !body->target->player || !body->target->player->ebrakefor)
|
||||
if (P_MobjWasRemoved(body->target) || !body->target->player)
|
||||
{
|
||||
P_RemoveMobj(body);
|
||||
}
|
||||
|
|
@ -55,7 +61,7 @@ void Obj_BlockBodyThink (mobj_t *body)
|
|||
body->flags &= ~(MF_NOCLIPTHING);
|
||||
|
||||
fixed_t baseScale = mo->scale / 2;
|
||||
baseScale += (mo->scale / 30) * player->spheres;
|
||||
baseScale += (mo->scale / 30) * guard_upscale(player);
|
||||
P_SetScale(body, baseScale);
|
||||
|
||||
P_MoveOrigin(body, mo->x, mo->y, mo->z + mo->height/2);
|
||||
|
|
|
|||
|
|
@ -668,13 +668,13 @@ Obj_MonitorOnDeath (mobj_t *monitor)
|
|||
const UINT32 localseed = restore_item_rng(sharedseed);
|
||||
|
||||
adjust_monitor_drop(monitor,
|
||||
K_CreatePaperItem(
|
||||
K_FlingPaperItem(
|
||||
monitor->x, monitor->y, monitor->z + (128 * mapobjectscale * flip),
|
||||
i * ang, flip,
|
||||
K_ItemResultToType(result),
|
||||
K_ItemResultToAmount(result)));
|
||||
|
||||
// K_CreatePaperItem may advance RNG, so update our
|
||||
// K_FlingPaperItem may advance RNG, so update our
|
||||
// copy of the seed afterward
|
||||
sharedseed = restore_item_rng(localseed);
|
||||
}
|
||||
|
|
|
|||
121
src/objects/powerup-aura.cpp
Normal file
121
src/objects/powerup-aura.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#include "../info.h"
|
||||
#include "../g_game.h"
|
||||
#include "../m_fixed.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../k_powerup.h"
|
||||
#include "../p_local.h"
|
||||
#include "../p_mobj.h"
|
||||
#include "../tables.h"
|
||||
|
||||
// copied from objects/monitor.c
|
||||
#define FINE90 (FINEANGLES/4)
|
||||
#define FINE180 (FINEANGLES/2)
|
||||
#define TRUETAN(n) FINETANGENT(FINE90 + (n)) // bruh
|
||||
|
||||
#define part_theta(o) ((o)->movedir)
|
||||
#define part_seek(o) ((o)->extravalue1)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr int kSpriteWidth = 32;
|
||||
constexpr int kNumSides = 6;
|
||||
|
||||
struct Aura : mobj_t
|
||||
{
|
||||
angle_t theta() const { return part_theta(this); }
|
||||
void theta(angle_t n) { part_theta(this) = n; }
|
||||
|
||||
unsigned seek() const { return part_seek(this); }
|
||||
void seek(unsigned n) { part_seek(this) = n; }
|
||||
|
||||
mobj_t* origin() const { return players[seek()].mo; }
|
||||
|
||||
static void spawn(int player)
|
||||
{
|
||||
const fixed_t angle_factor = ANGLE_MAX / kNumSides;
|
||||
|
||||
angle_t ang = 0u;
|
||||
|
||||
for (int i = 0; i < kNumSides; ++i)
|
||||
{
|
||||
Aura* x = static_cast<Aura*>(P_SpawnMobj(0, 0, 0, MT_POWERUP_AURA));
|
||||
|
||||
x->theta(ang);
|
||||
x->seek(player);
|
||||
|
||||
ang += angle_factor;
|
||||
}
|
||||
}
|
||||
|
||||
// copied from objects/monitor.c
|
||||
static fixed_t get_inradius(fixed_t length)
|
||||
{
|
||||
return FixedDiv(length, 2 * TRUETAN(FINE180 / kNumSides));
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
if (seek() >= MAXPLAYERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!playeringame[seek()])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!K_AnyPowerUpRemaining(&players[seek()]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void move()
|
||||
{
|
||||
if (P_MobjWasRemoved(origin()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
P_MoveOrigin(this, origin()->x, origin()->y, origin()->z);
|
||||
P_InstaScale(this, 11 * origin()->scale / 10);
|
||||
|
||||
translate();
|
||||
}
|
||||
|
||||
void translate()
|
||||
{
|
||||
const fixed_t width = scale * kSpriteWidth;
|
||||
const fixed_t rad = get_inradius(width);
|
||||
const angle_t ang = theta() + origin()->angle;
|
||||
|
||||
angle = (ang - ANGLE_90);
|
||||
|
||||
sprxoff = FixedMul(FCOS(ang), rad);
|
||||
spryoff = FixedMul(FSIN(ang), rad);
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_SpawnPowerUpAura(player_t* player)
|
||||
{
|
||||
Aura::spawn(player - players);
|
||||
}
|
||||
|
||||
void Obj_PowerUpAuraThink(mobj_t* mobj)
|
||||
{
|
||||
Aura* x = static_cast<Aura*>(mobj);
|
||||
|
||||
if (!x->valid())
|
||||
{
|
||||
P_RemoveMobj(x);
|
||||
return;
|
||||
}
|
||||
|
||||
x->move();
|
||||
}
|
||||
|
|
@ -141,7 +141,7 @@ struct Controller : mobj_t
|
|||
x->source(player->mo);
|
||||
x->mode(Mode::kDescend);
|
||||
x->zofs(0);
|
||||
x->expiry(leveltime + time);
|
||||
x->expiry(leveltime + time + kRiseTime);
|
||||
|
||||
P_SetTarget(&player->powerup.flickyController, x);
|
||||
|
||||
|
|
@ -754,16 +754,16 @@ void Obj_ExtendSuperFlickySwarm(mobj_t* mobj, tic_t time)
|
|||
x->expiry(x->expiry() + time);
|
||||
}
|
||||
|
||||
tic_t Obj_SuperFlickySwarmTime(const mobj_t* mobj)
|
||||
tic_t Obj_SuperFlickySwarmTime(mobj_t* mobj)
|
||||
{
|
||||
const Controller* x = static_cast<const Controller*>(mobj);
|
||||
Controller* x = static_cast<Controller*>(mobj);
|
||||
|
||||
return x ? x->powerup_remaining() : 0u;
|
||||
return !P_MobjWasRemoved(x) ? x->powerup_remaining() : 0u;
|
||||
}
|
||||
|
||||
boolean Obj_IsSuperFlickyWhippable(const mobj_t* mobj)
|
||||
{
|
||||
const Flicky* x = static_cast<const Flicky*>(mobj);
|
||||
|
||||
return !x->stunned();
|
||||
return mobj == x->chasing() && !x->stunned();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ void P_CheckTimeLimit(void)
|
|||
{
|
||||
if (((timelimitintics + starttime - leveltime) % TICRATE) == 0)
|
||||
S_StartSound(NULL, sfx_s3ka7);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1725,7 +1725,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
case MT_MONITOR:
|
||||
Obj_MonitorOnDeath(target);
|
||||
break;
|
||||
|
||||
case MT_BATTLEUFO:
|
||||
Obj_BattleUFODeath(target);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -2418,7 +2420,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
// Extend the invincibility if the hit was a direct hit.
|
||||
if (inflictor == source && source->player->invincibilitytimer)
|
||||
if (inflictor == source && source->player->invincibilitytimer &&
|
||||
!K_PowerUpRemaining(player, POWERUP_SMONITOR))
|
||||
{
|
||||
tic_t kinvextend;
|
||||
|
||||
|
|
|
|||
21
src/p_map.c
21
src/p_map.c
|
|
@ -753,6 +753,27 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->type == MT_BATTLEUFO)
|
||||
{
|
||||
if (tm.thing->type != MT_PLAYER)
|
||||
{
|
||||
return BMIT_CONTINUE; // not a player
|
||||
}
|
||||
|
||||
if (thing->health <= 0)
|
||||
{
|
||||
return BMIT_CONTINUE; // dead
|
||||
}
|
||||
|
||||
if (tm.thing->z > thing->z + thing->height)
|
||||
{
|
||||
return BMIT_CONTINUE; // overhead
|
||||
}
|
||||
|
||||
P_SetObjectMomZ(tm.thing, FRACUNIT, true);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->type == MT_SPB)
|
||||
{
|
||||
if (tm.thing->type != MT_PLAYER
|
||||
|
|
|
|||
73
src/p_mobj.c
73
src/p_mobj.c
|
|
@ -5331,6 +5331,7 @@ static boolean P_IsTrackerType(INT32 type)
|
|||
case MT_OVERTIME_CENTER:
|
||||
case MT_MONITOR:
|
||||
case MT_EMERALD:
|
||||
case MT_BATTLEUFO:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
|
@ -6698,6 +6699,14 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
case MT_SUPER_FLICKY_CONTROLLER:
|
||||
Obj_SuperFlickyControllerThink(mobj);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MT_POWERUP_AURA:
|
||||
Obj_PowerUpAuraThink(mobj);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return;
|
||||
|
|
@ -6943,6 +6952,14 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
|
|||
Obj_UFOPieceDead(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO:
|
||||
{
|
||||
if (P_IsObjectOnGround(mobj) && mobj->fuse == 0)
|
||||
{
|
||||
mobj->fuse = TICRATE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -8061,7 +8078,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
// cusval: responsible for disappear FX (should only happen once)
|
||||
|
||||
// S_MAGICANBOX: sides, starting angle is set in the spawner (SetRandomFakePlayerSkin)
|
||||
// S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets
|
||||
// S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets
|
||||
|
||||
mobj->extravalue2--;
|
||||
|
||||
|
|
@ -8428,6 +8445,21 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
Obj_ItemDebrisThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO:
|
||||
{
|
||||
Obj_BattleUFOThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_LEG:
|
||||
{
|
||||
Obj_BattleUFOLegThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_BEAM:
|
||||
{
|
||||
Obj_BattleUFOBeamThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_ROCKETSNEAKER:
|
||||
if (!mobj->target || !mobj->target->health)
|
||||
{
|
||||
|
|
@ -9649,6 +9681,8 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
|||
case MT_SNAPPER_LEG:
|
||||
case MT_MINECARTSEG:
|
||||
case MT_MONITOR_PART:
|
||||
case MT_BATTLEUFO:
|
||||
case MT_BATTLEUFO_LEG:
|
||||
return true;
|
||||
|
||||
case MT_RANDOMITEM:
|
||||
|
|
@ -10303,6 +10337,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
|
|||
case MT_KART_LEFTOVER:
|
||||
case MT_BATTLECAPSULE:
|
||||
case MT_SPECIAL_UFO:
|
||||
case MT_CDUFO:
|
||||
case MT_BATTLEUFO:
|
||||
thing->shadowscale = FRACUNIT;
|
||||
break;
|
||||
case MT_SMALLMACE:
|
||||
|
|
@ -10912,6 +10948,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
case MT_SPHEREBOX:
|
||||
Obj_RandomItemSpawn(mobj);
|
||||
break;
|
||||
case MT_BATTLEUFO:
|
||||
Obj_SpawnBattleUFOLegs(mobj);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -11154,6 +11193,11 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
Obj_RingShooterDelete(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_SPAWNER:
|
||||
{
|
||||
Obj_UnlinkBattleUFOSpawner(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
|
@ -11866,6 +11910,26 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
}
|
||||
}
|
||||
|
||||
// Block visuals
|
||||
// (These objects track whether a player is block-eligible on their own, no worries)
|
||||
if (!p->spectator)
|
||||
{
|
||||
mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING);
|
||||
P_SetTarget(&ring->target, p->mo);
|
||||
P_SetScale(ring, p->mo->scale);
|
||||
K_MatchGenericExtraFlags(ring, p->mo);
|
||||
ring->renderflags &= ~RF_DONTDRAW;
|
||||
|
||||
mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY);
|
||||
P_SetTarget(&body->target, p->mo);
|
||||
P_SetScale(body, p->mo->scale);
|
||||
K_MatchGenericExtraFlags(body, p->mo);
|
||||
body->renderflags |= RF_DONTDRAW;
|
||||
|
||||
if (K_PlayerGuard(p))
|
||||
S_StartSound(body, sfx_s1af);
|
||||
}
|
||||
|
||||
// I'm not refactoring the loop at the top of this file.
|
||||
pcount = 0;
|
||||
|
||||
|
|
@ -12240,7 +12304,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
|
|||
|
||||
if ((i == MT_RANDOMITEM) && (gametyperules & (GTR_PAPERITEMS|GTR_CIRCUIT)) == (GTR_PAPERITEMS|GTR_CIRCUIT))
|
||||
return MT_PAPERITEMSPOT;
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
@ -13401,6 +13465,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
|
|||
Obj_InitLoopCenter(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_SPAWNER:
|
||||
{
|
||||
Obj_LinkBattleUFOSpawner(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -634,6 +634,11 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
// ACS has read access to this, so it has to be net-communicated.
|
||||
// It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way.
|
||||
WRITEUINT32(save->p, players[i].roundconditions.unlocktriggers);
|
||||
|
||||
// powerupvars_t
|
||||
WRITEUINT16(save->p, players[i].powerup.superTimer);
|
||||
WRITEUINT16(save->p, players[i].powerup.barrierTimer);
|
||||
WRITEUINT16(save->p, players[i].powerup.rhythmBadgeTimer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1059,6 +1064,11 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
// It is the ONLY roundcondition that is sent over the wire and I'd like it to stay that way.
|
||||
players[i].roundconditions.unlocktriggers = READUINT32(save->p);
|
||||
|
||||
// powerupvars_t
|
||||
players[i].powerup.superTimer = READUINT16(save->p);
|
||||
players[i].powerup.barrierTimer = READUINT16(save->p);
|
||||
players[i].powerup.rhythmBadgeTimer = READUINT16(save->p);
|
||||
|
||||
//players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point
|
||||
}
|
||||
}
|
||||
|
|
@ -5728,6 +5738,10 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
|
|||
WRITEFIXED(save->p, battleovertime.y);
|
||||
WRITEFIXED(save->p, battleovertime.z);
|
||||
|
||||
// battleufo_t
|
||||
WRITEINT32(save->p, g_battleufo.previousId);
|
||||
WRITEUINT32(save->p, g_battleufo.due);
|
||||
|
||||
WRITEUINT32(save->p, wantedcalcdelay);
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
WRITEUINT32(save->p, itemCooldowns[i]);
|
||||
|
|
@ -5898,6 +5912,10 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
|
|||
battleovertime.y = READFIXED(save->p);
|
||||
battleovertime.z = READFIXED(save->p);
|
||||
|
||||
// battleufo_t
|
||||
g_battleufo.previousId = READINT32(save->p);
|
||||
g_battleufo.due = READUINT32(save->p);
|
||||
|
||||
wantedcalcdelay = READUINT32(save->p);
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
itemCooldowns[i] = READUINT32(save->p);
|
||||
|
|
|
|||
|
|
@ -7145,6 +7145,9 @@ static void P_ConvertBinaryThingTypes(void)
|
|||
case 2018: // MT_PETSMOKER
|
||||
mapthings[i].args[0] = !!(mapthings[i].options & MTF_OBJECTSPECIAL);
|
||||
break;
|
||||
case 3786: // MT_BATTLEUFO_SPAWNER
|
||||
mapthings[i].args[0] = mapthings[i].angle;
|
||||
break;
|
||||
case FLOOR_SLOPE_THING:
|
||||
case CEILING_SLOPE_THING:
|
||||
mapthings[i].args[0] = mapthings[i].extrainfo;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "k_director.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "acs/interface.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
#ifdef PARANOIA
|
||||
#include "deh_tables.h" // MOBJTYPE_LIST
|
||||
|
|
@ -230,6 +231,8 @@ void P_InitThinkers(void)
|
|||
{
|
||||
skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL;
|
||||
}
|
||||
|
||||
Obj_ResetUFOSpawners();
|
||||
}
|
||||
|
||||
// Adds a new thinker at the end of the list.
|
||||
|
|
|
|||
|
|
@ -115,6 +115,12 @@ int Draw::font_to_fontno(Font font)
|
|||
|
||||
case Font::kFreeplay:
|
||||
return KART_FONT;
|
||||
|
||||
case Font::kZVote:
|
||||
return OPPRF_FONT;
|
||||
|
||||
case Font::kPing:
|
||||
return PINGF_FONT;
|
||||
}
|
||||
|
||||
return TINY_FONT;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ public:
|
|||
kGamemode,
|
||||
kConsole,
|
||||
kFreeplay,
|
||||
kZVote,
|
||||
kPing,
|
||||
};
|
||||
|
||||
enum class Align
|
||||
|
|
|
|||
|
|
@ -2416,7 +2416,7 @@ void V_DrawStringScaled(
|
|||
if (chw)
|
||||
dim_fn = FixedCharacterDim;
|
||||
else
|
||||
dim_fn = VariableCharacterDim;
|
||||
dim_fn = BunchedCharacterDim;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2696,7 +2696,7 @@ fixed_t V_StringScaledWidth(
|
|||
if (chw)
|
||||
dim_fn = FixedCharacterDim;
|
||||
else
|
||||
dim_fn = VariableCharacterDim;
|
||||
dim_fn = BunchedCharacterDim;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue