mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-16 19:52:27 +00:00
Add Stone Shoe
This commit is contained in:
parent
74f4708f7f
commit
6d80b741ae
8 changed files with 532 additions and 17 deletions
|
|
@ -389,6 +389,14 @@ bool is_object_tracking_target(const mobj_t* mobj)
|
|||
return !(mobj->renderflags & (RF_TRANSMASK | RF_DONTDRAW)) && // the spraycan wasn't collected yet
|
||||
P_CheckSight(stplyr->mo, const_cast<mobj_t*>(mobj));
|
||||
|
||||
case MT_FLOATINGITEM:
|
||||
if (mobj->threshold != KDROP_STONESHOETRAP)
|
||||
return false;
|
||||
|
||||
if (cv_debugpickmeup.value)
|
||||
return false;
|
||||
|
||||
// FALLTHRU
|
||||
default:
|
||||
if (K_IsPickMeUpItem(mobj->type))
|
||||
return (mobj->target && !P_MobjWasRemoved(mobj->target) && (
|
||||
|
|
|
|||
93
src/k_kart.c
93
src/k_kart.c
|
|
@ -802,6 +802,7 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against)
|
|||
case MT_ORBINAUT_SHIELD:
|
||||
case MT_GACHABOM:
|
||||
case MT_DUELBOMB:
|
||||
case MT_STONESHOE:
|
||||
if (against->player)
|
||||
weight = K_PlayerWeight(against, NULL);
|
||||
break;
|
||||
|
|
@ -927,6 +928,8 @@ static boolean K_JustBumpedException(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MT_STONESHOE:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -3521,6 +3524,9 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
if (player->bananadrag > TICRATE)
|
||||
boostpower = (4*boostpower)/5;
|
||||
|
||||
if (player->stonedrag)
|
||||
boostpower = (4*boostpower)/5;
|
||||
|
||||
// Note: Handling will ONLY stack when sliptiding!
|
||||
// > (NB 2023-03-06: This was previously unintentionally applied while drifting as well.)
|
||||
// > (This only affected drifts where you were under the effect of multiple handling boosts.)
|
||||
|
|
@ -4663,7 +4669,7 @@ void K_RemoveGrowShrink(player_t *player)
|
|||
static boolean K_IsScaledItem(mobj_t *mobj)
|
||||
{
|
||||
return mobj && !P_MobjWasRemoved(mobj) &&
|
||||
(mobj->type == MT_ORBINAUT || mobj->type == MT_JAWZ || mobj->type == MT_GACHABOM
|
||||
(mobj->type == MT_ORBINAUT || mobj->type == MT_JAWZ || mobj->type == MT_GACHABOM || mobj->type == MT_STONESHOE
|
||||
|| mobj->type == MT_BANANA || mobj->type == MT_EGGMANITEM || mobj->type == MT_BALLHOG
|
||||
|| mobj->type == MT_SSMINE || mobj->type == MT_LANDMINE || mobj->type == MT_SINK
|
||||
|| mobj->type == MT_GARDENTOP || mobj->type == MT_DROPTARGET || mobj->type == MT_PLAYER);
|
||||
|
|
@ -6882,8 +6888,13 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
if (dir > 0)
|
||||
{
|
||||
// Shoot forward
|
||||
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, mapthing);
|
||||
mo->angle = player->mo->angle;
|
||||
if (mapthing == MT_FLOATINGITEM)
|
||||
mo = K_CreatePaperItem(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, player->mo->angle, 0, 1, 0);
|
||||
else
|
||||
{
|
||||
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, mapthing);
|
||||
mo->angle = player->mo->angle;
|
||||
}
|
||||
|
||||
// These are really weird so let's make it a very specific case to make SURE it works...
|
||||
if (player->mo->eflags & MFE_VERTICALFLIP)
|
||||
|
|
@ -6901,7 +6912,7 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
mo->extravalue2 = dir;
|
||||
|
||||
fixed_t HEIGHT = ((20 * FRACUNIT) + (dir * 10)) + (FixedDiv(player->mo->momz, mapobjectscale) * P_MobjFlip(player->mo)); // Also intentionally not player scale
|
||||
P_SetObjectMomZ(mo, HEIGHT, false);
|
||||
mo->momz = FixedMul(HEIGHT, mapobjectscale) * P_MobjFlip(mo);
|
||||
|
||||
angle_t fa = (player->mo->angle >> ANGLETOFINESHIFT);
|
||||
mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), FixedMul(PROJSPEED, dir));
|
||||
|
|
@ -6930,8 +6941,11 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
if (mo->eflags & MFE_UNDERWATER)
|
||||
mo->momz = (117 * mo->momz) / 200;
|
||||
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
if (mapthing != MT_FLOATINGITEM)
|
||||
{
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
}
|
||||
|
||||
switch (mapthing)
|
||||
{
|
||||
|
|
@ -6978,6 +6992,13 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
newy = player->mo->y + player->mo->momy;
|
||||
newz = player->mo->z;
|
||||
}
|
||||
else if (mapthing == MT_FLOATINGITEM) // Stone Shoe
|
||||
{
|
||||
newangle = player->mo->angle;
|
||||
newx = player->mo->x + player->mo->momx - FixedMul(2 * player->mo->radius + 40 * mapobjectscale, FCOS(newangle));
|
||||
newy = player->mo->y + player->mo->momy - FixedMul(2 * player->mo->radius + 40 * mapobjectscale, FSIN(newangle));
|
||||
newz = player->mo->z;
|
||||
}
|
||||
else if (lasttrail)
|
||||
{
|
||||
newangle = lasttrail->angle;
|
||||
|
|
@ -6997,14 +7018,23 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
newz = player->mo->z;
|
||||
}
|
||||
|
||||
mo = P_SpawnMobj(newx, newy, newz, mapthing); // this will never return null because collision isn't processed here
|
||||
if (mapthing == MT_FLOATINGITEM)
|
||||
mo = K_CreatePaperItem(newx, newy, newz, newangle, 0, 1, 0);
|
||||
else
|
||||
{
|
||||
mo = P_SpawnMobj(newx, newy, newz, mapthing); // this will never return null because collision isn't processed here
|
||||
mo->angle = newangle;
|
||||
}
|
||||
K_FlipFromObject(mo, player->mo);
|
||||
|
||||
mo->threshold = 10;
|
||||
P_SetTarget(&mo->target, player->mo);
|
||||
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
if (mapthing != MT_FLOATINGITEM)
|
||||
{
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
}
|
||||
|
||||
if (P_IsObjectOnGround(player->mo))
|
||||
{
|
||||
|
|
@ -7033,8 +7063,6 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
if (player->mo->eflags & MFE_VERTICALFLIP)
|
||||
mo->eflags |= MFE_VERTICALFLIP;
|
||||
|
||||
mo->angle = newangle;
|
||||
|
||||
if (mapthing == MT_SSMINE)
|
||||
mo->extravalue1 = 49; // Pads the start-up length from 21 frames to a full 2 seconds
|
||||
else if (mapthing == MT_BUBBLESHIELDTRAP)
|
||||
|
|
@ -10500,6 +10528,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
// S_StartSound(NULL, sfx_s26d);
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
|
||||
}
|
||||
|
||||
player->stonedrag = 0;
|
||||
}
|
||||
|
||||
void K_KartResetPlayerColor(player_t *player)
|
||||
|
|
@ -14601,6 +14631,37 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
break;
|
||||
case KITEM_STONESHOE:
|
||||
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
|
||||
{
|
||||
if (player->throwdir == -1)
|
||||
{
|
||||
// Do not spawn a shoe if you're already dragging one
|
||||
if (!P_MobjWasRemoved(player->stoneShoe))
|
||||
break;
|
||||
P_SetTarget(&player->stoneShoe, Obj_SpawnStoneShoe(player - players, player->mo));
|
||||
K_AddHitLag(player->mo, 8, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
K_SetItemOut(player); // need this to set itemscale
|
||||
|
||||
mobj_t *drop = K_ThrowKartItem(player, false, MT_FLOATINGITEM, -1, 0, 0);
|
||||
drop->threshold = KDROP_STONESHOETRAP;
|
||||
drop->movecount = 1;
|
||||
drop->extravalue2 = player - players;
|
||||
drop->radius = 32 * drop->scale;
|
||||
drop->flags |= MF_SHOOTABLE; // let it whip/lightning shield
|
||||
|
||||
K_UnsetItemOut(player);
|
||||
}
|
||||
|
||||
player->itemamount--;
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
break;
|
||||
case KITEM_SAD:
|
||||
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
|
||||
&& !player->sadtimer)
|
||||
|
|
@ -15889,6 +15950,7 @@ boolean K_IsPickMeUpItem(mobjtype_t type)
|
|||
case MT_BUBBLESHIELDTRAP:
|
||||
case MT_SSMINE:
|
||||
case MT_SSMINE_SHIELD:
|
||||
case MT_FLOATINGITEM: // Stone Shoe
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -15932,6 +15994,9 @@ static boolean K_PickUp(player_t *player, mobj_t *picked)
|
|||
case MT_GACHABOM:
|
||||
type = KITEM_GACHABOM;
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
type = KITEM_STONESHOE;
|
||||
break;
|
||||
case MT_BUBBLESHIELDTRAP:
|
||||
type = KITEM_BUBBLESHIELD;
|
||||
break;
|
||||
|
|
@ -15942,6 +16007,12 @@ static boolean K_PickUp(player_t *player, mobj_t *picked)
|
|||
case MT_SSMINE_SHIELD:
|
||||
type = KITEM_MINE;
|
||||
break;
|
||||
case MT_FLOATINGITEM:
|
||||
if (picked->threshold == KDROP_STONESHOETRAP)
|
||||
type = KITEM_STONESHOE;
|
||||
else
|
||||
type = KITEM_SAD;
|
||||
break;
|
||||
default:
|
||||
type = KITEM_SAD;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -460,6 +460,13 @@ boolean Obj_TickLightningShieldVisual(mobj_t *mobj);
|
|||
void Obj_SpawnFlameShieldVisuals(mobj_t *source);
|
||||
boolean Obj_TickFlameShieldVisual(mobj_t *mobj);
|
||||
|
||||
/* Stone Shoe */
|
||||
mobj_t *Obj_SpawnStoneShoe(INT32 owner, mobj_t *victim);
|
||||
boolean Obj_TickStoneShoe(mobj_t *shoe);
|
||||
boolean Obj_TickStoneShoeChain(mobj_t *chain);
|
||||
player_t *Obj_StoneShoeOwnerPlayer(mobj_t *shoe);
|
||||
void Obj_CollideStoneShoe(mobj_t *mover, mobj_t *mobj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
flybot767.c
|
||||
lightning-shield.cpp
|
||||
flame-shield.cpp
|
||||
stone-shoe.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(versus)
|
||||
|
|
|
|||
355
src/objects/stone-shoe.cpp
Normal file
355
src/objects/stone-shoe.cpp
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2025 by James Robert Roman
|
||||
// Copyright (C) 2025 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 <cstdlib>
|
||||
|
||||
#include "objects.hpp"
|
||||
|
||||
#include "../g_game.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../m_easing.h"
|
||||
#include "../m_fixed.h"
|
||||
#include "../p_spec.h"
|
||||
#include "../r_main.h"
|
||||
#include "../tables.h"
|
||||
|
||||
using namespace srb2::objects;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Player : Mobj
|
||||
{
|
||||
bool valid() const { return player != nullptr; }
|
||||
};
|
||||
|
||||
struct Shoe;
|
||||
|
||||
struct Chain : Mobj
|
||||
{
|
||||
void hnext() = delete;
|
||||
Chain* next() const { return Mobj::hnext<Chain>(); }
|
||||
void next(Chain* n) { Mobj::hnext(n); }
|
||||
|
||||
void target() = delete;
|
||||
Shoe* shoe() const { return Mobj::target<Shoe>(); }
|
||||
void shoe(Shoe* n) { Mobj::target(n); }
|
||||
|
||||
bool valid() const;
|
||||
|
||||
bool try_damage(Player* pmo);
|
||||
|
||||
bool tick()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Shoe : Mobj
|
||||
{
|
||||
void target() = delete;
|
||||
Player* follow() const { return Mobj::target<Player>(); }
|
||||
void follow(Player* n) { Mobj::target(n); }
|
||||
|
||||
void movedir() = delete;
|
||||
INT32 dir() const { return Mobj::movedir; }
|
||||
void dir(INT32 n) { Mobj::movedir = n; }
|
||||
|
||||
void hnext() = delete;
|
||||
Chain* chain() const { return Mobj::hnext<Chain>(); }
|
||||
void chain(Chain* n) { Mobj::hnext(n); }
|
||||
|
||||
void extravalue1() = delete;
|
||||
INT32 chainLength() const { return mobj_t::extravalue1; }
|
||||
void chainLength(INT32 n) { mobj_t::extravalue1 = n; }
|
||||
|
||||
void extravalue2() = delete;
|
||||
INT32 owner() const { return mobj_t::extravalue2; }
|
||||
void owner(INT32 n) { mobj_t::extravalue2 = n; }
|
||||
|
||||
void threshold() = delete;
|
||||
bool bouncing() const { return mobj_t::threshold; }
|
||||
void bouncing(bool n) { mobj_t::threshold = n; }
|
||||
|
||||
bool valid() const { return Mobj::valid(follow()) && follow()->valid() && Mobj::valid(chain()); }
|
||||
|
||||
Fixed minDist() const { return 200 * mapobjectscale; }
|
||||
Fixed maxDist() const { return 800 * mapobjectscale; }
|
||||
|
||||
angle_t followAngle() const { return R_PointToAngle2(x, y, follow()->x, follow()->y); }
|
||||
Fixed followDistance() const { return FixedHypot(x - follow()->x, y - follow()->y); }
|
||||
|
||||
static Vec2<Fixed> followVector(angle_t a) { return Vec2<Fixed> {FCOS(a), FSIN(a)}; }
|
||||
Vec2<Fixed> followVector() const { return followVector(followAngle()); }
|
||||
|
||||
player_t* ownerPlayer() const
|
||||
{
|
||||
if (owner() < 0 || owner() >= MAXPLAYERS)
|
||||
return nullptr;
|
||||
return &players[owner()];
|
||||
}
|
||||
|
||||
static Shoe* spawn
|
||||
( INT32 owner,
|
||||
Player* victim)
|
||||
{
|
||||
Vec2<Fixed> P = followVector(victim->angle) * Fixed {-40 * mapobjectscale};
|
||||
Shoe* shoe = victim->spawn_from<Shoe>({P, 0}, MT_STONESHOE);
|
||||
|
||||
shoe->follow(victim);
|
||||
shoe->owner(owner);
|
||||
shoe->dir(0);
|
||||
shoe->fuse = 15 * TICRATE;
|
||||
|
||||
INT32 numLinks = 8;
|
||||
Chain* link = nullptr;
|
||||
|
||||
for (INT32 i = 0; i < numLinks; ++i)
|
||||
{
|
||||
Chain* node = shoe->spawn_from<Chain>(MT_STONESHOE_CHAIN);
|
||||
node->next(link);
|
||||
node->shoe(shoe);
|
||||
link = node;
|
||||
}
|
||||
|
||||
shoe->chain(link);
|
||||
shoe->chainLength(numLinks);
|
||||
|
||||
return shoe;
|
||||
}
|
||||
|
||||
bool tick()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
move();
|
||||
move_chain();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_damage
|
||||
( Player* pmo,
|
||||
Mobj* inflictor)
|
||||
{
|
||||
if (pmo == follow())
|
||||
return false;
|
||||
|
||||
if (!valid())
|
||||
return false;
|
||||
|
||||
mobj_t* source = nullptr;
|
||||
|
||||
if (ownerPlayer())
|
||||
source = ownerPlayer()->mo;
|
||||
|
||||
bool hit = false;
|
||||
|
||||
if (bouncing())
|
||||
hit = P_DamageMobj(pmo, inflictor, source, 1, DMG_TUMBLE);
|
||||
else if (FixedHypot(momx, momy) > 16 * mapobjectscale)
|
||||
hit = P_DamageMobj(pmo, inflictor, source, 1, DMG_NORMAL);
|
||||
|
||||
if (hit && ownerPlayer() && follow()->player && pmo->player)
|
||||
{
|
||||
// Give Amps to both the originator of the Shoe and the person dragging it.
|
||||
K_SpawnAmps(ownerPlayer(), K_PvPAmpReward(10, ownerPlayer(), pmo->player), pmo);
|
||||
K_SpawnAmps(follow()->player, K_PvPAmpReward(10, follow()->player, pmo->player), pmo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void animate()
|
||||
{
|
||||
INT32 speed = 20; // TODO
|
||||
tic_t t = leveltime / speed;
|
||||
INT32 th = ANGLE_180 / speed * 2;
|
||||
UINT32 ff = 0;
|
||||
|
||||
if (t % 8 > 3)
|
||||
{
|
||||
ff = FF_VERTICALFLIP;
|
||||
angle = ANGLE_180 + dir();
|
||||
}
|
||||
else
|
||||
angle = dir();
|
||||
|
||||
frame = (t % 4) | ff;
|
||||
dir(dir() + th);
|
||||
rollangle -= th;
|
||||
|
||||
old_angle = angle;
|
||||
}
|
||||
|
||||
void move()
|
||||
{
|
||||
Fixed dist = followDistance();
|
||||
angle_t a = followAngle();
|
||||
bool close = true;
|
||||
|
||||
Fixed dz = z - follow()->z;
|
||||
|
||||
if (dz < -maxDist())
|
||||
z = follow()->z - maxDist();
|
||||
else if (dz > maxDist())
|
||||
z = follow()->z + maxDist();
|
||||
|
||||
if (dist > minDist())
|
||||
{
|
||||
if (dist > maxDist())
|
||||
{
|
||||
move_origin({
|
||||
follow()->x - maxDist() * Fixed {FCOS(a)},
|
||||
follow()->y - maxDist() * Fixed {FSIN(a)},
|
||||
z,
|
||||
});
|
||||
|
||||
close = false;
|
||||
|
||||
if (P_IsObjectOnGround(this))
|
||||
{
|
||||
momz = 32 * mapobjectscale;
|
||||
bouncing(true);
|
||||
}
|
||||
}
|
||||
|
||||
thrust(a, 8 * mapobjectscale);
|
||||
|
||||
Fixed maxSpeed = 32 * mapobjectscale;
|
||||
Fixed speed = FixedHypot(momx, momy);
|
||||
|
||||
if (speed > maxSpeed)
|
||||
instathrust(a, maxSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!P_IsObjectOnGround(this))
|
||||
bouncing(false);
|
||||
}
|
||||
|
||||
if (close)
|
||||
friction -= 200;
|
||||
else
|
||||
friction += 500;
|
||||
|
||||
if (dist > maxDist())
|
||||
animate();
|
||||
else
|
||||
{
|
||||
frame = 1;
|
||||
rollangle = 0;
|
||||
angle = a;
|
||||
}
|
||||
|
||||
follow()->player->stonedrag = dist > minDist();
|
||||
|
||||
sprzoff(30 * scale());
|
||||
}
|
||||
|
||||
void move_chain()
|
||||
{
|
||||
const Fixed shoeSpriteRadius = 48 * scale();
|
||||
const Fixed chainSpriteRadius = 26 * chain()->scale();
|
||||
|
||||
Fixed fd = std::max<Fixed>(followDistance() - shoeSpriteRadius - follow()->radius - chainSpriteRadius * 2, 0);
|
||||
Fixed fdz = follow()->z - z;
|
||||
Fixed nd = fd / std::max(chainLength(), 1);
|
||||
Fixed ndz = fdz / std::max(chainLength(), 1);
|
||||
|
||||
Vec2<Fixed> v = followVector();
|
||||
Vec2<Fixed> p = pos2d() + v * nd / 2 + v * Fixed {shoeSpriteRadius + chainSpriteRadius};
|
||||
Fixed pz = z + ndz / 2;
|
||||
|
||||
Chain* node = chain();
|
||||
|
||||
while (Mobj::valid(node))
|
||||
{
|
||||
node->move_origin({p, pz});
|
||||
node->sprzoff(sprzoff());
|
||||
|
||||
// Let chain flicker like shoe does
|
||||
node->renderflags = renderflags;
|
||||
|
||||
p += v * nd;
|
||||
pz += ndz;
|
||||
|
||||
node = node->next();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool Chain::valid() const
|
||||
{
|
||||
return Mobj::valid(shoe());
|
||||
}
|
||||
|
||||
bool Chain::try_damage(Player* pmo)
|
||||
{
|
||||
if (!Mobj::valid(shoe()))
|
||||
return false;
|
||||
|
||||
return shoe()->try_damage(pmo, this);
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
mobj_t *Obj_SpawnStoneShoe(INT32 owner, mobj_t *victim)
|
||||
{
|
||||
return Shoe::spawn(owner, static_cast<Player*>(victim));
|
||||
}
|
||||
|
||||
boolean Obj_TickStoneShoe(mobj_t *shoe)
|
||||
{
|
||||
return static_cast<Shoe*>(shoe)->tick();
|
||||
}
|
||||
|
||||
boolean Obj_TickStoneShoeChain(mobj_t *chain)
|
||||
{
|
||||
return static_cast<Chain*>(chain)->tick();
|
||||
}
|
||||
|
||||
player_t *Obj_StoneShoeOwnerPlayer(mobj_t *shoe)
|
||||
{
|
||||
return static_cast<Shoe*>(shoe)->ownerPlayer();
|
||||
}
|
||||
|
||||
void Obj_CollideStoneShoe(mobj_t *mover, mobj_t *mobj)
|
||||
{
|
||||
switch (mobj->type)
|
||||
{
|
||||
case MT_STONESHOE: {
|
||||
Shoe* shoe = static_cast<Shoe*>(mobj);
|
||||
|
||||
if (!shoe->try_damage(static_cast<Player*>(mover), shoe))
|
||||
K_KartSolidBounce(mover, shoe);
|
||||
break;
|
||||
}
|
||||
|
||||
case MT_STONESHOE_CHAIN:
|
||||
static_cast<Chain*>(mobj)->try_damage(static_cast<Player*>(mover));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -425,14 +425,41 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (special->scale < special->destscale/2)
|
||||
return;
|
||||
|
||||
if (!P_CanPickupItem(player, PICKUP_PAPERITEM) || (player->itemamount && player->itemtype != special->threshold))
|
||||
if (!P_CanPickupItem(player, PICKUP_PAPERITEM))
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
if ((UINT16)(player->itemamount) + special->movecount > 255)
|
||||
player->itemamount = 255;
|
||||
if (special->threshold == KDROP_STONESHOETRAP)
|
||||
{
|
||||
if (K_TryPickMeUp(special, toucher, false))
|
||||
return;
|
||||
|
||||
if (!P_MobjWasRemoved(player->stoneShoe))
|
||||
{
|
||||
player->pflags |= PF_CASTSHADOW;
|
||||
return;
|
||||
}
|
||||
|
||||
P_SetTarget(&player->stoneShoe, Obj_SpawnStoneShoe(special->extravalue2, toucher));
|
||||
K_AddHitLag(toucher, 8, false);
|
||||
|
||||
player_t *owner = Obj_StoneShoeOwnerPlayer(special);
|
||||
if (owner)
|
||||
{
|
||||
K_SpawnAmps(player, K_PvPAmpReward(20, owner, player), toucher);
|
||||
K_SpawnAmps(owner, K_PvPAmpReward(20, owner, player), toucher);
|
||||
}
|
||||
}
|
||||
else
|
||||
player->itemamount += special->movecount;
|
||||
{
|
||||
if (player->itemamount && player->itemtype != special->threshold)
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
if ((UINT16)(player->itemamount) + special->movecount > 255)
|
||||
player->itemamount = 255;
|
||||
else
|
||||
player->itemamount += special->movecount;
|
||||
}
|
||||
}
|
||||
|
||||
S_StartSound(special, special->info->deathsound);
|
||||
|
|
@ -1087,6 +1114,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
Obj_PulleyHookTouch(special, toucher);
|
||||
return;
|
||||
|
||||
case MT_STONESHOE_CHAIN:
|
||||
Obj_CollideStoneShoe(toucher, special);
|
||||
return;
|
||||
|
||||
default: // SOC or script pickup
|
||||
P_SetTarget(&special->target, toucher);
|
||||
break;
|
||||
|
|
@ -3202,7 +3233,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
K_SpawnAmps(source->player, K_PvPAmpReward((type == DMG_WHUMBLE) ? 30 : 20, source->player, player), target);
|
||||
// Stone Shoe handles amps on its own
|
||||
if (inflictor->type != MT_STONESHOE && inflictor->type != MT_STONESHOE_CHAIN)
|
||||
K_SpawnAmps(source->player, K_PvPAmpReward((type == DMG_WHUMBLE) ? 30 : 20, source->player, player), target);
|
||||
K_BotHitPenalty(player);
|
||||
|
||||
if (G_SameTeam(source->player, player))
|
||||
|
|
|
|||
11
src/p_map.c
11
src/p_map.c
|
|
@ -1531,6 +1531,17 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
K_KartBouncing(g_tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (thing->type == MT_STONESHOE)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (g_tm.thing->z > thing->z + thing->height)
|
||||
return BMIT_CONTINUE; // overhead
|
||||
if (g_tm.thing->z + g_tm.thing->height < thing->z)
|
||||
return BMIT_CONTINUE; // underneath
|
||||
|
||||
Obj_CollideStoneShoe(g_tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if ((thing->flags & MF_SHOOTABLE) && K_PlayerCanPunt(g_tm.thing->player))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
|
|||
29
src/p_mobj.c
29
src/p_mobj.c
|
|
@ -1274,6 +1274,12 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
gravityadd *= 6;
|
||||
break;
|
||||
case MT_FLOATINGITEM: {
|
||||
if (mo->threshold == KDROP_STONESHOETRAP)
|
||||
{
|
||||
gravityadd = (5*gravityadd)/2;
|
||||
break;
|
||||
}
|
||||
|
||||
// Basically this accelerates gravity after
|
||||
// the object reached its peak vertical
|
||||
// momentum. It's a gradual acceleration up
|
||||
|
|
@ -1296,6 +1302,9 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
if (!mo->fuse)
|
||||
gravityadd *= 2;
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
gravityadd *= 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -6704,6 +6713,11 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MT_STONESHOE_CHAIN:
|
||||
{
|
||||
Obj_TickStoneShoeChain(mobj);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
if (mobj->fuse)
|
||||
{ // Scenery object fuse! Very basic!
|
||||
|
|
@ -10228,6 +10242,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
break;
|
||||
}
|
||||
|
||||
case MT_STONESHOE:
|
||||
return Obj_TickStoneShoe(mobj);
|
||||
|
||||
default:
|
||||
// check mobj against possible water content, before movement code
|
||||
P_MobjCheckWater(mobj);
|
||||
|
|
@ -10297,6 +10314,12 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
if (mobj->fuse <= 3 * TICRATE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
@ -11096,6 +11119,12 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
|
|||
thing->shadowscale = FRACUNIT;
|
||||
thing->whiteshadow = false;
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
thing->shadowscale = 2*FRACUNIT/3;
|
||||
break;
|
||||
case MT_STONESHOE_CHAIN:
|
||||
thing->shadowscale = FRACUNIT/5;
|
||||
break;
|
||||
default:
|
||||
if (thing->flags & (MF_ENEMY|MF_BOSS))
|
||||
thing->shadowscale = FRACUNIT;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue