mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Invincible player punts hazardous/solid things, unless MF_ELEMENTAL
If player is in one of these states: - Invincibility - Grow (K_IsBigger) - Flame Shield dash - Over 200% speed And the other object: - Does not have MF_DONTPUNT Then, touching a solid object: - Punts the object, unless the object has MF_ELEMENTAL - Fizzles the object, if the object has MF_ELEMENTAL Or, when an object damages the player: - That object is punted, unless it has MF_ELEMENTAL - The object fizzles, if it has MF_ELEMENTAL Punting means: - A copy of the object is made - Both the player and copy receive 5 tics of hitlag - The copy is thrust away from the player at a minimum of 60 FU, or 2x either the player's or object's momentum, whichever is ultimately greater - The copy despawns after 2 seconds - The copy flickers constantly, while thrust away Fizzling means: - The object disappears completely - A puff of smoke is spawned in place of the object - No hitlag is applied to the player Both punting and fizzling: - Hide the original object (intangible and invisible) - The original object reppears after 30 seconds - For 2 seconds before reappearing, the object flickers back in, but is still intangible
This commit is contained in:
parent
a8a1c14580
commit
61cad641bb
12 changed files with 192 additions and 2 deletions
|
|
@ -18,6 +18,7 @@
|
||||||
#include "k_podium.h"
|
#include "k_podium.h"
|
||||||
#include "k_powerup.h"
|
#include "k_powerup.h"
|
||||||
#include "k_hitlag.h"
|
#include "k_hitlag.h"
|
||||||
|
#include "m_random.h"
|
||||||
|
|
||||||
angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2)
|
angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2)
|
||||||
{
|
{
|
||||||
|
|
@ -1170,3 +1171,114 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void K_PuntHazard(mobj_t *t1, mobj_t *t2)
|
||||||
|
{
|
||||||
|
// TODO: spawn a unique mobjtype other than MT_GHOST
|
||||||
|
mobj_t *img = P_SpawnGhostMobj(t1);
|
||||||
|
|
||||||
|
K_MakeObjectReappear(t1);
|
||||||
|
|
||||||
|
img->flags &= ~MF_NOGRAVITY;
|
||||||
|
img->renderflags = t1->renderflags & ~RF_DONTDRAW;
|
||||||
|
img->extravalue1 = 1;
|
||||||
|
img->extravalue2 = 2;
|
||||||
|
img->fuse = 2*TICRATE;
|
||||||
|
|
||||||
|
struct Vector
|
||||||
|
{
|
||||||
|
fixed_t x_, y_, z_;
|
||||||
|
fixed_t h_ = FixedHypot(x_, y_);
|
||||||
|
fixed_t speed_ = std::max(60 * mapobjectscale, FixedHypot(h_, z_) * 2);
|
||||||
|
|
||||||
|
explicit Vector(fixed_t x, fixed_t y, fixed_t z) : x_(x), y_(y), z_(z) {}
|
||||||
|
explicit Vector(const mobj_t* mo) :
|
||||||
|
Vector(std::max(
|
||||||
|
Vector(mo->x - mo->old_x, mo->y - mo->old_y, mo->z - mo->old_z),
|
||||||
|
Vector(mo->momx, mo->momy, mo->momz)
|
||||||
|
))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
explicit Vector(const Vector&) = default;
|
||||||
|
|
||||||
|
bool operator<(const Vector& b) const { return speed_ < b.speed_; }
|
||||||
|
|
||||||
|
void invert()
|
||||||
|
{
|
||||||
|
x_ = -x_;
|
||||||
|
y_ = -y_;
|
||||||
|
z_ = -z_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void thrust(mobj_t* mo) const
|
||||||
|
{
|
||||||
|
angle_t yaw = R_PointToAngle2(0, 0, h_, z_);
|
||||||
|
yaw = std::max(AbsAngle(yaw), static_cast<angle_t>(ANGLE_11hh)) + (yaw & ANGLE_180);
|
||||||
|
|
||||||
|
P_InstaThrust(mo, R_PointToAngle2(0, 0, x_, y_), FixedMul(speed_, FCOS(yaw)));
|
||||||
|
mo->momz = FixedMul(speed_, FSIN(yaw));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector h_vector(t1);
|
||||||
|
Vector p_vector(t2);
|
||||||
|
|
||||||
|
h_vector.invert();
|
||||||
|
|
||||||
|
std::max(h_vector, p_vector).thrust(img);
|
||||||
|
|
||||||
|
K_DoPowerClash(img, t2); // applies hitlag
|
||||||
|
P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean K_PuntCollide(mobj_t *t1, mobj_t *t2)
|
||||||
|
{
|
||||||
|
if (t1->flags & MF_DONTPUNT)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!t2->player)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!K_PlayerCanPunt(t2->player))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t1->flags & MF_ELEMENTAL)
|
||||||
|
{
|
||||||
|
K_MakeObjectReappear(t1);
|
||||||
|
|
||||||
|
// copied from MT_ITEMCAPSULE
|
||||||
|
UINT8 i;
|
||||||
|
INT16 spacing = (t1->radius >> 1) / t1->scale;
|
||||||
|
// dust effects
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
mobj_t *puff = P_SpawnMobjFromMobj(
|
||||||
|
t1,
|
||||||
|
P_RandomRange(PR_ITEM_DEBRIS, -spacing, spacing) * FRACUNIT,
|
||||||
|
P_RandomRange(PR_ITEM_DEBRIS, -spacing, spacing) * FRACUNIT,
|
||||||
|
P_RandomRange(PR_ITEM_DEBRIS, 0, 4*spacing) * FRACUNIT,
|
||||||
|
MT_SPINDASHDUST
|
||||||
|
);
|
||||||
|
|
||||||
|
puff->momz = puff->scale * P_MobjFlip(puff);
|
||||||
|
|
||||||
|
P_Thrust(puff, R_PointToAngle2(t2->x, t2->y, puff->x, puff->y), 3*puff->scale);
|
||||||
|
|
||||||
|
puff->momx += t2->momx / 2;
|
||||||
|
puff->momy += t2->momy / 2;
|
||||||
|
puff->momz += t2->momz / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
K_PuntHazard(t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2);
|
||||||
|
|
||||||
boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2);
|
boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2);
|
||||||
|
|
||||||
|
void K_PuntHazard(mobj_t *t1, mobj_t *t2);
|
||||||
|
boolean K_PuntCollide(mobj_t *t1, mobj_t *t2);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
30
src/k_kart.c
30
src/k_kart.c
|
|
@ -12636,4 +12636,34 @@ boolean K_IsPlayingDisplayPlayer(player_t *player)
|
||||||
return P_IsDisplayPlayer(player) && (!player->exiting);
|
return P_IsDisplayPlayer(player) && (!player->exiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean K_PlayerCanPunt(player_t *player)
|
||||||
|
{
|
||||||
|
if (player->invincibilitytimer > 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player->flamedash > 0 && player->itemtype == KITEM_FLAMESHIELD)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player->growshrinktimer > 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player->tripwirePass >= TRIPWIRE_BLASTER && player->speed >= 2 * K_GetKartSpeed(player, false, false))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void K_MakeObjectReappear(mobj_t *mo)
|
||||||
|
{
|
||||||
|
(!P_MobjWasRemoved(mo->punt_ref) ? mo->punt_ref : mo)->reappear = leveltime + (30*TICRATE);
|
||||||
|
}
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,9 @@ void K_SetTireGrease(player_t *player, tic_t tics);
|
||||||
|
|
||||||
boolean K_IsPlayingDisplayPlayer(player_t *player);
|
boolean K_IsPlayingDisplayPlayer(player_t *player);
|
||||||
|
|
||||||
|
boolean K_PlayerCanPunt(player_t *player);
|
||||||
|
void K_MakeObjectReappear(mobj_t *mo);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
#include "k_hitlag.h"
|
#include "k_hitlag.h"
|
||||||
#include "acs/interface.h"
|
#include "acs/interface.h"
|
||||||
#include "k_powerup.h"
|
#include "k_powerup.h"
|
||||||
|
#include "k_collide.h"
|
||||||
|
|
||||||
// CTF player names
|
// CTF player names
|
||||||
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
|
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
|
||||||
|
|
@ -2929,6 +2930,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
||||||
invincible = false;
|
invincible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: doing this from P_DamageMobj limits punting to objects that damage the player.
|
||||||
|
// And it may be kind of yucky.
|
||||||
|
// But this is easier than accounting for every condition in PIT_CheckThing!
|
||||||
|
if (inflictor && K_PuntCollide(inflictor, target))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (invincible && type != DMG_STUMBLE && type != DMG_WHUMBLE)
|
if (invincible && type != DMG_STUMBLE && type != DMG_WHUMBLE)
|
||||||
{
|
{
|
||||||
const INT32 oldHitlag = target->hitlag;
|
const INT32 oldHitlag = target->hitlag;
|
||||||
|
|
|
||||||
|
|
@ -595,6 +595,8 @@ mobj_t *P_FindMobjFromTID(mtag_t tid, mobj_t *i, mobj_t *activator);
|
||||||
|
|
||||||
void P_DeleteMobjStringArgs(mobj_t *mobj);
|
void P_DeleteMobjStringArgs(mobj_t *mobj);
|
||||||
|
|
||||||
|
tic_t P_MobjIsReappearing(const mobj_t *mobj);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
10
src/p_map.c
10
src/p_map.c
|
|
@ -563,6 +563,10 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
||||||
if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING)))
|
if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING)))
|
||||||
return BMIT_CONTINUE;
|
return BMIT_CONTINUE;
|
||||||
|
|
||||||
|
// Thing is respawning
|
||||||
|
if (P_MobjIsReappearing(thing))
|
||||||
|
return BMIT_CONTINUE;
|
||||||
|
|
||||||
blockdist = thing->radius + tm.thing->radius;
|
blockdist = thing->radius + tm.thing->radius;
|
||||||
|
|
||||||
if (abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist)
|
if (abs(thing->x - tm.x) >= blockdist || abs(thing->y - tm.y) >= blockdist)
|
||||||
|
|
@ -1631,7 +1635,10 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
||||||
if (tm.thing->z + tm.thing->height < thing->z)
|
if (tm.thing->z + tm.thing->height < thing->z)
|
||||||
return BMIT_CONTINUE; // underneath
|
return BMIT_CONTINUE; // underneath
|
||||||
|
|
||||||
|
if (!K_PuntCollide(thing, tm.thing))
|
||||||
|
{
|
||||||
K_KartSolidBounce(tm.thing, thing);
|
K_KartSolidBounce(tm.thing, thing);
|
||||||
|
}
|
||||||
return BMIT_CONTINUE;
|
return BMIT_CONTINUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2346,7 +2353,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y, TryMoveResult_t *re
|
||||||
// Check things first, possibly picking things up.
|
// Check things first, possibly picking things up.
|
||||||
|
|
||||||
// MF_NOCLIPTHING: used by camera to not be blocked by things
|
// MF_NOCLIPTHING: used by camera to not be blocked by things
|
||||||
if (!(thing->flags & MF_NOCLIPTHING))
|
// Respawning things should also be intangible to other things
|
||||||
|
if (!(thing->flags & MF_NOCLIPTHING) && !P_MobjIsReappearing(thing))
|
||||||
{
|
{
|
||||||
for (bx = xl; bx <= xh; bx++)
|
for (bx = xl; bx <= xh; bx++)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15381,3 +15381,9 @@ void P_DeleteMobjStringArgs(mobj_t *mobj)
|
||||||
mobj->script_stringargs[i] = NULL;
|
mobj->script_stringargs[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tic_t P_MobjIsReappearing(const mobj_t *mobj)
|
||||||
|
{
|
||||||
|
tic_t t = (!P_MobjWasRemoved(mobj->punt_ref) ? mobj->punt_ref : mobj)->reappear;
|
||||||
|
return t - min(leveltime, t);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -437,7 +437,12 @@ struct mobj_t
|
||||||
|
|
||||||
boolean frozen;
|
boolean frozen;
|
||||||
|
|
||||||
|
// Object was punted and is temporarily invisible and
|
||||||
|
// intangible. This is the leveltime that it will
|
||||||
|
// reappear.
|
||||||
tic_t reappear;
|
tic_t reappear;
|
||||||
|
|
||||||
|
// If punt_ref, set punt_ref->reappear, treat as if this->reappear
|
||||||
mobj_t *punt_ref;
|
mobj_t *punt_ref;
|
||||||
|
|
||||||
// WARNING: New fields must be added separately to savegame and Lua.
|
// WARNING: New fields must be added separately to savegame and Lua.
|
||||||
|
|
|
||||||
|
|
@ -1166,6 +1166,9 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
|
||||||
|
|
||||||
K_ReduceVFX(ghost, mobj->player);
|
K_ReduceVFX(ghost, mobj->player);
|
||||||
|
|
||||||
|
ghost->reappear = mobj->reappear;
|
||||||
|
P_SetTarget(&ghost->punt_ref, mobj->punt_ref);
|
||||||
|
|
||||||
return ghost;
|
return ghost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3746,6 +3746,12 @@ boolean R_ThingVisible (mobj_t *thing)
|
||||||
if (r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing)))
|
if (r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (tic_t t = P_MobjIsReappearing(thing))
|
||||||
|
{
|
||||||
|
// Flicker back in
|
||||||
|
return t <= 2*TICRATE && (leveltime & 1);
|
||||||
|
}
|
||||||
|
|
||||||
if ((viewssnum == 0 && (thing->renderflags & RF_DONTDRAWP1))
|
if ((viewssnum == 0 && (thing->renderflags & RF_DONTDRAWP1))
|
||||||
|| (viewssnum == 1 && (thing->renderflags & RF_DONTDRAWP2))
|
|| (viewssnum == 1 && (thing->renderflags & RF_DONTDRAWP2))
|
||||||
|| (viewssnum == 2 && (thing->renderflags & RF_DONTDRAWP3))
|
|| (viewssnum == 2 && (thing->renderflags & RF_DONTDRAWP3))
|
||||||
|
|
|
||||||
|
|
@ -948,6 +948,9 @@ boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32
|
||||||
if (!listener)
|
if (!listener)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (source->thinker.function.acp1 == (actionf_p1)P_MobjThinker && P_MobjIsReappearing(source))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Init listensource with default listener
|
// Init listensource with default listener
|
||||||
listensource.x = listener->x;
|
listensource.x = listener->x;
|
||||||
listensource.y = listener->y;
|
listensource.y = listener->y;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue