mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
The Garden Top
This is all the visual effects and item logic of the Top minus (almost all [1]) physics adjustments when a player is riding one. While on a Top: - Otherwordly humming while floating - Cannot drift [1]. Instead, holding drift begins grinding the Top into the ground -- sparks fly out - Sprite tilts left and right as you turn - No wheel screech when turning too far - Speed lines while holding drift - Tripwire Boost effect scales to cover you AND the Top - One hit and you lose it - Throwing forward, getting hit or just losing it because you were in first place for too long: the Top flies out from under you and begins snaking like crazy - Throwing backward also makes the Top fly out from under you but it also thrusts you forward. The Top dies instantly so it's not dangerous ;-) - If you're in first for too long, it begins vibrating - If you tumble, it dances across your entire screen A loose top will tumble anyone it hits.
This commit is contained in:
parent
b5cdf25298
commit
5063a4acf1
12 changed files with 923 additions and 21 deletions
|
|
@ -290,6 +290,8 @@ typedef enum
|
|||
#define ITEMSCALE_GROW 1
|
||||
#define ITEMSCALE_SHRINK 2
|
||||
|
||||
#define GARDENTOP_MAXGRINDTIME (45)
|
||||
|
||||
// player_t struct for all respawn variables
|
||||
typedef struct respawnvars_s
|
||||
{
|
||||
|
|
|
|||
232
src/k_kart.c
232
src/k_kart.c
|
|
@ -2414,7 +2414,7 @@ void K_SpawnDriftBoostClipSpark(mobj_t *clip)
|
|||
spark->momy = clip->momx/2;
|
||||
}
|
||||
|
||||
void K_SpawnNormalSpeedLines(player_t *player)
|
||||
static void K_SpawnGenericSpeedLines(player_t *player, boolean top)
|
||||
{
|
||||
mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(PR_DECORATION,-36,36) * player->mo->scale),
|
||||
player->mo->y + (P_RandomRange(PR_DECORATION,-36,36) * player->mo->scale),
|
||||
|
|
@ -2422,20 +2422,40 @@ void K_SpawnNormalSpeedLines(player_t *player)
|
|||
MT_FASTLINE);
|
||||
|
||||
P_SetTarget(&fast->target, player->mo);
|
||||
P_InitAngle(fast, K_MomentumAngle(player->mo));
|
||||
fast->momx = 3*player->mo->momx/4;
|
||||
fast->momy = 3*player->mo->momy/4;
|
||||
fast->momz = 3*P_GetMobjZMovement(player->mo)/4;
|
||||
|
||||
K_MatchGenericExtraFlags(fast, player->mo);
|
||||
fast->z += player->mo->sprzoff;
|
||||
|
||||
if (player->tripwireLeniency)
|
||||
if (top)
|
||||
{
|
||||
fast->destscale = fast->destscale * 2;
|
||||
P_SetScale(fast, 3*fast->scale/2);
|
||||
P_InitAngle(fast, player->mo->angle);
|
||||
P_SetScale(fast, (fast->destscale =
|
||||
3 * fast->destscale / 2));
|
||||
|
||||
fast->spritexscale = 3*FRACUNIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_InitAngle(fast, K_MomentumAngle(player->mo));
|
||||
|
||||
if (player->tripwireLeniency)
|
||||
{
|
||||
fast->destscale = fast->destscale * 2;
|
||||
P_SetScale(fast, 3*fast->scale/2);
|
||||
}
|
||||
}
|
||||
|
||||
if (player->eggmanexplode)
|
||||
K_MatchGenericExtraFlags(fast, player->mo);
|
||||
|
||||
if (top)
|
||||
{
|
||||
fast->color = SKINCOLOR_SUNSLAM;
|
||||
fast->colorized = true;
|
||||
fast->renderflags |= RF_ADD;
|
||||
}
|
||||
else if (player->eggmanexplode)
|
||||
{
|
||||
// Make it red when you have the eggman speed boost
|
||||
fast->color = SKINCOLOR_RED;
|
||||
|
|
@ -2463,6 +2483,16 @@ void K_SpawnNormalSpeedLines(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
void K_SpawnNormalSpeedLines(player_t *player)
|
||||
{
|
||||
K_SpawnGenericSpeedLines(player, false);
|
||||
}
|
||||
|
||||
void K_SpawnGardenTopSpeedLines(player_t *player)
|
||||
{
|
||||
K_SpawnGenericSpeedLines(player, true);
|
||||
}
|
||||
|
||||
void K_SpawnInvincibilitySpeedLines(mobj_t *mo)
|
||||
{
|
||||
mobj_t *fast = P_SpawnMobjFromMobj(mo,
|
||||
|
|
@ -2561,14 +2591,21 @@ static void K_SpawnGrowShrinkParticles(mobj_t *mo, INT32 timer)
|
|||
|
||||
void K_SpawnBumpEffect(mobj_t *mo)
|
||||
{
|
||||
mobj_t *top = mo->player ? K_GetGardenTop(mo->player) : NULL;
|
||||
|
||||
mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP);
|
||||
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
fx->eflags |= MFE_VERTICALFLIP;
|
||||
else
|
||||
fx->eflags &= ~MFE_VERTICALFLIP;
|
||||
|
||||
fx->scale = mo->scale;
|
||||
|
||||
S_StartSound(mo, sfx_s3k49);
|
||||
if (top)
|
||||
S_StartSound(mo, top->info->attacksound);
|
||||
else
|
||||
S_StartSound(mo, sfx_s3k49);
|
||||
}
|
||||
|
||||
static SINT8 K_GlanceAtPlayers(player_t *glancePlayer)
|
||||
|
|
@ -2723,6 +2760,10 @@ void K_KartMoveAnimation(player_t *player)
|
|||
drift = intsign(player->aizdriftturn);
|
||||
turndir = 0;
|
||||
}
|
||||
else if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
drift = -turndir;
|
||||
}
|
||||
else if (turndir == 0 && drift == 0)
|
||||
{
|
||||
// Only try glancing if you're driving straight.
|
||||
|
|
@ -3288,6 +3329,46 @@ boolean K_WaterSkip(player_t *player)
|
|||
return false;
|
||||
}
|
||||
|
||||
boolean K_IsRidingFloatingTop(player_t *player)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Obj_GardenTopPlayerIsGrinding(player);
|
||||
}
|
||||
|
||||
boolean K_IsHoldingDownTop(player_t *player)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mobj_t *K_GetGardenTop(player_t *player)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (player->mo == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return player->mo->hnext;
|
||||
}
|
||||
|
||||
static fixed_t K_FlameShieldDashVar(INT32 val)
|
||||
{
|
||||
// 1 second = 75% + 50% top speed
|
||||
|
|
@ -4698,6 +4779,19 @@ fixed_t K_ItemScaleForPlayer(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
fixed_t K_DefaultPlayerRadius(player_t *player)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
return top->radius;
|
||||
}
|
||||
|
||||
return FixedMul(player->mo->scale,
|
||||
player->mo->info->radius);
|
||||
}
|
||||
|
||||
static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, INT32 flags2, fixed_t speed, SINT8 dir)
|
||||
{
|
||||
mobj_t *th;
|
||||
|
|
@ -4812,6 +4906,9 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
|
|||
th->destscale = th->destscale << 1;
|
||||
th->scalespeed = abs(th->destscale - th->scale) / (2*TICRATE);
|
||||
break;
|
||||
case MT_GARDENTOP:
|
||||
th->movefactor = finalspeed;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5472,8 +5569,11 @@ void K_DriftDustHandling(mobj_t *spawner)
|
|||
dust->destscale = spawner->scale * 3;
|
||||
dust->scalespeed = spawner->scale/12;
|
||||
|
||||
if (leveltime % 6 == 0)
|
||||
S_StartSound(spawner, sfx_screec);
|
||||
if (!spawner->player || !K_GetGardenTop(spawner->player))
|
||||
{
|
||||
if (leveltime % 6 == 0)
|
||||
S_StartSound(spawner, sfx_screec);
|
||||
}
|
||||
|
||||
K_MatchGenericExtraFlags(dust, spawner);
|
||||
|
||||
|
|
@ -5633,7 +5733,7 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
|
|||
|
||||
if (missile) // Shootables
|
||||
{
|
||||
if (dir < 0 && mapthing != MT_SPB)
|
||||
if (dir < 0 && mapthing != MT_SPB && mapthing != MT_GARDENTOP)
|
||||
{
|
||||
// Shoot backward
|
||||
mo = K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) + angleOffset, 0, PROJSPEED, dir);
|
||||
|
|
@ -6244,7 +6344,7 @@ void K_DropHnextList(player_t *player, boolean keepshields)
|
|||
flip = P_MobjFlip(player->mo);
|
||||
ponground = P_IsObjectOnGround(player->mo);
|
||||
|
||||
if (shield != KSHIELD_NONE && !keepshields)
|
||||
if (shield != KSHIELD_NONE && shield != KSHIELD_TOP && !keepshields)
|
||||
{
|
||||
if (shield == KSHIELD_LIGHTNING)
|
||||
{
|
||||
|
|
@ -6296,6 +6396,9 @@ void K_DropHnextList(player_t *player, boolean keepshields)
|
|||
orbit = false;
|
||||
type = MT_EGGMANITEM;
|
||||
break;
|
||||
case MT_GARDENTOP:
|
||||
Obj_GardenTopDestroy(player);
|
||||
return;
|
||||
// intentionally do nothing
|
||||
case MT_ROCKETSNEAKER:
|
||||
case MT_SINK_SHIELD:
|
||||
|
|
@ -7602,6 +7705,33 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
{
|
||||
const boolean onground = P_IsObjectOnGround(player->mo);
|
||||
|
||||
/* reset sprite offsets :) */
|
||||
player->mo->sprxoff = 0;
|
||||
player->mo->spryoff = 0;
|
||||
player->mo->sprzoff = 0;
|
||||
player->mo->spritexoffset = 0;
|
||||
player->mo->spriteyoffset = 0;
|
||||
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
/* FIXME: I cannot figure out how offset the
|
||||
player correctly in real time to pivot around
|
||||
the BOTTOM of the Top. This hack plus the one
|
||||
in R_PlayerSpriteRotation. */
|
||||
player->mo->spritexoffset += FixedMul(
|
||||
FixedDiv(top->height, top->scale),
|
||||
FINESINE(top->rollangle >> ANGLETOFINESHIFT));
|
||||
|
||||
player->mo->sprzoff += top->sprzoff + (
|
||||
P_GetMobjHead(top) -
|
||||
P_GetMobjFeet(player->mo));
|
||||
}
|
||||
}
|
||||
|
||||
K_UpdateOffroad(player);
|
||||
K_UpdateDraft(player);
|
||||
K_UpdateEngineSounds(player); // Thanks, VAda!
|
||||
|
|
@ -8049,8 +8179,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (cmd->buttons & BT_DRIFT)
|
||||
{
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
if (player->topdriftheld <= GARDENTOP_MAXGRINDTIME)
|
||||
player->topdriftheld++;
|
||||
|
||||
// Squish :)
|
||||
player->mo->spritexscale = 6*FRACUNIT/4;
|
||||
player->mo->spriteyscale = 2*FRACUNIT/4;
|
||||
|
||||
if (leveltime & 1)
|
||||
K_SpawnGardenTopSpeedLines(player);
|
||||
}
|
||||
// Only allow drifting while NOT trying to do an spindash input.
|
||||
if ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK)
|
||||
else if ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK)
|
||||
{
|
||||
player->pflags |= PF_DRIFTINPUT;
|
||||
}
|
||||
|
|
@ -8187,7 +8329,7 @@ void K_KartResetPlayerColor(player_t *player)
|
|||
|
||||
finalise:
|
||||
|
||||
if (player->curshield)
|
||||
if (player->curshield && player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
fullbright = true;
|
||||
}
|
||||
|
|
@ -9245,6 +9387,7 @@ void K_KartUpdatePosition(player_t *player)
|
|||
fixed_t position = 1;
|
||||
fixed_t oldposition = player->position;
|
||||
fixed_t i;
|
||||
INT32 realplayers = 0;
|
||||
|
||||
if (player->spectator || !player->mo)
|
||||
{
|
||||
|
|
@ -9259,6 +9402,8 @@ void K_KartUpdatePosition(player_t *player)
|
|||
if (!playeringame[i] || players[i].spectator || !players[i].mo)
|
||||
continue;
|
||||
|
||||
realplayers++;
|
||||
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
if (player->exiting) // End of match standings
|
||||
|
|
@ -9322,6 +9467,33 @@ void K_KartUpdatePosition(player_t *player)
|
|||
if (oldposition != position) // Changed places?
|
||||
player->positiondelay = 10; // Position number growth
|
||||
|
||||
/* except in FREE PLAY */
|
||||
if (player->curshield == KSHIELD_TOP &&
|
||||
(gametyperules & GTR_CIRCUIT) &&
|
||||
realplayers > 1)
|
||||
{
|
||||
/* grace period so you don't fall off INSTANTLY */
|
||||
if (position == 1 && player->topinfirst < 2*TICRATE)
|
||||
{
|
||||
player->topinfirst++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (position == 1)
|
||||
{
|
||||
Obj_GardenTopThrow(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->topinfirst = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player->topinfirst = 0;
|
||||
}
|
||||
|
||||
player->position = position;
|
||||
}
|
||||
|
||||
|
|
@ -9473,6 +9645,7 @@ void K_KartEbrakeVisuals(player_t *p)
|
|||
p->mo->hprev->angle = p->mo->angle;
|
||||
p->mo->hprev->fuse = TICRATE/2; // When we leave spindash for any reason, make sure this bubble goes away soon after.
|
||||
K_FlipFromObject(p->mo->hprev, p->mo);
|
||||
p->mo->hprev->sprzoff = p->mo->sprzoff;
|
||||
}
|
||||
|
||||
if (!p->spindash)
|
||||
|
|
@ -10490,6 +10663,37 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case KITEM_GARDENTOP:
|
||||
if (ATTACK_IS_DOWN && NO_HYUDORO)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
player->topinfirst = 0;
|
||||
Obj_GardenTopDeploy(player->mo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->throwdir == -1)
|
||||
{
|
||||
mobj_t *top = Obj_GardenTopDestroy(player);
|
||||
|
||||
// Fly off the Top at high speed
|
||||
P_Thrust(player->mo, K_MomentumAngle(player->mo), 80 * player->mo->scale);
|
||||
P_SetObjectMomZ(player->mo, player->mo->height / 2, true);
|
||||
|
||||
top->momx = player->mo->momx;
|
||||
top->momy = player->mo->momy;
|
||||
top->momz = player->mo->momz;
|
||||
}
|
||||
else
|
||||
{
|
||||
Obj_GardenTopThrow(player);
|
||||
S_StartSound(player->mo, sfx_tossed); // play only when actually thrown :^,J
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KITEM_BUBBLESHIELD:
|
||||
if (player->curshield != KSHIELD_BUBBLE)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ void K_SpawnDashDustRelease(player_t *player);
|
|||
void K_SpawnDriftBoostClip(player_t *player);
|
||||
void K_SpawnDriftBoostClipSpark(mobj_t *clip);
|
||||
void K_SpawnNormalSpeedLines(player_t *player);
|
||||
void K_SpawnGardenTopSpeedLines(player_t *player);
|
||||
void K_SpawnInvincibilitySpeedLines(mobj_t *mo);
|
||||
void K_SpawnBumpEffect(mobj_t *mo);
|
||||
void K_KartMoveAnimation(player_t *player);
|
||||
|
|
@ -144,6 +145,9 @@ tripwirepass_t K_TripwirePassConditions(player_t *player);
|
|||
boolean K_TripwirePass(player_t *player);
|
||||
boolean K_WaterRun(player_t *player);
|
||||
boolean K_WaterSkip(player_t *player);
|
||||
boolean K_IsRidingFloatingTop(player_t *player);
|
||||
boolean K_IsHoldingDownTop(player_t *player);
|
||||
mobj_t *K_GetGardenTop(player_t *player);
|
||||
void K_ApplyTripWire(player_t *player, tripwirestate_t state);
|
||||
INT16 K_GetSpindashChargeTime(player_t *player);
|
||||
fixed_t K_GetSpindashChargeSpeed(player_t *player);
|
||||
|
|
@ -170,6 +174,7 @@ UINT8 K_GetOrbinautItemFrame(UINT8 count);
|
|||
boolean K_IsSPBInGame(void);
|
||||
void K_KartEbrakeVisuals(player_t *p);
|
||||
void K_HandleDirectionalInfluence(player_t *player);
|
||||
fixed_t K_DefaultPlayerRadius(player_t *player);
|
||||
|
||||
// sound stuff for lua
|
||||
void K_PlayAttackTaunt(mobj_t *source);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,14 @@ void Obj_HyudoroThink(mobj_t *actor);
|
|||
void Obj_HyudoroCenterThink(mobj_t *actor);
|
||||
void Obj_HyudoroCollide(mobj_t *special, mobj_t *toucher);
|
||||
|
||||
/* Garden Top */
|
||||
void Obj_GardenTopDeploy(mobj_t *rider);
|
||||
mobj_t *Obj_GardenTopThrow(player_t *player);
|
||||
mobj_t *Obj_GardenTopDestroy(player_t *player);
|
||||
void Obj_GardenTopThink(mobj_t *top);
|
||||
void Obj_GardenTopSparkThink(mobj_t *spark);
|
||||
boolean Obj_GardenTopPlayerIsGrinding(player_t *player);
|
||||
|
||||
/* Shrink */
|
||||
void Obj_PohbeeThinker(mobj_t *pohbee);
|
||||
void Obj_PohbeeRemoved(mobj_t *pohbee);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
hyudoro.c
|
||||
gardentop.c
|
||||
shrink.c
|
||||
item-debris.c
|
||||
spb.c
|
||||
|
|
|
|||
612
src/objects/gardentop.c
Normal file
612
src/objects/gardentop.c
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_local.h"
|
||||
#include "../s_sound.h"
|
||||
|
||||
// TODO: separate from this file
|
||||
static fixed_t K_FlipZOffset(mobj_t *us, mobj_t *them)
|
||||
{
|
||||
fixed_t z = 0;
|
||||
|
||||
if (them->eflags & MFE_VERTICALFLIP)
|
||||
z += them->height;
|
||||
|
||||
if (us->eflags & MFE_VERTICALFLIP)
|
||||
z -= us->height;
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
#define SPARKCOLOR SKINCOLOR_ROBIN
|
||||
|
||||
enum {
|
||||
TOP_ANCHORED,
|
||||
TOP_LOOSE,
|
||||
};
|
||||
|
||||
#define topsfx_floating sfx_s3k7d
|
||||
#define topsfx_grinding sfx_s3k79
|
||||
#define topsfx_lift sfx_s3ka0
|
||||
|
||||
#define rider_top(o) ((o)->hnext)
|
||||
|
||||
#define top_mode(o) ((o)->extravalue1)
|
||||
#define top_float(o) ((o)->lastlook)
|
||||
#define top_sound(o) ((o)->extravalue2)
|
||||
#define top_soundtic(o) ((o)->movecount)
|
||||
|
||||
/* TOP_ANCHORED */
|
||||
#define top_rider(o) ((o)->tracer)
|
||||
|
||||
/* TOP_LOOSE */
|
||||
#define top_waveangle(o) ((o)->movedir)
|
||||
/* wavepause will take mobjinfo reactiontime automatically */
|
||||
#define top_wavepause(o) ((o)->reactiontime)
|
||||
|
||||
#define spark_top(o) ((o)->target)
|
||||
#define spark_angle(o) ((o)->movedir)
|
||||
|
||||
static inline player_t *
|
||||
get_rider_player (mobj_t *rider)
|
||||
{
|
||||
return rider ? rider->player : NULL;
|
||||
}
|
||||
|
||||
static inline player_t *
|
||||
get_top_rider_player (mobj_t *top)
|
||||
{
|
||||
return get_rider_player(top_rider(top));
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
is_top_grind_input (mobj_t *top)
|
||||
{
|
||||
player_t *player = get_top_rider_player(top);
|
||||
|
||||
return player && K_IsHoldingDownTop(player);
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
is_top_grinding (mobj_t *top)
|
||||
{
|
||||
if (top_float(top) > 0)
|
||||
return false;
|
||||
|
||||
if (!P_IsObjectOnGround(top))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
grind_spark_base_scale (player_t *player)
|
||||
{
|
||||
return FRACUNIT/2 +
|
||||
player->topdriftheld * FRACUNIT
|
||||
/ GARDENTOP_MAXGRINDTIME;
|
||||
}
|
||||
|
||||
static inline INT32
|
||||
get_player_steer_tilt
|
||||
( player_t * player,
|
||||
INT32 stages)
|
||||
{
|
||||
return player->steering
|
||||
* stages
|
||||
|
||||
// 1 degree for a full turn
|
||||
/ KART_FULLTURN
|
||||
* ANG1
|
||||
|
||||
// stages is for fractions of a full turn, divide to
|
||||
// get a fraction of a degree
|
||||
/ stages
|
||||
|
||||
// angle is inverted in reverse gravity
|
||||
* P_MobjFlip(player->mo);
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
goofy_shake (fixed_t n)
|
||||
{
|
||||
return P_RandomRange(PR_DECORATION, -1, 1) * n;
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_top
|
||||
( mobj_t * top,
|
||||
INT32 mode)
|
||||
{
|
||||
top_mode(top) = mode;
|
||||
top_float(top) = 0;
|
||||
top_sound(top) = sfx_None;
|
||||
top_waveangle(top) = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_spark
|
||||
( mobj_t * top,
|
||||
angle_t angle)
|
||||
{
|
||||
mobj_t *spark = P_SpawnMobjFromMobj(
|
||||
top, 0, 0, 0, MT_GARDENTOPSPARK);
|
||||
|
||||
P_SetTarget(&spark_top(spark), top);
|
||||
|
||||
spark_angle(spark) = angle;
|
||||
|
||||
spark->color = SPARKCOLOR;
|
||||
spark->spriteyscale = 3*FRACUNIT/4;
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_spark_circle
|
||||
( mobj_t * top,
|
||||
UINT8 n)
|
||||
{
|
||||
const angle_t a = ANGLE_MAX / n;
|
||||
|
||||
UINT8 i;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
spawn_spark(top, i * a);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_grind_spark (mobj_t *top)
|
||||
{
|
||||
mobj_t *rider = top_rider(top);
|
||||
mobj_t *spark;
|
||||
|
||||
player_t *player = NULL;
|
||||
|
||||
fixed_t x = 0;
|
||||
fixed_t y = 0;
|
||||
|
||||
angle_t angle = top->angle;
|
||||
|
||||
if (rider)
|
||||
{
|
||||
const fixed_t speed = -20 * top->scale;
|
||||
|
||||
angle = K_MomentumAngle(rider);
|
||||
|
||||
x = P_ReturnThrustX(rider, angle, speed);
|
||||
y = P_ReturnThrustY(rider, angle, speed);
|
||||
|
||||
player = get_rider_player(rider);
|
||||
}
|
||||
|
||||
spark = P_SpawnMobjFromMobj(
|
||||
top, x, y, 0, MT_DRIFTSPARK);
|
||||
|
||||
spark->momx = x;
|
||||
spark->momy = y;
|
||||
|
||||
P_SetMobjState(spark, S_DRIFTSPARK_A1);
|
||||
|
||||
spark->angle = angle;
|
||||
spark->color = SPARKCOLOR;
|
||||
|
||||
if (player)
|
||||
{
|
||||
spark->destscale = FixedMul(spark->destscale,
|
||||
grind_spark_base_scale(player));
|
||||
|
||||
P_SetScale(spark, spark->destscale);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
loop_sfx
|
||||
( mobj_t * top,
|
||||
sfxenum_t sfx)
|
||||
{
|
||||
switch (sfx)
|
||||
{
|
||||
case topsfx_floating:
|
||||
if (S_SoundPlaying(top, sfx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case topsfx_grinding:
|
||||
if ((sfxenum_t)top_sound(top) != sfx)
|
||||
{
|
||||
top_soundtic(top) = leveltime;
|
||||
}
|
||||
|
||||
/* FIXME: could this sound just be looped
|
||||
normally? :face_holding_back_tears: */
|
||||
if ((leveltime - top_soundtic(top)) % 28 > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
S_StartSound(top, sfx);
|
||||
}
|
||||
|
||||
static void
|
||||
modulate (mobj_t *top)
|
||||
{
|
||||
const fixed_t max_hover = top->height / 4;
|
||||
const fixed_t hover_step = max_hover / 4;
|
||||
|
||||
sfxenum_t ambience = sfx_None;
|
||||
|
||||
if (is_top_grind_input(top))
|
||||
{
|
||||
if (top_float(top) == max_hover)
|
||||
{
|
||||
P_SetMobjState(top, S_GARDENTOP_SINKING1);
|
||||
}
|
||||
|
||||
if (top_float(top) > 0)
|
||||
{
|
||||
top_float(top) -= hover_step;
|
||||
}
|
||||
else if (P_IsObjectOnGround(top))
|
||||
{
|
||||
spawn_grind_spark(top);
|
||||
ambience = topsfx_grinding;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (top_float(top) == 0)
|
||||
{
|
||||
P_SetMobjState(top, S_GARDENTOP_FLOATING);
|
||||
|
||||
S_StopSoundByID(top, topsfx_grinding);
|
||||
S_StartSound(top, topsfx_lift);
|
||||
}
|
||||
|
||||
if (top_float(top) < max_hover)
|
||||
{
|
||||
top_float(top) += hover_step;
|
||||
}
|
||||
else
|
||||
{
|
||||
ambience = topsfx_floating;
|
||||
}
|
||||
}
|
||||
|
||||
top->sprzoff = top_float(top) * P_MobjFlip(top);
|
||||
|
||||
if (ambience)
|
||||
{
|
||||
loop_sfx(top, ambience);
|
||||
}
|
||||
|
||||
top_sound(top) = ambience;
|
||||
}
|
||||
|
||||
static void
|
||||
tilt (mobj_t *top)
|
||||
{
|
||||
player_t *player = get_top_rider_player(top);
|
||||
|
||||
INT32 tilt = top->rollangle;
|
||||
|
||||
if (is_top_grind_input(top))
|
||||
{
|
||||
const angle_t tiltmax = ANGLE_22h;
|
||||
|
||||
tilt += get_player_steer_tilt(player, 4);
|
||||
|
||||
if (abs(tilt) > tiltmax)
|
||||
{
|
||||
tilt = intsign(tilt) * tiltmax;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const angle_t decay = ANG1 * 2;
|
||||
|
||||
if (abs(tilt) > decay)
|
||||
{
|
||||
tilt -= intsign(tilt) * decay;
|
||||
}
|
||||
else
|
||||
{
|
||||
tilt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
top->rollangle = tilt;
|
||||
|
||||
/* Vibrate left and right if you're about to lose it. */
|
||||
if (player && player->topinfirst)
|
||||
{
|
||||
top->spritexoffset = P_LerpFlip(32*FRACUNIT, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
top->spritexoffset = 0;
|
||||
}
|
||||
|
||||
/* Go ABSOLUTELY NUTS if the player is tumbling... */
|
||||
if (player && player->tumbleBounces > 0)
|
||||
{
|
||||
const fixed_t yofs = 48 * FRACUNIT;
|
||||
const fixed_t ofs3d = 24 * top->scale;
|
||||
|
||||
/* spriteyoffset scales, e.g. with K_Squish */
|
||||
top->spriteyoffset = FixedDiv(
|
||||
goofy_shake(yofs), top->spriteyscale);
|
||||
|
||||
top->sprxoff = goofy_shake(ofs3d);
|
||||
top->spryoff = goofy_shake(ofs3d);
|
||||
}
|
||||
else
|
||||
{
|
||||
top->spriteyoffset = 0;
|
||||
top->sprxoff = 0;
|
||||
top->spryoff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
anchor_top (mobj_t *top)
|
||||
{
|
||||
mobj_t *rider = top_rider(top);
|
||||
player_t *player = get_rider_player(rider);
|
||||
|
||||
if (player && player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
P_RemoveMobj(top);
|
||||
return;
|
||||
}
|
||||
|
||||
tilt(top);
|
||||
|
||||
P_MoveOrigin(top, rider->x, rider->y,
|
||||
rider->z + K_FlipZOffset(top, rider));
|
||||
|
||||
K_GenericExtraFlagsNoZAdjust(top, rider);
|
||||
|
||||
/* Copying the Z momentum lets the Top squash and stretch
|
||||
as it falls with the player. Don't copy the X/Y
|
||||
momentum because then it would always get slightly
|
||||
ahead of the player. */
|
||||
top->momx = 0;
|
||||
top->momy = 0;
|
||||
top->momz = rider->momz;
|
||||
|
||||
/* The Z momentum can put the Top slightly ahead of the
|
||||
player in that axis too. It looks cool if the Top
|
||||
falls below you but not if it bounces up. */
|
||||
if (top->momz * P_MobjFlip(top) > 0)
|
||||
{
|
||||
top->momz = 0;
|
||||
}
|
||||
|
||||
/* match rider's slope tilt */
|
||||
top->pitch = rider->pitch;
|
||||
top->roll = rider->roll;
|
||||
}
|
||||
|
||||
static void
|
||||
loose_think (mobj_t *top)
|
||||
{
|
||||
const fixed_t thrustamount = top->movefactor;
|
||||
const angle_t momangle = K_MomentumAngle(top);
|
||||
|
||||
angle_t ang = top->angle;
|
||||
|
||||
mobj_t *ghost = P_SpawnGhostMobj(top);
|
||||
ghost->colorized = true; // already has color!
|
||||
|
||||
if (AngleDelta(ang, momangle) > ANGLE_90)
|
||||
{
|
||||
top->angle = momangle;
|
||||
}
|
||||
|
||||
if (top_wavepause(top))
|
||||
{
|
||||
top_wavepause(top)--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* oscillate between +90 and -90 degrees */
|
||||
ang += AbsAngle(top_waveangle(top)) - ANGLE_90;
|
||||
}
|
||||
|
||||
P_InstaThrust(top, top->angle, thrustamount);
|
||||
P_Thrust(top, ang, thrustamount);
|
||||
|
||||
//top_waveangle(top) = (angle_t)top_waveangle(top) + ANG10;
|
||||
top_waveangle(top) += ANG10;
|
||||
|
||||
/* intangibility grace period */
|
||||
if (top->threshold > 0)
|
||||
{
|
||||
top->threshold--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
anchor_spark (mobj_t *spark)
|
||||
{
|
||||
mobj_t *top = spark_top(spark);
|
||||
mobj_t *rider = top_rider(top);
|
||||
player_t *player = get_rider_player(rider);
|
||||
|
||||
const angle_t angle = top->angle + spark_angle(spark);
|
||||
const fixed_t x = P_ReturnThrustX(top, angle, spark->scale);
|
||||
const fixed_t y = P_ReturnThrustY(top, angle, spark->scale);
|
||||
|
||||
/* FIXME: THIS FUNCTION FUCKING SUCKS */
|
||||
K_FlipFromObject(spark, top);
|
||||
|
||||
P_MoveOrigin(spark, top->x + x, top->y + y,
|
||||
top->z + K_FlipZOffset(spark, top));
|
||||
|
||||
spark->angle = angle;
|
||||
|
||||
if (player)
|
||||
{
|
||||
const fixed_t topspeed =
|
||||
K_GetKartSpeed(player, false, false);
|
||||
|
||||
const fixed_t speed = FixedHypot(
|
||||
rider->momx, rider->momy);
|
||||
|
||||
P_SetScale(spark, FixedMul(top->scale, FRACUNIT/2 +
|
||||
FixedDiv(speed / 2, topspeed)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Obj_GardenTopDeploy (mobj_t *rider)
|
||||
{
|
||||
player_t *player = rider->player;
|
||||
|
||||
mobj_t *top = P_SpawnMobjFromMobj(
|
||||
rider, 0, 0, 0, MT_GARDENTOP);
|
||||
|
||||
init_top(top, TOP_ANCHORED);
|
||||
|
||||
top->flags |= MF_NOCLIPHEIGHT;
|
||||
|
||||
/* only the player's shadow needs to be rendered */
|
||||
top->shadowscale = 0;
|
||||
|
||||
P_SetTarget(&top_rider(top), rider);
|
||||
P_SetTarget(&rider_top(rider), top);
|
||||
|
||||
if (player)
|
||||
{
|
||||
player->curshield = KSHIELD_TOP;
|
||||
rider->radius = K_DefaultPlayerRadius(player);
|
||||
}
|
||||
|
||||
spawn_spark_circle(top, 6);
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_GardenTopThrow (player_t *player)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
const fixed_t oldfloat = top_float(top);
|
||||
const fixed_t height = top->height;
|
||||
|
||||
K_UpdateHnextList(player, true);
|
||||
|
||||
/* Sucks that another one needs to be spawned but
|
||||
this way, the throwing function can be used. */
|
||||
top = K_ThrowKartItem(
|
||||
player, true, MT_GARDENTOP, 1, 0, 0);
|
||||
|
||||
init_top(top, TOP_LOOSE);
|
||||
|
||||
top_float(top) = oldfloat;
|
||||
top_waveangle(top) = 0;
|
||||
|
||||
/* prevents it from hitting us on its way out */
|
||||
top->threshold = 20;
|
||||
|
||||
/* ensure it's tangible */
|
||||
top->flags &= ~(MF_NOCLIPTHING);
|
||||
|
||||
/* Put player PHYSICALLY on top. While riding the
|
||||
Top, player collision was used and the player
|
||||
technically remained on the ground. Now they
|
||||
should fall off. */
|
||||
P_SetOrigin(player->mo, player->mo->x, player->mo->y,
|
||||
player->mo->z + height * P_MobjFlip(player->mo));
|
||||
|
||||
if (player->itemamount > 0)
|
||||
player->itemamount--;
|
||||
|
||||
if (player->itemamount <= 0)
|
||||
player->itemtype = KITEM_NONE;
|
||||
|
||||
player->curshield = KSHIELD_NONE;
|
||||
|
||||
player->mo->radius = K_DefaultPlayerRadius(player);
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_GardenTopDestroy (player_t *player)
|
||||
{
|
||||
mobj_t *top = Obj_GardenTopThrow(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
/* kill kill kill die die die */
|
||||
P_KillMobj(top, NULL, NULL, DMG_NORMAL);
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_GardenTopThink (mobj_t *top)
|
||||
{
|
||||
modulate(top);
|
||||
|
||||
switch (top_mode(top))
|
||||
{
|
||||
case TOP_ANCHORED:
|
||||
if (top_rider(top))
|
||||
{
|
||||
anchor_top(top);
|
||||
}
|
||||
break;
|
||||
|
||||
case TOP_LOOSE:
|
||||
loose_think(top);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Obj_GardenTopSparkThink (mobj_t *spark)
|
||||
{
|
||||
mobj_t *top = spark_top(spark);
|
||||
|
||||
if (!top)
|
||||
{
|
||||
P_RemoveMobj(spark);
|
||||
return;
|
||||
}
|
||||
|
||||
anchor_spark(spark);
|
||||
|
||||
if (is_top_grinding(top))
|
||||
{
|
||||
spark->renderflags ^= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
spark->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
Obj_GardenTopPlayerIsGrinding (player_t *player)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
return top ? is_top_grinding(top) : false;
|
||||
}
|
||||
|
|
@ -143,6 +143,7 @@ void Obj_OrbinautThink(mobj_t *th)
|
|||
boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
boolean damageitem = false;
|
||||
boolean tumbleitem = false;
|
||||
boolean sprung = false;
|
||||
|
||||
if ((orbinaut_selfdelay(t1) > 0 && t2->hitlag > 0)
|
||||
|
|
@ -173,6 +174,11 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (t1->type == MT_GARDENTOP)
|
||||
{
|
||||
tumbleitem = true;
|
||||
}
|
||||
|
||||
if (t2->player)
|
||||
{
|
||||
if ((t2->player->flashing > 0 && t2->hitlag == 0)
|
||||
|
|
@ -190,7 +196,8 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
else
|
||||
{
|
||||
// Player Damage
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_WIPEOUT|DMG_WOMBO);
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO |
|
||||
(tumbleitem ? DMG_TUMBLE : DMG_WIPEOUT));
|
||||
K_KartBouncing(t2, t1);
|
||||
S_StartSound(t2, sfx_s3k7b);
|
||||
}
|
||||
|
|
@ -233,6 +240,11 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
damageitem = true;
|
||||
}
|
||||
|
||||
if (t1->type == MT_GARDENTOP)
|
||||
{
|
||||
damageitem = false;
|
||||
}
|
||||
|
||||
if (damageitem)
|
||||
{
|
||||
// This Item Damage
|
||||
|
|
|
|||
|
|
@ -2014,6 +2014,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
player->emeralds = 0;
|
||||
K_CheckEmeralds(source->player);
|
||||
}
|
||||
|
||||
/* Drop "shield" immediately on contact. */
|
||||
if (source->player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
Obj_GardenTopDestroy(source->player);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
10
src/p_map.c
10
src/p_map.c
|
|
@ -866,6 +866,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ
|
||||
|| tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG
|
||||
|| tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK
|
||||
|| tmthing->type == MT_GARDENTOP
|
||||
|| (tmthing->type == MT_PLAYER && thing->target != tmthing)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -881,6 +882,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ
|
||||
|| thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG
|
||||
|| thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK
|
||||
|| thing->type == MT_GARDENTOP
|
||||
|| (thing->type == MT_PLAYER && tmthing->target != thing)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -901,6 +903,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ
|
||||
|| tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG
|
||||
|| tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK
|
||||
|| tmthing->type == MT_GARDENTOP
|
||||
|| (tmthing->type == MT_PLAYER)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -915,6 +918,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ
|
||||
|| thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG
|
||||
|| thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK
|
||||
|| thing->type == MT_GARDENTOP
|
||||
|| (thing->type == MT_PLAYER)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -932,7 +936,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
|
||||
if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ
|
||||
|| tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD)
|
||||
|| tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD
|
||||
|| tmthing->type == MT_GARDENTOP)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
|
|
@ -943,7 +948,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return Obj_OrbinautJawzCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||
}
|
||||
else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ
|
||||
|| thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD)
|
||||
|| thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD
|
||||
|| thing->type == MT_GARDENTOP)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
|
|
|
|||
37
src/p_mobj.c
37
src/p_mobj.c
|
|
@ -1734,6 +1734,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
switch (mo->type)
|
||||
{
|
||||
case MT_ORBINAUT: // Orbinaut speed decreasing
|
||||
case MT_GARDENTOP:
|
||||
if (mo->health > 1)
|
||||
{
|
||||
S_StartSound(mo, mo->info->attacksound);
|
||||
|
|
@ -6324,6 +6325,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
|
|||
return false;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
case MT_GARDENTOP:
|
||||
case MT_ORBINAUT_SHIELD:
|
||||
case MT_BANANA_SHIELD:
|
||||
case MT_EGGMANITEM_SHIELD:
|
||||
|
|
@ -7028,7 +7030,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case MT_TRIPWIREBOOST:
|
||||
case MT_TRIPWIREBOOST: {
|
||||
mobj_t *top;
|
||||
fixed_t newHeight;
|
||||
fixed_t newScale;
|
||||
|
||||
if (!mobj->target || !mobj->target->health
|
||||
|| !mobj->target->player || !mobj->target->player->tripwireLeniency)
|
||||
{
|
||||
|
|
@ -7036,10 +7042,21 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
return false;
|
||||
}
|
||||
|
||||
newHeight = mobj->target->height;
|
||||
newScale = mobj->target->scale;
|
||||
|
||||
top = K_GetGardenTop(mobj->target->player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
newHeight += 5 * top->height / 4;
|
||||
newScale = FixedMul(newScale, FixedDiv(newHeight / 2, mobj->target->height));
|
||||
}
|
||||
|
||||
mobj->angle = K_MomentumAngle(mobj->target);
|
||||
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (mobj->target->height >> 1));
|
||||
mobj->destscale = mobj->target->scale;
|
||||
P_SetScale(mobj, mobj->target->scale);
|
||||
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (newHeight / 2));
|
||||
mobj->destscale = newScale;
|
||||
P_SetScale(mobj, newScale);
|
||||
|
||||
if (mobj->extravalue1)
|
||||
{
|
||||
|
|
@ -7111,6 +7128,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_BOOSTFLAME:
|
||||
if (!mobj->target || !mobj->target->health)
|
||||
{
|
||||
|
|
@ -7682,6 +7700,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MT_GARDENTOP:
|
||||
{
|
||||
Obj_GardenTopThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_GARDENTOPSPARK:
|
||||
{
|
||||
Obj_GardenTopSparkThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_HYUDORO:
|
||||
{
|
||||
Obj_HyudoroThink(mobj);
|
||||
|
|
@ -9727,6 +9755,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
|
|||
case MT_BUBBLESHIELD:
|
||||
case MT_BUBBLESHIELDTRAP:
|
||||
case MT_FLAMESHIELD:
|
||||
case MT_GARDENTOP:
|
||||
thing->shadowscale = FRACUNIT;
|
||||
break;
|
||||
case MT_RING:
|
||||
|
|
|
|||
|
|
@ -3263,6 +3263,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
}
|
||||
}
|
||||
|
||||
/* The Top is Big Large so zoom out */
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
camdist += 40 * mapobjectscale;
|
||||
camheight += 40 * mapobjectscale;
|
||||
}
|
||||
|
||||
if (!resetcalled && (leveltime >= introtime && timeover != 2)
|
||||
&& (t_cam_rotate[num] != -42))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
|
|||
|
||||
angle_t rollAngle = 0;
|
||||
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (player->mo->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
rollAngle -= player->underwatertilt;
|
||||
|
|
@ -61,6 +63,14 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
|
|||
(17 / player->stairjank));
|
||||
}
|
||||
|
||||
if (top)
|
||||
{
|
||||
/* FIXME: why does it not look right at more acute
|
||||
angles without this? There's a related hack to
|
||||
spritexoffset in K_KartPlayerThink. */
|
||||
rollAngle += 3 * (INT32)top->rollangle / 2;
|
||||
}
|
||||
|
||||
return rollAngle;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue