mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'destroy-kart' into 'master'
Destroyed Kart effects Closes #1146 See merge request KartKrew/Kart!2196
This commit is contained in:
commit
531e4ccd4a
13 changed files with 681 additions and 148 deletions
|
|
@ -370,6 +370,13 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
||||||
"S_KART_TIRE1",
|
"S_KART_TIRE1",
|
||||||
"S_KART_TIRE2",
|
"S_KART_TIRE2",
|
||||||
|
|
||||||
|
"S_KART_FIRE",
|
||||||
|
"S_KART_SMOKE",
|
||||||
|
|
||||||
|
"S_KART_XPL01",
|
||||||
|
"S_KART_XPL02",
|
||||||
|
"S_KART_XPL03",
|
||||||
|
|
||||||
// Boss Explosion
|
// Boss Explosion
|
||||||
"S_BOSSEXPLODE",
|
"S_BOSSEXPLODE",
|
||||||
|
|
||||||
|
|
@ -3061,6 +3068,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
||||||
"MT_PLAYER",
|
"MT_PLAYER",
|
||||||
"MT_KART_LEFTOVER",
|
"MT_KART_LEFTOVER",
|
||||||
"MT_KART_TIRE",
|
"MT_KART_TIRE",
|
||||||
|
"MT_KART_PARTICLE",
|
||||||
|
|
||||||
// Generic Boss Items
|
// Generic Boss Items
|
||||||
"MT_BOSSEXPLODE",
|
"MT_BOSSEXPLODE",
|
||||||
|
|
|
||||||
60
src/info.c
60
src/info.c
|
|
@ -746,6 +746,22 @@ char sprnames[NUMSPRITES + 1][5] =
|
||||||
// Tutorial
|
// Tutorial
|
||||||
"TLKP", // Talk Point
|
"TLKP", // Talk Point
|
||||||
|
|
||||||
|
// Destroyed Kart
|
||||||
|
"DIEA", // tire
|
||||||
|
"DIEB", // pipeframe bar
|
||||||
|
"DIEC", // pedal tip
|
||||||
|
"DIED", // right pedal
|
||||||
|
"DIEE", // steering wheel
|
||||||
|
"DIEF", // kart
|
||||||
|
"DIEG", // left pedal
|
||||||
|
"DIEH", // strut
|
||||||
|
"DIEI", // wheel axle bar
|
||||||
|
"DIEJ", // screw
|
||||||
|
"DIEK", // electric engine
|
||||||
|
"DIEL", // fire
|
||||||
|
"DIEM", // smoke
|
||||||
|
"DIEN", // explosion
|
||||||
|
|
||||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||||
"VIEW",
|
"VIEW",
|
||||||
};
|
};
|
||||||
|
|
@ -873,18 +889,25 @@ state_t states[NUMSTATES] =
|
||||||
{SPR_PLAY, SPR2_DRRO, 1, {NULL}, 0, 0, S_KART_DRIFT_R_OUT}, // S_KART_DRIFT_R_OUT
|
{SPR_PLAY, SPR2_DRRO, 1, {NULL}, 0, 0, S_KART_DRIFT_R_OUT}, // S_KART_DRIFT_R_OUT
|
||||||
{SPR_PLAY, SPR2_DRRI, 1, {NULL}, 0, 0, S_KART_DRIFT_R_IN}, // S_KART_DRIFT_R_IN
|
{SPR_PLAY, SPR2_DRRI, 1, {NULL}, 0, 0, S_KART_DRIFT_R_IN}, // S_KART_DRIFT_R_IN
|
||||||
{SPR_PLAY, SPR2_SPIN|FF_ANIMATE, 350, {NULL}, 0, 1, S_KART_STILL}, // S_KART_SPINOUT
|
{SPR_PLAY, SPR2_SPIN|FF_ANIMATE, 350, {NULL}, 0, 1, S_KART_STILL}, // S_KART_SPINOUT
|
||||||
{SPR_PLAY, SPR2_DEAD, 3, {NULL}, 0, 0, S_KART_DEAD}, // S_KART_DEAD
|
{SPR_PLAY, SPR2_DEAD|FF_SEMIBRIGHT, 3, {NULL}, 0, 0, S_KART_DEAD}, // S_KART_DEAD
|
||||||
{SPR_PLAY, SPR2_SIGN|FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 0, 1, 0}, // S_KART_SIGN
|
{SPR_PLAY, SPR2_SIGN|FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 0, 1, 0}, // S_KART_SIGN
|
||||||
{SPR_PLAY, SPR2_SIGL|FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 0, 1, 0}, // S_KART_SIGL
|
{SPR_PLAY, SPR2_SIGL|FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 0, 1, 0}, // S_KART_SIGL
|
||||||
|
|
||||||
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, // S_OBJPLACE_DUMMY
|
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, // S_OBJPLACE_DUMMY
|
||||||
|
|
||||||
{SPR_KART, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER
|
{SPR_KART, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER
|
||||||
{SPR_KART, 1, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER_NOTIRES
|
{SPR_DIEF, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER_NOTIRES
|
||||||
|
|
||||||
{SPR_TIRE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE1
|
{SPR_TIRE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE1
|
||||||
{SPR_TIRE, 1, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE2
|
{SPR_TIRE, 1, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE2
|
||||||
|
|
||||||
|
{SPR_DIEL, 0|FF_ANIMATE, 12, {NULL}, 11, 1, S_NULL}, // S_KART_FIRE
|
||||||
|
{SPR_DIEM, FF_SEMIBRIGHT|FF_ANIMATE|FF_TRANS30, 30, {NULL}, 9, 3, S_NULL}, // S_KART_SMOKE
|
||||||
|
|
||||||
|
{SPR_DIEN, 0|FF_PAPERSPRITE|FF_ADD, 3, {NULL}, 0, 0, S_KART_XPL02}, // S_KART_XPL01
|
||||||
|
{SPR_DIEN, 1|FF_PAPERSPRITE|FF_ADD|FF_ANIMATE, 4, {NULL}, 1, 2, S_KART_XPL03}, // S_KART_XPL02
|
||||||
|
{SPR_DIEN, 3|FF_PAPERSPRITE|FF_ADD|FF_ANIMATE, 10, {NULL}, 4, 2, S_NULL}, // S_KART_XPL03
|
||||||
|
|
||||||
// Boss Explosion
|
// Boss Explosion
|
||||||
{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE
|
{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE
|
||||||
|
|
||||||
|
|
@ -3722,7 +3745,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||||
sfx_None, // painsound
|
sfx_None, // painsound
|
||||||
S_NULL, // meleestate
|
S_NULL, // meleestate
|
||||||
S_NULL, // missilestate
|
S_NULL, // missilestate
|
||||||
S_KART_DEAD, // deathstate
|
S_KART_SPINOUT, // deathstate
|
||||||
S_NULL, // xdeathstate
|
S_NULL, // xdeathstate
|
||||||
sfx_None, // deathsound
|
sfx_None, // deathsound
|
||||||
1, // speed
|
1, // speed
|
||||||
|
|
@ -3738,13 +3761,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||||
|
|
||||||
{ // MT_KART_LEFTOVER
|
{ // MT_KART_LEFTOVER
|
||||||
4095, // doomednum
|
4095, // doomednum
|
||||||
S_KART_LEFTOVER, // spawnstate
|
S_KART_LEFTOVER_NOTIRES, // spawnstate
|
||||||
2, // spawnhealth
|
2, // spawnhealth
|
||||||
S_NULL, // seestate
|
S_NULL, // seestate
|
||||||
sfx_None, // seesound
|
sfx_None, // seesound
|
||||||
0, // reactiontime
|
0, // reactiontime
|
||||||
sfx_None, // attacksound
|
sfx_None, // attacksound
|
||||||
S_NULL, // painstate
|
S_KART_LEFTOVER_NOTIRES, // painstate
|
||||||
0, // painchance
|
0, // painchance
|
||||||
sfx_None, // painsound
|
sfx_None, // painsound
|
||||||
S_NULL, // meleestate
|
S_NULL, // meleestate
|
||||||
|
|
@ -3790,6 +3813,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||||
S_NULL // raisestate
|
S_NULL // raisestate
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ // MT_KART_PARTICLE
|
||||||
|
-1, // doomednum
|
||||||
|
S_INVISIBLE, // spawnstate
|
||||||
|
1, // 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
|
||||||
|
1, // speed
|
||||||
|
6*FRACUNIT, // radius
|
||||||
|
12*FRACUNIT, // height
|
||||||
|
-1, // display offset
|
||||||
|
1000, // mass
|
||||||
|
0, // damage
|
||||||
|
sfx_None, // activesound
|
||||||
|
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_DONTENCOREMAP|MF_NOSQUISH, // flags
|
||||||
|
S_NULL // raisestate
|
||||||
|
},
|
||||||
|
|
||||||
{ // MT_BOSSEXPLODE
|
{ // MT_BOSSEXPLODE
|
||||||
-1, // doomednum
|
-1, // doomednum
|
||||||
S_BOSSEXPLODE, // spawnstate
|
S_BOSSEXPLODE, // spawnstate
|
||||||
|
|
|
||||||
24
src/info.h
24
src/info.h
|
|
@ -1281,6 +1281,22 @@ typedef enum sprite
|
||||||
// Tutorial
|
// Tutorial
|
||||||
SPR_TLKP, // Talk Point
|
SPR_TLKP, // Talk Point
|
||||||
|
|
||||||
|
// Destroyed Kart
|
||||||
|
SPR_DIEA, // tire
|
||||||
|
SPR_DIEB, // pipeframe bar
|
||||||
|
SPR_DIEC, // pedal tip
|
||||||
|
SPR_DIED, // right pedal
|
||||||
|
SPR_DIEE, // steering wheel
|
||||||
|
SPR_DIEF, // kart
|
||||||
|
SPR_DIEG, // left pedal
|
||||||
|
SPR_DIEH, // strut
|
||||||
|
SPR_DIEI, // wheel axle bar
|
||||||
|
SPR_DIEJ, // screw
|
||||||
|
SPR_DIEK, // electric engine
|
||||||
|
SPR_DIEL, // fire
|
||||||
|
SPR_DIEM, // smoke
|
||||||
|
SPR_DIEN, // explosion
|
||||||
|
|
||||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||||
SPR_VIEW,
|
SPR_VIEW,
|
||||||
|
|
||||||
|
|
@ -1371,6 +1387,13 @@ typedef enum state
|
||||||
S_KART_TIRE1,
|
S_KART_TIRE1,
|
||||||
S_KART_TIRE2,
|
S_KART_TIRE2,
|
||||||
|
|
||||||
|
S_KART_FIRE,
|
||||||
|
S_KART_SMOKE,
|
||||||
|
|
||||||
|
S_KART_XPL01,
|
||||||
|
S_KART_XPL02,
|
||||||
|
S_KART_XPL03,
|
||||||
|
|
||||||
// Boss Explosion
|
// Boss Explosion
|
||||||
S_BOSSEXPLODE,
|
S_BOSSEXPLODE,
|
||||||
|
|
||||||
|
|
@ -4089,6 +4112,7 @@ typedef enum mobj_type
|
||||||
MT_PLAYER,
|
MT_PLAYER,
|
||||||
MT_KART_LEFTOVER,
|
MT_KART_LEFTOVER,
|
||||||
MT_KART_TIRE,
|
MT_KART_TIRE,
|
||||||
|
MT_KART_PARTICLE,
|
||||||
|
|
||||||
// Generic Boss Items
|
// Generic Boss Items
|
||||||
MT_BOSSEXPLODE,
|
MT_BOSSEXPLODE,
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ void Obj_DuelBombInit(mobj_t *bomb);
|
||||||
|
|
||||||
/* Broly Ki */
|
/* Broly Ki */
|
||||||
mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration);
|
mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration);
|
||||||
|
mobj_t *Obj_SpawnCustomBrolyKi(mobj_t *source, tic_t duration, fixed_t start, fixed_t end);
|
||||||
boolean Obj_BrolyKiThink(mobj_t *ki);
|
boolean Obj_BrolyKiThink(mobj_t *ki);
|
||||||
|
|
||||||
/* Special Stage UFO */
|
/* Special Stage UFO */
|
||||||
|
|
@ -417,6 +418,13 @@ void Obj_TalkPointOrbThink(mobj_t* mo);
|
||||||
void Obj_SpawnPowerUpSpinner(mobj_t *source, INT32 powerup, tic_t duration);
|
void Obj_SpawnPowerUpSpinner(mobj_t *source, INT32 powerup, tic_t duration);
|
||||||
void Obj_TickPowerUpSpinner(mobj_t *mobj);
|
void Obj_TickPowerUpSpinner(mobj_t *mobj);
|
||||||
|
|
||||||
|
/* Destroyed Kart */
|
||||||
|
void Obj_SpawnDestroyedKart(mobj_t *player);
|
||||||
|
void Obj_DestroyedKartThink(mobj_t *kart);
|
||||||
|
boolean Obj_DestroyKart(mobj_t *kart);
|
||||||
|
void Obj_DestroyedKartParticleThink(mobj_t *part);
|
||||||
|
void Obj_DestroyedKartParticleLanding(mobj_t *part);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// DR. ROBOTNIK'S RING RACERS
|
// DR. ROBOTNIK'S RING RACERS
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2023 by James Robert Roman
|
// Copyright (C) 2023-2024 by James Robert Roman
|
||||||
//
|
//
|
||||||
// This program is free software distributed under the
|
// This program is free software distributed under the
|
||||||
// terms of the GNU General Public License, version 2.
|
// terms of the GNU General Public License, version 2.
|
||||||
|
|
@ -157,7 +157,7 @@ struct Mobj : mobj_t
|
||||||
statenum_t num() const { return static_cast<statenum_t>(static_cast<const state_t*>(this) - states); }
|
statenum_t num() const { return static_cast<statenum_t>(static_cast<const state_t*>(this) - states); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void state(statenum_t state) { P_SetMobjState(this, state); }
|
void state(statenum_t state) { (player ? P_SetPlayerMobjState : P_SetMobjState)(this, state); }
|
||||||
const State* state() const { return static_cast<const State*>(mobj_t::state); }
|
const State* state() const { return static_cast<const State*>(mobj_t::state); }
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -276,6 +276,11 @@ struct Mobj : mobj_t
|
||||||
{
|
{
|
||||||
K_SetHitLagForObjects(this, inflictor, source, tics, damage);
|
K_SetHitLagForObjects(this, inflictor, source, tics, damage);
|
||||||
}
|
}
|
||||||
|
void exact_hitlag(INT32 tics, bool damage)
|
||||||
|
{
|
||||||
|
mobj_t::hitlag = tics;
|
||||||
|
mobj_t::eflags = (mobj_t::eflags & ~MFE_DAMAGEHITLAG) | (MFE_DAMAGEHITLAG * damage);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace srb2
|
}; // namespace srb2
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ target_sources(SRB2SDL2 PRIVATE
|
||||||
talk-point.cpp
|
talk-point.cpp
|
||||||
powerup-spinner.cpp
|
powerup-spinner.cpp
|
||||||
adventure-air-booster.c
|
adventure-air-booster.c
|
||||||
|
destroyed-kart.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(versus)
|
add_subdirectory(versus)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// DR. ROBOTNIK'S RING RACERS
|
// DR. ROBOTNIK'S RING RACERS
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2023 by James Robert Roman
|
// Copyright (C) 2023-2024 by James Robert Roman
|
||||||
//
|
//
|
||||||
// This program is free software distributed under the
|
// This program is free software distributed under the
|
||||||
// terms of the GNU General Public License, version 2.
|
// terms of the GNU General Public License, version 2.
|
||||||
|
|
@ -16,11 +16,13 @@
|
||||||
using namespace srb2::objects;
|
using namespace srb2::objects;
|
||||||
|
|
||||||
mobj_t *
|
mobj_t *
|
||||||
Obj_SpawnBrolyKi
|
Obj_SpawnCustomBrolyKi
|
||||||
( mobj_t * source,
|
( mobj_t * source,
|
||||||
tic_t duration)
|
tic_t duration,
|
||||||
|
fixed_t start,
|
||||||
|
fixed_t end)
|
||||||
{
|
{
|
||||||
Broly* x = Broly::spawn<Broly>(static_cast<Mobj*>(source), duration, {64 * mapobjectscale, 0});
|
Broly* x = Broly::spawn<Broly>(static_cast<Mobj*>(source), duration, {start, end});
|
||||||
|
|
||||||
if (!x)
|
if (!x)
|
||||||
{
|
{
|
||||||
|
|
@ -36,6 +38,14 @@ Obj_SpawnBrolyKi
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mobj_t *
|
||||||
|
Obj_SpawnBrolyKi
|
||||||
|
( mobj_t * source,
|
||||||
|
tic_t duration)
|
||||||
|
{
|
||||||
|
return Obj_SpawnCustomBrolyKi(source, duration, 64 * mapobjectscale, 0);
|
||||||
|
}
|
||||||
|
|
||||||
boolean
|
boolean
|
||||||
Obj_BrolyKiThink (mobj_t *x)
|
Obj_BrolyKiThink (mobj_t *x)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
511
src/objects/destroyed-kart.cpp
Normal file
511
src/objects/destroyed-kart.cpp
Normal file
|
|
@ -0,0 +1,511 @@
|
||||||
|
// DR. ROBOTNIK'S RING RACERS
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2024 by James Robert Roman.
|
||||||
|
// Copyright (C) 2024 by Kart Krew.
|
||||||
|
//
|
||||||
|
// This program is free software distributed under the
|
||||||
|
// terms of the GNU General Public License, version 2.
|
||||||
|
// See the 'LICENSE' file for more details.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "../cxxutil.hpp"
|
||||||
|
#include "objects.hpp"
|
||||||
|
|
||||||
|
#include "../m_easing.h"
|
||||||
|
#include "../m_random.h"
|
||||||
|
#include "../r_skins.h"
|
||||||
|
#include "../tables.h"
|
||||||
|
|
||||||
|
using namespace srb2::objects;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
Vec2<Fixed> angle_vector(angle_t x)
|
||||||
|
{
|
||||||
|
return Vec2<Fixed> {FCOS(x), FSIN(x)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void radial_generic(int ofs, int spokes, F&& f)
|
||||||
|
{
|
||||||
|
int ang = 360 / spokes;
|
||||||
|
for (int i = 0; i < spokes; ++i)
|
||||||
|
{
|
||||||
|
f((ofs + (ang * i)) % 360);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
angle_t degr_to_angle(int degr)
|
||||||
|
{
|
||||||
|
return FixedAngle(degr * FRACUNIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Particle : Mobj
|
||||||
|
{
|
||||||
|
void extravalue1() = delete;
|
||||||
|
UINT8 bounces() const { return mobj_t::extravalue1; }
|
||||||
|
void bounces(UINT8 n) { mobj_t::extravalue1 = n; }
|
||||||
|
|
||||||
|
void extravalue2() = delete;
|
||||||
|
UINT8 counter() const { return mobj_t::extravalue2; }
|
||||||
|
void counter(UINT8 n) { mobj_t::extravalue2 = n; }
|
||||||
|
|
||||||
|
bool is_shrapnel() const { return sprite == SPR_KRBM; }
|
||||||
|
|
||||||
|
static void spew(Mobj* source)
|
||||||
|
{
|
||||||
|
auto generic = [&](spritenum_t sprite, int degr, Fixed scale, int momx, const Vec2<int>& momz)
|
||||||
|
{
|
||||||
|
Particle* x = source->spawn_from<Particle>({}, MT_KART_PARTICLE);
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
x->sprite = sprite;
|
||||||
|
x->color = source->color;
|
||||||
|
x->frame = FF_SEMIBRIGHT;
|
||||||
|
x->lightlevel = 112;
|
||||||
|
x->scale(scale * x->scale());
|
||||||
|
|
||||||
|
x->instathrust(source->angle + degr_to_angle(degr), momx * mapobjectscale);
|
||||||
|
x->momz = P_RandomRange(PR_ITEM_DEBRIS, momz.x, momz.y) * mapobjectscale * 2;
|
||||||
|
|
||||||
|
x->angle = P_Random(PR_ITEM_DEBRIS);
|
||||||
|
x->rollangle = P_Random(PR_ITEM_DEBRIS);
|
||||||
|
|
||||||
|
x->renderflags |= RF_DONTDRAW;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto part = [&](spritenum_t sprite, int degr, Fixed scale)
|
||||||
|
{
|
||||||
|
return generic(sprite, degr, scale, 2, {8, 16});
|
||||||
|
};
|
||||||
|
|
||||||
|
auto radial = [&](spritenum_t sprite, int ofs, int spokes, Fixed scale)
|
||||||
|
{
|
||||||
|
radial_generic(ofs, spokes, [&](int ang) { part(sprite, ang, scale); });
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Fixed kSmall = 3*FRACUNIT/2;
|
||||||
|
constexpr Fixed kMedium = 7*FRACUNIT/4;
|
||||||
|
constexpr Fixed kLarge = 2*FRACUNIT;
|
||||||
|
|
||||||
|
part(SPR_DIEE, 0, kLarge); // steering wheel
|
||||||
|
part(SPR_DIEK, 180 + 45, kLarge); // engine
|
||||||
|
|
||||||
|
part(SPR_DIEG, 90, kLarge); // left pedal base
|
||||||
|
part(SPR_DIED, -90, kLarge); // right pedal base
|
||||||
|
|
||||||
|
radial(SPR_DIEI, 90, 2, kLarge); // wheel axle bars
|
||||||
|
radial(SPR_DIEC, 90, 2, kLarge); // pedal tips
|
||||||
|
radial(SPR_DIEA, 45, 4, kMedium); // tires
|
||||||
|
radial(SPR_DIEH, 45, 4, kMedium); // struts / springs
|
||||||
|
radial(SPR_DIEB, 360/12, 6, kSmall); // pipeframe bars
|
||||||
|
radial(SPR_DIEJ, 360/16, 8, kSmall); // screws
|
||||||
|
|
||||||
|
radial_generic(0, 6, [&](int degr) { generic(SPR_KRBM, degr, kSmall, 8, {22, 28}); }); // shrapnel
|
||||||
|
|
||||||
|
// explosion
|
||||||
|
radial_generic(
|
||||||
|
45, 4,
|
||||||
|
[&](int degr)
|
||||||
|
{
|
||||||
|
if (Mobj* x = source->spawn_from<Mobj>({0, 0, source->height}, MT_KART_PARTICLE))
|
||||||
|
{
|
||||||
|
x->flags |= MF_NOGRAVITY | MF_NOCLIPHEIGHT;
|
||||||
|
x->height = 0;
|
||||||
|
x->scale(2 * x->scale());
|
||||||
|
x->angle = degr_to_angle(degr);
|
||||||
|
x->state(S_KART_XPL01);
|
||||||
|
x->renderflags |= RF_REDUCEVFX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void think()
|
||||||
|
{
|
||||||
|
if (state()->num() == S_BRAKEDRIFT)
|
||||||
|
{
|
||||||
|
renderflags ^= RF_DONTDRAW;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// explosion
|
||||||
|
if (sprite == SPR_DIEN)
|
||||||
|
{
|
||||||
|
counter(counter() + 1);
|
||||||
|
if (counter() > 6)
|
||||||
|
{
|
||||||
|
renderflags ^= RF_DONTDRAW;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr tic_t kReappear = 16;
|
||||||
|
if (counter() < kReappear && !is_shrapnel())
|
||||||
|
{
|
||||||
|
counter(counter() + 1);
|
||||||
|
if (counter() == kReappear)
|
||||||
|
{
|
||||||
|
renderflags &= ~RF_DONTDRAW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
angle += ANGLE_11hh;
|
||||||
|
rollangle += ANGLE_11hh;
|
||||||
|
|
||||||
|
if (is_shrapnel() && leveltime % 2 == 0)
|
||||||
|
{
|
||||||
|
if (Mobj* x = spawn_from<Mobj>({}, MT_BOOMEXPLODE))
|
||||||
|
{
|
||||||
|
x->color = SKINCOLOR_RUBY;
|
||||||
|
x->scale_between(x->scale() / 2, x->scale() * 8, x->scale() / 16);
|
||||||
|
x->state(S_SLOWBOOM2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spritescale({FRACUNIT, FRACUNIT}); // unsquish
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_land()
|
||||||
|
{
|
||||||
|
if (!fuse)
|
||||||
|
{
|
||||||
|
fuse = (is_shrapnel() ? 70 : 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto squash = [&](int tics)
|
||||||
|
{
|
||||||
|
hitlag(tics);
|
||||||
|
spritescale({2*FRACUNIT, FRACUNIT/2}); // squish
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (sprite)
|
||||||
|
{
|
||||||
|
case SPR_DIEB: // bar
|
||||||
|
squash(2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPR_DIEH: // struts
|
||||||
|
squash(4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPR_DIEI: // screws
|
||||||
|
squash(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPR_DIEK: // engine
|
||||||
|
squash(5);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_shrapnel() && fuse > 7 && (bounces() & 1)) // 7 = 0.2/(1/35)
|
||||||
|
{
|
||||||
|
voice(
|
||||||
|
static_cast<sfxenum_t>(P_RandomRange(PR_ITEM_DEBRIS, sfx_die01, sfx_die03)),
|
||||||
|
P_RandomRange(PR_ITEM_DEBRIS, 20, 40) * 255 / 100
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bounces(bounces() + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Kart : Mobj
|
||||||
|
{
|
||||||
|
static constexpr tic_t kVibrateTimer = 70;
|
||||||
|
static constexpr UINT32 kNoClipFlags = MF_NOCLIP | MF_NOCLIPTHING;
|
||||||
|
|
||||||
|
static tic_t burn_duration() { return (gametyperules & GTR_CLOSERPLAYERS ? 10 : 20) * TICRATE; }
|
||||||
|
|
||||||
|
void extravalue1() = delete;
|
||||||
|
UINT8 weight() const { return mobj_t::extravalue1; }
|
||||||
|
void weight(UINT8 n) { mobj_t::extravalue1 = n; }
|
||||||
|
|
||||||
|
void extravalue2() = delete;
|
||||||
|
tic_t timer() const { return mobj_t::extravalue2; }
|
||||||
|
void timer(tic_t n) { mobj_t::extravalue2 = n; }
|
||||||
|
|
||||||
|
void threshold() = delete;
|
||||||
|
tic_t cooldown() const { return mobj_t::threshold; }
|
||||||
|
void cooldown(tic_t n) { mobj_t::threshold = n; }
|
||||||
|
|
||||||
|
void movecount() = delete;
|
||||||
|
tic_t burning() const { return mobj_t::movecount; }
|
||||||
|
void burning(tic_t n) { mobj_t::movecount = n; }
|
||||||
|
|
||||||
|
void target() = delete;
|
||||||
|
Mobj* player() const { return Mobj::target(); }
|
||||||
|
void player(Mobj* n) { Mobj::target(n); }
|
||||||
|
|
||||||
|
static void spawn(Mobj* target)
|
||||||
|
{
|
||||||
|
SRB2_ASSERT(target->player != nullptr);
|
||||||
|
|
||||||
|
Kart* kart = target->spawn_from<Kart>({}, MT_KART_LEFTOVER);
|
||||||
|
if (!kart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kart->angle = target->angle;
|
||||||
|
kart->color = target->color;
|
||||||
|
P_SetObjectMomZ(kart, 20*FRACUNIT, false);
|
||||||
|
kart->weight(target->player->kartweight);
|
||||||
|
kart->flags |= kNoClipFlags;
|
||||||
|
|
||||||
|
if (target->player->pflags & PF_NOCONTEST)
|
||||||
|
target->tracer(kart);
|
||||||
|
|
||||||
|
kart->state(S_INVISIBLE);
|
||||||
|
kart->timer(kVibrateTimer);
|
||||||
|
kart->exact_hitlag(15, true);
|
||||||
|
kart->player(target);
|
||||||
|
|
||||||
|
Obj_SpawnCustomBrolyKi(target, kart->hitlag() - 2, 32 * mapobjectscale, 0);
|
||||||
|
|
||||||
|
target->exact_hitlag(kart->hitlag() + 1, true);
|
||||||
|
target->frame |= FF_SEMIBRIGHT;
|
||||||
|
target->lightlevel = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
void think()
|
||||||
|
{
|
||||||
|
if (burning() > 0)
|
||||||
|
{
|
||||||
|
burning(burning() - 1);
|
||||||
|
fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cooldown() > 0)
|
||||||
|
{
|
||||||
|
cooldown(cooldown() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timer() > 0)
|
||||||
|
{
|
||||||
|
timer(timer() - 1);
|
||||||
|
animate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool destroy()
|
||||||
|
{
|
||||||
|
if (cooldown())
|
||||||
|
{
|
||||||
|
// no-op P_DamageMobj
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (health <= 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Particle::spew(this);
|
||||||
|
scale(3 * scale() / 2);
|
||||||
|
health = 1;
|
||||||
|
state(S_KART_LEFTOVER_NOTIRES);
|
||||||
|
cooldown(20);
|
||||||
|
burning(burn_duration());
|
||||||
|
|
||||||
|
if (!cv_reducevfx.value)
|
||||||
|
{
|
||||||
|
voice(sfx_die00);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Mobj* p = player(); Mobj::valid(p))
|
||||||
|
{
|
||||||
|
if (p->player && skins[p->player->skin].flags & SF_BADNIK)
|
||||||
|
{
|
||||||
|
P_SpawnBadnikExplosion(p);
|
||||||
|
p->spritescale({2*FRACUNIT, 2*FRACUNIT});
|
||||||
|
p->flags |= MF_NOSQUISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->state(S_KART_DEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void fire()
|
||||||
|
{
|
||||||
|
auto spread = [&](const Vec2<Fixed>& range, const Vec2<Fixed>& zrange)
|
||||||
|
{
|
||||||
|
angle_t ang = P_Random(PR_ITEM_DEBRIS);
|
||||||
|
Fixed r = P_RandomRange(PR_ITEM_DEBRIS, range.x, range.y) * mapobjectscale * 4;
|
||||||
|
Fixed z = P_RandomRange(PR_ITEM_DEBRIS, zrange.x, zrange.y) * mapobjectscale * 4;
|
||||||
|
return spawn_from<Mobj>({angle_vector(ang) * r, z}, MT_THOK);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto vfx = [&](fixed_t f)
|
||||||
|
{
|
||||||
|
if (Mobj* x = spread({16, 32}, {0, 0}))
|
||||||
|
{
|
||||||
|
x->state(S_KART_FIRE);
|
||||||
|
x->lightlevel = 176;
|
||||||
|
x->renderflags |= RF_ABSOLUTELIGHTLEVEL | RF_SEMIBRIGHT | RF_REDUCEVFX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f < 3*FRACUNIT/4)
|
||||||
|
{
|
||||||
|
auto smoke = [&]
|
||||||
|
{
|
||||||
|
if (Mobj* x = spread({3, 6}, {0, 8}))
|
||||||
|
{
|
||||||
|
Fixed from = x->scale() / 3;
|
||||||
|
Fixed to = 5 * x->scale() / 4;
|
||||||
|
x->scale_between(from, to, (to - from) / 35);
|
||||||
|
x->state(S_KART_SMOKE);
|
||||||
|
x->lightlevel = -112;
|
||||||
|
x->momz = 16 * mapobjectscale;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
smoke();
|
||||||
|
smoke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
UINT32 rf = RF_SEMIBRIGHT;
|
||||||
|
|
||||||
|
if (burning() && P_IsObjectOnGround(this))
|
||||||
|
{
|
||||||
|
fixed_t f = burning() * FRACUNIT / burn_duration();
|
||||||
|
|
||||||
|
if ((leveltime % std::max(1, Easing_OutCubic(f, 8, 1))) == 0)
|
||||||
|
{
|
||||||
|
vfx(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f < 3*FRACUNIT/4)
|
||||||
|
{
|
||||||
|
auto spark = [&](int degr)
|
||||||
|
{
|
||||||
|
angle_t ang = angle + degr_to_angle(degr);
|
||||||
|
if (Particle* x = spawn_from<Particle>({angle_vector(ang) * Fixed {radius}, 0}, MT_KART_PARTICLE))
|
||||||
|
{
|
||||||
|
x->state(S_BRAKEDRIFT);
|
||||||
|
x->fuse = 12;
|
||||||
|
x->color = SKINCOLOR_PASTEL;
|
||||||
|
x->angle = ang - ANGLE_90;
|
||||||
|
x->scale(2 * x->scale() / 5);
|
||||||
|
x->flags |= MF_NOGRAVITY | MF_NOCLIPHEIGHT;
|
||||||
|
x->renderflags |= RF_ADD;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (leveltime % 16 == 0)
|
||||||
|
{
|
||||||
|
radial_generic(45, 4, spark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leveltime & 1)
|
||||||
|
{
|
||||||
|
rf = RF_FULLBRIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
voice_loop(sfx_kc51);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderflags = (renderflags & ~RF_BRIGHTMASK) | rf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void animate()
|
||||||
|
{
|
||||||
|
Mobj* p = player();
|
||||||
|
|
||||||
|
if (!Mobj::valid(p))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timer())
|
||||||
|
{
|
||||||
|
// Vibration on the death sprite eases downward
|
||||||
|
p->exact_hitlag(Easing_InCubic(timer() * FRACUNIT / kVibrateTimer, 2, 90), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flags &= ~kNoClipFlags;
|
||||||
|
P_PlayDeathSound(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// First tick after hitlag: destroyed kart appears!
|
||||||
|
if (state()->num() == S_INVISIBLE)
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void P_SpawnBadnikExplosion(mobj_t *target)
|
||||||
|
{
|
||||||
|
UINT8 count = 24;
|
||||||
|
angle_t ang = 0;
|
||||||
|
angle_t step = ANGLE_MAX / count;
|
||||||
|
fixed_t spd = 8 * mapobjectscale;
|
||||||
|
for (UINT8 i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
mobj_t *x = P_SpawnMobjFromMobjUnscaled(
|
||||||
|
target,
|
||||||
|
P_RandomRange(PR_EXPLOSION, -48, 48) * target->scale,
|
||||||
|
P_RandomRange(PR_EXPLOSION, -48, 48) * target->scale,
|
||||||
|
P_RandomRange(PR_EXPLOSION, -48, 48) * target->scale,
|
||||||
|
MT_THOK
|
||||||
|
);
|
||||||
|
x->hitlag = 0;
|
||||||
|
P_InstaScale(x, 3 * x->scale / 2);
|
||||||
|
P_InstaThrust(x, ang, spd);
|
||||||
|
x->momz = P_RandomRange(PR_EXPLOSION, -4, 4) * mapobjectscale;
|
||||||
|
P_SetMobjStateNF(x, S_BADNIK_EXPLOSION1);
|
||||||
|
ang += step;
|
||||||
|
}
|
||||||
|
// burst effects (copied from MT_ITEMCAPSULE)
|
||||||
|
ang = FixedAngle(360*P_RandomFixed(PR_ITEM_DEBRIS));
|
||||||
|
for (UINT8 i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
mobj_t *blast = P_SpawnMobjFromMobj(target, 0, 0, target->info->height >> 1, MT_BATTLEBUMPER_BLAST);
|
||||||
|
blast->hitlag = 0;
|
||||||
|
blast->angle = ang + i*ANGLE_90;
|
||||||
|
P_SetScale(blast, 2*blast->scale/3);
|
||||||
|
blast->destscale = 6*blast->scale;
|
||||||
|
blast->scalespeed = (blast->destscale - blast->scale) / 30;
|
||||||
|
P_SetMobjStateNF(blast, static_cast<statenum_t>(S_BADNIK_EXPLOSION_SHOCKWAVE1 + i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
void Obj_SpawnDestroyedKart(mobj_t *player)
|
||||||
|
{
|
||||||
|
Kart::spawn(static_cast<Mobj*>(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Obj_DestroyedKartThink(mobj_t *kart)
|
||||||
|
{
|
||||||
|
static_cast<Kart*>(kart)->think();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean Obj_DestroyKart(mobj_t *kart)
|
||||||
|
{
|
||||||
|
return static_cast<Kart*>(kart)->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Obj_DestroyedKartParticleThink(mobj_t *part)
|
||||||
|
{
|
||||||
|
static_cast<Particle*>(part)->think();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Obj_DestroyedKartParticleLanding(mobj_t *part)
|
||||||
|
{
|
||||||
|
static_cast<Particle*>(part)->on_land();
|
||||||
|
}
|
||||||
|
|
@ -1656,40 +1656,6 @@ boolean P_CheckRacers(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void P_SpawnBadnikExplosion(mobj_t *target)
|
|
||||||
{
|
|
||||||
UINT8 count = 24;
|
|
||||||
angle_t ang = 0;
|
|
||||||
angle_t step = ANGLE_MAX / count;
|
|
||||||
fixed_t spd = 8 * mapobjectscale;
|
|
||||||
for (UINT8 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
mobj_t *x = P_SpawnMobjFromMobjUnscaled(
|
|
||||||
target,
|
|
||||||
P_RandomRange(PR_EXPLOSION, -48, 48) * target->scale,
|
|
||||||
P_RandomRange(PR_EXPLOSION, -48, 48) * target->scale,
|
|
||||||
P_RandomRange(PR_EXPLOSION, -48, 48) * target->scale,
|
|
||||||
MT_THOK
|
|
||||||
);
|
|
||||||
P_InstaScale(x, 3 * x->scale / 2);
|
|
||||||
P_InstaThrust(x, ang, spd);
|
|
||||||
x->momz = P_RandomRange(PR_EXPLOSION, -4, 4) * mapobjectscale;
|
|
||||||
P_SetMobjStateNF(x, S_BADNIK_EXPLOSION1);
|
|
||||||
ang += step;
|
|
||||||
}
|
|
||||||
// burst effects (copied from MT_ITEMCAPSULE)
|
|
||||||
ang = FixedAngle(360*P_RandomFixed(PR_ITEM_DEBRIS));
|
|
||||||
for (UINT8 i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
mobj_t *blast = P_SpawnMobjFromMobj(target, 0, 0, target->info->height >> 1, MT_BATTLEBUMPER_BLAST);
|
|
||||||
blast->angle = ang + i*ANGLE_90;
|
|
||||||
P_SetScale(blast, 2*blast->scale/3);
|
|
||||||
blast->destscale = 6*blast->scale;
|
|
||||||
blast->scalespeed = (blast->destscale - blast->scale) / 30;
|
|
||||||
P_SetMobjStateNF(blast, S_BADNIK_EXPLOSION_SHOCKWAVE1 + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Kills an object.
|
/** Kills an object.
|
||||||
*
|
*
|
||||||
* \param target The victim.
|
* \param target The victim.
|
||||||
|
|
@ -1890,31 +1856,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
||||||
{
|
{
|
||||||
fixed_t flingSpeed = FixedHypot(target->momx, target->momy);
|
fixed_t flingSpeed = FixedHypot(target->momx, target->momy);
|
||||||
angle_t flingAngle;
|
angle_t flingAngle;
|
||||||
mobj_t *kart;
|
|
||||||
|
|
||||||
target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player)
|
target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player)
|
||||||
target->momx = target->momy = target->momz = 0;
|
target->momx = target->momy = target->momz = 0;
|
||||||
|
|
||||||
kart = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_KART_LEFTOVER);
|
Obj_SpawnDestroyedKart(target);
|
||||||
|
|
||||||
if (kart && !P_MobjWasRemoved(kart))
|
|
||||||
{
|
|
||||||
kart->angle = target->angle;
|
|
||||||
kart->color = target->color;
|
|
||||||
kart->hitlag = target->hitlag;
|
|
||||||
kart->eflags |= MFE_DAMAGEHITLAG;
|
|
||||||
P_SetObjectMomZ(kart, 6*FRACUNIT, false);
|
|
||||||
kart->extravalue1 = target->player->kartweight;
|
|
||||||
|
|
||||||
// Copy interp data
|
|
||||||
kart->old_angle = target->old_angle;
|
|
||||||
kart->old_x = target->old_x;
|
|
||||||
kart->old_y = target->old_y;
|
|
||||||
kart->old_z = target->old_z;
|
|
||||||
|
|
||||||
if (target->player->pflags & PF_NOCONTEST)
|
|
||||||
P_SetTarget(&target->tracer, kart);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source && !P_MobjWasRemoved(source))
|
if (source && !P_MobjWasRemoved(source))
|
||||||
{
|
{
|
||||||
|
|
@ -1956,16 +1902,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
||||||
boolean battle = (gametyperules & (GTR_BUMPERS | GTR_BOSS)) == GTR_BUMPERS;
|
boolean battle = (gametyperules & (GTR_BUMPERS | GTR_BOSS)) == GTR_BUMPERS;
|
||||||
P_InstaThrust(target, flingAngle, max(flingSpeed, 6 * target->scale) / (battle ? 1 : 3));
|
P_InstaThrust(target, flingAngle, max(flingSpeed, 6 * target->scale) / (battle ? 1 : 3));
|
||||||
P_SetObjectMomZ(target, battle ? 20*FRACUNIT : 18*FRACUNIT, false);
|
P_SetObjectMomZ(target, battle ? 20*FRACUNIT : 18*FRACUNIT, false);
|
||||||
|
|
||||||
P_PlayDeathSound(target);
|
|
||||||
|
|
||||||
if (skins[target->player->skin].flags & SF_BADNIK)
|
|
||||||
{
|
|
||||||
P_SpawnBadnikExplosion(target);
|
|
||||||
target->spritexscale = 2*FRACUNIT;
|
|
||||||
target->spriteyscale = 2*FRACUNIT;
|
|
||||||
target->flags |= MF_NOSQUISH;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prisons Free Play: don't eliminate P1 for
|
// Prisons Free Play: don't eliminate P1 for
|
||||||
|
|
@ -2554,6 +2490,9 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou
|
||||||
|
|
||||||
static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 type)
|
static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 type)
|
||||||
{
|
{
|
||||||
|
(void)inflictor;
|
||||||
|
(void)source;
|
||||||
|
|
||||||
const boolean beforeexit = !(player->exiting || (player->pflags & PF_NOCONTEST));
|
const boolean beforeexit = !(player->exiting || (player->pflags & PF_NOCONTEST));
|
||||||
|
|
||||||
if (type == DMG_SPECTATOR && (G_GametypeHasTeams() || G_GametypeHasSpectators()))
|
if (type == DMG_SPECTATOR && (G_GametypeHasTeams() || G_GametypeHasSpectators()))
|
||||||
|
|
@ -2672,7 +2611,7 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
||||||
}
|
}
|
||||||
|
|
||||||
K_DropEmeraldsFromPlayer(player, player->emeralds);
|
K_DropEmeraldsFromPlayer(player, player->emeralds);
|
||||||
K_SetHitLagForObjects(player->mo, inflictor, source, MAXHITLAGTICS, true);
|
//K_SetHitLagForObjects(player->mo, inflictor, source, MAXHITLAGTICS, true);
|
||||||
|
|
||||||
player->carry = CR_NONE;
|
player->carry = CR_NONE;
|
||||||
|
|
||||||
|
|
@ -2697,19 +2636,6 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
||||||
|
|
||||||
if (type == DMG_TIMEOVER)
|
if (type == DMG_TIMEOVER)
|
||||||
{
|
{
|
||||||
if (gametyperules & GTR_CIRCUIT)
|
|
||||||
{
|
|
||||||
mobj_t *boom;
|
|
||||||
|
|
||||||
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
|
|
||||||
player->mo->renderflags |= RF_DONTDRAW;
|
|
||||||
|
|
||||||
boom = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FZEROBOOM);
|
|
||||||
boom->scale = player->mo->scale;
|
|
||||||
boom->angle = player->mo->angle;
|
|
||||||
P_SetTarget(&boom->target, player->mo);
|
|
||||||
}
|
|
||||||
|
|
||||||
player->pflags |= PF_ELIMINATED;
|
player->pflags |= PF_ELIMINATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2898,6 +2824,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
||||||
case MT_ICECAPBLOCK:
|
case MT_ICECAPBLOCK:
|
||||||
return Obj_TryCrateDamage(target, inflictor);
|
return Obj_TryCrateDamage(target, inflictor);
|
||||||
|
|
||||||
|
case MT_KART_LEFTOVER:
|
||||||
|
// intangible (do not let instawhip shred damage)
|
||||||
|
if (Obj_DestroyKart(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
P_SetObjectMomZ(target, 12*FRACUNIT, false);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -3467,7 +3401,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
||||||
if ((damagetype & DMG_TYPEMASK) != DMG_WHUMBLE && (gametyperules & GTR_BUMPERS) && !battleprisons)
|
if ((damagetype & DMG_TYPEMASK) != DMG_WHUMBLE && (gametyperules & GTR_BUMPERS) && !battleprisons)
|
||||||
laglength /= 2;
|
laglength /= 2;
|
||||||
|
|
||||||
K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
if (!(target->player && (damagetype & DMG_DEATHMASK)))
|
||||||
|
K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
||||||
|
|
||||||
target->flags2 |= MF2_ALREADYHIT;
|
target->flags2 |= MF2_ALREADYHIT;
|
||||||
|
|
||||||
|
|
|
||||||
82
src/p_mobj.c
82
src/p_mobj.c
|
|
@ -1282,6 +1282,10 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
||||||
if (mo->fuse)
|
if (mo->fuse)
|
||||||
gravityadd /= 10;
|
gravityadd /= 10;
|
||||||
break;
|
break;
|
||||||
|
case MT_KART_PARTICLE:
|
||||||
|
if (!mo->fuse)
|
||||||
|
gravityadd *= 2;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -2468,68 +2472,17 @@ boolean P_ZMovement(mobj_t *mo)
|
||||||
mom.z = -mom.z;
|
mom.z = -mom.z;
|
||||||
else if (mo->type == MT_KART_LEFTOVER)
|
else if (mo->type == MT_KART_LEFTOVER)
|
||||||
{
|
{
|
||||||
if (mo->health > 1)
|
|
||||||
{
|
|
||||||
const fixed_t tireOffset = 32;
|
|
||||||
const angle_t aOffset = ANGLE_22h;
|
|
||||||
|
|
||||||
UINT8 i;
|
|
||||||
angle_t tireAngle;
|
|
||||||
mobj_t *tire;
|
|
||||||
|
|
||||||
// Spawn tires!
|
|
||||||
mo->health = 1;
|
|
||||||
P_SetMobjState(mo, S_KART_LEFTOVER_NOTIRES);
|
|
||||||
|
|
||||||
// Front tires
|
|
||||||
tireAngle = mo->angle - aOffset;
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
tire = P_SpawnMobjFromMobj(
|
|
||||||
mo,
|
|
||||||
tireOffset * FINECOSINE(tireAngle >> ANGLETOFINESHIFT),
|
|
||||||
tireOffset * FINESINE(tireAngle >> ANGLETOFINESHIFT),
|
|
||||||
0,
|
|
||||||
MT_KART_TIRE
|
|
||||||
);
|
|
||||||
|
|
||||||
tire->angle = mo->angle;
|
|
||||||
tire->fuse = 3*TICRATE;
|
|
||||||
P_InstaThrust(tire, tireAngle, 4 * mo->scale);
|
|
||||||
P_SetObjectMomZ(tire, 4*FRACUNIT, false);
|
|
||||||
|
|
||||||
tireAngle += (aOffset * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Back tires
|
|
||||||
tireAngle = (mo->angle + ANGLE_180) - aOffset;
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
tire = P_SpawnMobjFromMobj(
|
|
||||||
mo,
|
|
||||||
tireOffset * FINECOSINE(tireAngle >> ANGLETOFINESHIFT),
|
|
||||||
tireOffset * FINESINE(tireAngle >> ANGLETOFINESHIFT),
|
|
||||||
0,
|
|
||||||
MT_KART_TIRE
|
|
||||||
);
|
|
||||||
|
|
||||||
tire->angle = mo->angle;
|
|
||||||
tire->fuse = 3*TICRATE;
|
|
||||||
P_InstaThrust(tire, tireAngle, 4 * mo->scale);
|
|
||||||
P_SetObjectMomZ(tire, 4*FRACUNIT, false);
|
|
||||||
|
|
||||||
P_SetMobjState(tire, S_KART_TIRE2);
|
|
||||||
|
|
||||||
tireAngle += (aOffset * 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mom.z = 0;
|
mom.z = 0;
|
||||||
}
|
}
|
||||||
else if (mo->type == MT_KART_TIRE)
|
else if (mo->type == MT_KART_TIRE)
|
||||||
{
|
{
|
||||||
mom.z = -mom.z;
|
mom.z = -mom.z;
|
||||||
}
|
}
|
||||||
|
else if (mo->type == MT_KART_PARTICLE)
|
||||||
|
{
|
||||||
|
mom.z = -mom.z / (mo->fuse ? 1 : 2);
|
||||||
|
Obj_DestroyedKartParticleLanding(mo);
|
||||||
|
}
|
||||||
else if (mo->type == MT_BIGTUMBLEWEED
|
else if (mo->type == MT_BIGTUMBLEWEED
|
||||||
|| mo->type == MT_LITTLETUMBLEWEED
|
|| mo->type == MT_LITTLETUMBLEWEED
|
||||||
|| mo->type == MT_CANNONBALLDECOR
|
|| mo->type == MT_CANNONBALLDECOR
|
||||||
|
|
@ -9895,6 +9848,22 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MT_KART_PARTICLE:
|
||||||
|
{
|
||||||
|
Obj_DestroyedKartParticleThink(mobj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MT_KART_LEFTOVER:
|
||||||
|
{
|
||||||
|
Obj_DestroyedKartThink(mobj);
|
||||||
|
if (P_MobjWasRemoved(mobj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// check mobj against possible water content, before movement code
|
// check mobj against possible water content, before movement code
|
||||||
P_MobjCheckWater(mobj);
|
P_MobjCheckWater(mobj);
|
||||||
|
|
@ -9958,6 +9927,7 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
||||||
case MT_POGOSPRING:
|
case MT_POGOSPRING:
|
||||||
case MT_EMERALD:
|
case MT_EMERALD:
|
||||||
case MT_BLENDEYE_PUYO:
|
case MT_BLENDEYE_PUYO:
|
||||||
|
case MT_KART_PARTICLE:
|
||||||
if (mobj->fuse <= TICRATE)
|
if (mobj->fuse <= TICRATE)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -2828,7 +2828,6 @@ static void P_DeathThink(player_t *player)
|
||||||
if (player->mo)
|
if (player->mo)
|
||||||
{
|
{
|
||||||
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
|
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
|
||||||
player->mo->renderflags |= RF_DONTDRAW;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -1529,6 +1529,12 @@ sfxinfo_t S_sfx[NUMSFX] =
|
||||||
// Patching up base sounds
|
// Patching up base sounds
|
||||||
{"s226l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // s2 spikes LOUD
|
{"s226l", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // s2 spikes LOUD
|
||||||
|
|
||||||
|
// Destroyed Kart
|
||||||
|
{"die00", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||||
|
{"die01", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||||
|
{"die02", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||||
|
{"die03", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||||
|
|
||||||
// SRB2kart - Skin sounds
|
// SRB2kart - Skin sounds
|
||||||
{"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR, ""},
|
{"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR, ""},
|
||||||
{"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR, ""},
|
{"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR, ""},
|
||||||
|
|
|
||||||
|
|
@ -1605,6 +1605,12 @@ typedef enum
|
||||||
// Patch-up
|
// Patch-up
|
||||||
sfx_s226l,
|
sfx_s226l,
|
||||||
|
|
||||||
|
// Destroyed Kart
|
||||||
|
sfx_die00,
|
||||||
|
sfx_die01,
|
||||||
|
sfx_die02,
|
||||||
|
sfx_die03,
|
||||||
|
|
||||||
// And LASTLY, Kart's skin sounds.
|
// And LASTLY, Kart's skin sounds.
|
||||||
sfx_kwin,
|
sfx_kwin,
|
||||||
sfx_klose,
|
sfx_klose,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue