mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-03-11 21:56:43 +00:00
Merge branch 'stun' into 'master'
Add stun mechanic & Flybot767 See merge request kart-krew-dev/ring-racers-internal!2537
This commit is contained in:
commit
88e1a9e718
17 changed files with 326 additions and 44 deletions
|
|
@ -724,6 +724,8 @@ struct player_t
|
|||
UINT8 noEbrakeMagnet; // Briefly disable 2.2 responsive ebrake if you're bumped by another player.
|
||||
UINT8 tumbleBounces;
|
||||
UINT16 tumbleHeight; // In *mobjscaled* fracunits, or mfu, not raw fu
|
||||
UINT16 stunned; // Number of tics during which rings cannot be picked up
|
||||
UINT8 stunnedCombo; // Number of hits sustained while stunned, reduces consecutive stun penalties
|
||||
UINT8 justDI; // Turn-lockout timer to briefly prevent unintended turning after DI, resets when actionable or no input
|
||||
boolean flipDI; // Bananas flip the DI direction. Was a bug, but it made bananas much more interesting.
|
||||
|
||||
|
|
|
|||
|
|
@ -3081,6 +3081,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_BADNIK_EXPLOSION_SHOCKWAVE2",
|
||||
"S_BADNIK_EXPLOSION1",
|
||||
"S_BADNIK_EXPLOSION2",
|
||||
|
||||
// Flybot767 (stun)
|
||||
"S_FLYBOT767",
|
||||
};
|
||||
|
||||
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
|
||||
|
|
@ -3973,6 +3976,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_PULLUPHOOK",
|
||||
|
||||
"MT_AMPS",
|
||||
|
||||
"MT_FLYBOT767",
|
||||
};
|
||||
|
||||
const char *const MOBJFLAG_LIST[] = {
|
||||
|
|
@ -5246,6 +5251,11 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"TN_CHANGEPITCH",TN_CHANGEPITCH},
|
||||
{"TN_LOOPING",TN_LOOPING},
|
||||
|
||||
{"PICKUP_RINGORSPHERE", PICKUP_RINGORSPHERE},
|
||||
{"PICKUP_ITEMBOX", PICKUP_ITEMBOX},
|
||||
{"PICKUP_EGGBOX", PICKUP_EGGBOX},
|
||||
{"PICKUP_PAPERITEM", PICKUP_PAPERITEM},
|
||||
|
||||
{NULL,0}
|
||||
};
|
||||
|
||||
|
|
|
|||
32
src/info.c
32
src/info.c
|
|
@ -771,6 +771,9 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"DIEM", // smoke
|
||||
"DIEN", // explosion
|
||||
|
||||
// Flybot767 (stun)
|
||||
"STUN",
|
||||
|
||||
// Pulley
|
||||
"HCCH",
|
||||
"HCHK",
|
||||
|
|
@ -3632,6 +3635,9 @@ state_t states[NUMSTATES] =
|
|||
{SPR_NULL, 0, 1, {A_PlaySound}, sfx_s3k3d, 1, S_BATTLEBUMPER_EXBLAST1}, // S_BADNIK_EXPLOSION_SHOCKWAVE2
|
||||
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_BADNIK_EXPLOSION2}, // S_BADNIK_EXPLOSION1
|
||||
{SPR_WIPD, FF_FULLBRIGHT|FF_RANDOMANIM|FF_ANIMATE, 30, {NULL}, 9, 3, S_NULL}, // S_BADNIK_EXPLOSION2
|
||||
|
||||
// Flybot767 (stun)
|
||||
{SPR_STUN, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 4, 4, S_NULL}, // S_FLYBOT767
|
||||
};
|
||||
|
||||
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||
|
|
@ -22320,6 +22326,32 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_FLYBOT767
|
||||
-1, // doomednum
|
||||
S_FLYBOT767, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_pop, // deathsound
|
||||
4*FRACUNIT, // speed
|
||||
32*FRACUNIT, // radius
|
||||
15*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1306,6 +1306,9 @@ typedef enum sprite
|
|||
SPR_DIEM, // smoke
|
||||
SPR_DIEN, // explosion
|
||||
|
||||
// Flybot767 (stun)
|
||||
SPR_STUN,
|
||||
|
||||
// Pulley
|
||||
SPR_HCCH,
|
||||
SPR_HCHK,
|
||||
|
|
@ -4117,6 +4120,9 @@ typedef enum state
|
|||
S_BADNIK_EXPLOSION1,
|
||||
S_BADNIK_EXPLOSION2,
|
||||
|
||||
// Flybot767 (stun)
|
||||
S_FLYBOT767,
|
||||
|
||||
S_FIRSTFREESLOT,
|
||||
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
|
||||
NUMSTATES
|
||||
|
|
@ -5032,6 +5038,8 @@ typedef enum mobj_type
|
|||
|
||||
MT_AMPS,
|
||||
|
||||
MT_FLYBOT767,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
|
||||
NUMMOBJTYPES
|
||||
|
|
|
|||
|
|
@ -497,7 +497,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
|||
break;
|
||||
}
|
||||
|
||||
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 1))
|
||||
if (P_CanPickupItem(g_nudgeSearch.botmo->player, PICKUP_ITEMBOX))
|
||||
{
|
||||
K_AddAttackObject(thing, side, ((thing->extravalue1 < RINGBOX_TIME) ? 10 : 20));
|
||||
}
|
||||
|
|
@ -508,7 +508,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
|||
break;
|
||||
}
|
||||
|
||||
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 1)) // Can pick up an actual item
|
||||
if (P_CanPickupItem(g_nudgeSearch.botmo->player, PICKUP_ITEMBOX)) // Can pick up an actual item
|
||||
{
|
||||
const UINT8 stealth = K_EggboxStealth(thing->x, thing->y);
|
||||
const UINT8 requiredstealth = (g_nudgeSearch.botmo->player->botvars.difficulty * g_nudgeSearch.botmo->player->botvars.difficulty);
|
||||
|
|
@ -529,7 +529,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
|||
break;
|
||||
}
|
||||
|
||||
if (P_CanPickupItem(g_nudgeSearch.botmo->player, 3))
|
||||
if (P_CanPickupItem(g_nudgeSearch.botmo->player, PICKUP_PAPERITEM))
|
||||
{
|
||||
K_AddAttackObject(thing, side, 20);
|
||||
}
|
||||
|
|
@ -541,8 +541,8 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
|
|||
break;
|
||||
}
|
||||
|
||||
if ((RINGTOTAL(g_nudgeSearch.botmo->player) < 20 && !(g_nudgeSearch.botmo->player->pflags & PF_RINGLOCK)
|
||||
&& P_CanPickupItem(g_nudgeSearch.botmo->player, 0))
|
||||
if ((RINGTOTAL(g_nudgeSearch.botmo->player) < 20
|
||||
&& P_CanPickupItem(g_nudgeSearch.botmo->player, PICKUP_RINGORSPHERE))
|
||||
&& !thing->extravalue1
|
||||
&& (g_nudgeSearch.botmo->player->itemtype != KITEM_LIGHTNINGSHIELD))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
|
|||
if (t1->health <= 0 || t2->health <= 0)
|
||||
return true;
|
||||
|
||||
if (!P_CanPickupItem(t2->player, 2))
|
||||
if (!P_CanPickupItem(t2->player, PICKUP_EGGBOX))
|
||||
return true;
|
||||
|
||||
K_DropItems(t2->player);
|
||||
|
|
|
|||
31
src/k_kart.c
31
src/k_kart.c
|
|
@ -8819,7 +8819,7 @@ static inline BlockItReturn_t PIT_AttractingRings(mobj_t *thing)
|
|||
return BMIT_CONTINUE; // Too far away
|
||||
}
|
||||
|
||||
if (RINGTOTAL(attractmo->player) >= 20 || (attractmo->player->pflags & PF_RINGLOCK))
|
||||
if (RINGTOTAL(attractmo->player) >= 20 || !P_CanPickupItem(attractmo->player, PICKUP_RINGORSPHERE))
|
||||
{
|
||||
// Already reached max -- just joustle rings around.
|
||||
|
||||
|
|
@ -9379,6 +9379,33 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
if (player->ringdelay)
|
||||
player->ringdelay--;
|
||||
|
||||
if ((player->stunned > 0)
|
||||
&& (player->respawn.state == RESPAWNST_NONE)
|
||||
&& !P_PlayerInPain(player)
|
||||
&& P_IsObjectOnGround(player->mo)
|
||||
)
|
||||
{
|
||||
// MEGA FUCKING HACK BECAUSE P_SAVEG MOBJS ARE FULL
|
||||
// Would updating player_saveflags to 32 bits have any negative consequences?
|
||||
// For now, player->stunned 16th bit is a flag to determine whether the flybots were spawned
|
||||
|
||||
// timer counts down at triple speed while spindashing
|
||||
player->stunned = (player->stunned & 0x8000) | max(0, (player->stunned & 0x7FFF) - (player->spindash ? 3 : 1));
|
||||
|
||||
// when timer reaches 0, reset the flag and stun combo counter
|
||||
if ((player->stunned & 0x7FFF) == 0)
|
||||
{
|
||||
player->stunned = 0;
|
||||
player->stunnedCombo = 0;
|
||||
}
|
||||
// otherwise if the flybots aren't spawned, spawn them now!
|
||||
else if ((player->stunned & 0x8000) == 0)
|
||||
{
|
||||
player->stunned |= 0x8000;
|
||||
Obj_SpawnFlybotsForPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
if (player->trickpanel == TRICKSTATE_READY)
|
||||
{
|
||||
if (!player->throwdir && !cmd->turning)
|
||||
|
|
@ -10043,7 +10070,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
|
||||
extern consvar_t cv_fuzz;
|
||||
if (cv_fuzz.value && P_CanPickupItem(player, 1))
|
||||
if (cv_fuzz.value && P_CanPickupItem(player, PICKUP_ITEMBOX))
|
||||
{
|
||||
K_StartItemRoulette(player, P_RandomRange(PR_FUZZ, 0, 1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -435,6 +435,11 @@ boolean Obj_DestroyKart(mobj_t *kart);
|
|||
void Obj_DestroyedKartParticleThink(mobj_t *part);
|
||||
void Obj_DestroyedKartParticleLanding(mobj_t *part);
|
||||
|
||||
/* Flybot767 (stun) */
|
||||
void Obj_SpawnFlybotsForPlayer(player_t *player);
|
||||
void Obj_FlybotThink(mobj_t *flybot);
|
||||
void Obj_FlybotDeath(mobj_t *flybot);
|
||||
|
||||
/* Pulley */
|
||||
void Obj_PulleyThink(mobj_t *root);
|
||||
void Obj_PulleyHookTouch(mobj_t *special, mobj_t *toucher);
|
||||
|
|
|
|||
|
|
@ -260,6 +260,10 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->tumbleBounces);
|
||||
else if (fastcmp(field,"tumbleheight"))
|
||||
lua_pushinteger(L, plr->tumbleHeight);
|
||||
else if (fastcmp(field,"stunned"))
|
||||
lua_pushinteger(L, plr->stunned);
|
||||
else if (fastcmp(field,"stunnedcombo"))
|
||||
lua_pushinteger(L, plr->stunnedCombo);
|
||||
else if (fastcmp(field,"justdi"))
|
||||
lua_pushinteger(L, plr->justDI);
|
||||
else if (fastcmp(field,"flipdi"))
|
||||
|
|
@ -874,6 +878,10 @@ static int player_set(lua_State *L)
|
|||
plr->tumbleBounces = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"tumbleheight"))
|
||||
plr->tumbleHeight = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"stunned"))
|
||||
plr->stunned = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"stunnedcombo"))
|
||||
plr->stunnedCombo = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"justdi"))
|
||||
plr->justDI = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"flipdi"))
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
pulley.cpp
|
||||
amps.c
|
||||
ballhog.cpp
|
||||
flybot767.c
|
||||
)
|
||||
|
||||
add_subdirectory(versus)
|
||||
|
|
|
|||
142
src/objects/flybot767.c
Normal file
142
src/objects/flybot767.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2025 by Lachlan "Lach" Wright
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file flybot767.c
|
||||
/// \brief Flybot767 object code.
|
||||
|
||||
#include "../p_local.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../m_easing.h"
|
||||
|
||||
#define FLYBOT_QUANTITY 2
|
||||
#define FLYBOT_VERTICAL_OFFSET (16 * FRACUNIT)
|
||||
#define FLYBOT_BOB_AMPLITUDE (16 * FRACUNIT)
|
||||
#define FLYBOT_BOB_FREQUENCY (ANG15)
|
||||
#define FLYBOT_FADE_STARTTIME (2 * TICRATE)
|
||||
#define FLYBOT_SCALE (17 * FRACUNIT / 20)
|
||||
static const fixed_t PI = 355 * FRACUNIT / 113;
|
||||
|
||||
static fixed_t SetFlybotZ(mobj_t *flybot)
|
||||
{
|
||||
flybot->z = FixedMul(mapobjectscale, FLYBOT_VERTICAL_OFFSET) + FixedMul(mapobjectscale, P_ReturnThrustX(NULL, flybot->movedir, FLYBOT_BOB_AMPLITUDE));
|
||||
if (flybot->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
flybot->z = -flybot->z - flybot->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
flybot->z += flybot->target->height;
|
||||
}
|
||||
flybot->z += flybot->target->z;
|
||||
return flybot->z;
|
||||
}
|
||||
|
||||
void Obj_SpawnFlybotsForPlayer(player_t *player)
|
||||
{
|
||||
UINT8 i;
|
||||
mobj_t *mo = player->mo;
|
||||
fixed_t radius = mo->radius;
|
||||
|
||||
for (i = 0; i < FLYBOT_QUANTITY; i++)
|
||||
{
|
||||
angle_t angle = mo->angle + ANGLE_90 + FixedAngle(i * 360 * FRACUNIT / FLYBOT_QUANTITY);
|
||||
mobj_t *flybot = P_SpawnMobj(
|
||||
mo->x + P_ReturnThrustX(NULL, angle, radius),
|
||||
mo->y + P_ReturnThrustY(NULL, angle, radius),
|
||||
mo->z,
|
||||
MT_FLYBOT767
|
||||
);
|
||||
|
||||
P_InstaScale(flybot, flybot->old_scale = FixedMul(mapobjectscale, FLYBOT_SCALE));
|
||||
P_SetTarget(&flybot->target, mo);
|
||||
flybot->eflags |= mo->eflags & MFE_VERTICALFLIP;
|
||||
flybot->movedir = flybot->old_angle = flybot->angle = angle + ANGLE_90;
|
||||
flybot->old_z = SetFlybotZ(flybot);
|
||||
flybot->renderflags |= (i * RF_DONTDRAW);
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_FlybotThink(mobj_t *flybot)
|
||||
{
|
||||
UINT16 stunned = UINT16_MAX;
|
||||
angle_t deltaAngle, angle;
|
||||
fixed_t radius, circumference;
|
||||
fixed_t speed = FixedMul(mapobjectscale, flybot->info->speed);
|
||||
mobj_t *mo = flybot->target;
|
||||
|
||||
if (P_MobjWasRemoved(mo))
|
||||
{
|
||||
P_KillMobj(flybot, NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mo->player)
|
||||
{
|
||||
if (((stunned = mo->player->stunned & 0x7FFF) == 0) || (mo->player->playerstate == PST_DEAD))
|
||||
{
|
||||
P_KillMobj(flybot, NULL, NULL, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
flybot->frame = flybot->frame & ~FF_TRANSMASK;
|
||||
if (stunned < FLYBOT_FADE_STARTTIME)
|
||||
{
|
||||
flybot->frame |= Easing_InCubic(FixedDiv(stunned, FLYBOT_FADE_STARTTIME), 7, 1) << FF_TRANSSHIFT;
|
||||
}
|
||||
|
||||
flybot->eflags = (flybot->eflags & ~MFE_VERTICALFLIP) | (mo->eflags & MFE_VERTICALFLIP);
|
||||
flybot->movedir += FLYBOT_BOB_FREQUENCY;
|
||||
flybot->renderflags ^= RF_DONTDRAW;
|
||||
|
||||
radius = mo->radius;
|
||||
circumference = 2 * FixedMul(PI, radius);
|
||||
deltaAngle = FixedAngle(FixedMul(FixedDiv(speed, circumference), 360 * FRACUNIT));
|
||||
flybot->angle += deltaAngle;
|
||||
angle = flybot->angle - ANGLE_90;
|
||||
|
||||
P_MoveOrigin(flybot,
|
||||
mo->x + P_ReturnThrustX(NULL, angle, radius),
|
||||
mo->y + P_ReturnThrustY(NULL, angle, radius),
|
||||
SetFlybotZ(flybot)
|
||||
);
|
||||
}
|
||||
|
||||
void Obj_FlybotDeath(mobj_t *flybot)
|
||||
{
|
||||
UINT8 i;
|
||||
angle_t angle = 0;
|
||||
fixed_t hThrust = 4*mapobjectscale, vThrust = 4*mapobjectscale;
|
||||
vector3_t mom = {0, 0, 0};
|
||||
mobj_t *mo = flybot->target;
|
||||
|
||||
if (!P_MobjWasRemoved(mo))
|
||||
{
|
||||
mom.x = mo->momx;
|
||||
mom.y = mo->momy;
|
||||
mom.z = mo->momz;
|
||||
//S_StartSound(mo, flybot->info->deathsound);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
mo = P_SpawnMobjFromMobj(flybot, 0, 0, 0, MT_PARTICLE);
|
||||
P_SetMobjState(mo, S_SPINDASHDUST);
|
||||
mo->flags |= MF_NOSQUISH;
|
||||
mo->renderflags |= RF_FULLBRIGHT;
|
||||
mo->momx = mom.x;
|
||||
mo->momy = mom.y;
|
||||
mo->momz = mom.z + vThrust;
|
||||
P_Thrust(mo, angle, hThrust);
|
||||
vThrust *= -1;
|
||||
angle += ANGLE_90;
|
||||
}
|
||||
}
|
||||
|
|
@ -629,7 +629,7 @@ award_immediately (mobj_t *hyu)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!P_CanPickupItem(player, 1))
|
||||
if (!P_CanPickupItem(player, PICKUP_ITEMBOX))
|
||||
return false;
|
||||
|
||||
// Prevent receiving any more items or even stacked
|
||||
|
|
|
|||
|
|
@ -47,11 +47,11 @@ static player_t *GetItemBoxPlayer(mobj_t *mobj)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Always use normal item box rules -- could pass in "2" for fakes but they blend in better like this
|
||||
if (P_CanPickupItem(&players[i], 1))
|
||||
// Always use normal item box rules -- could pass in "PICKUP_EGGBOX" for fakes but they blend in better like this
|
||||
if (P_CanPickupItem(&players[i], PICKUP_ITEMBOX))
|
||||
{
|
||||
// Check for players who can take this pickup, but won't be allowed to (antifarming)
|
||||
UINT8 mytype = (mobj->flags2 & MF2_BOSSDEAD) ? 2 : 1;
|
||||
UINT8 mytype = (mobj->flags2 & MF2_BOSSDEAD) ? CHEESE_RINGBOX : CHEESE_ITEMBOX;
|
||||
if (P_IsPickupCheesy(&players[i], mytype))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -120,21 +120,32 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon)
|
|||
if (player->exiting || mapreset || (player->pflags & PF_ELIMINATED) || player->itemRoulette.reserved)
|
||||
return false;
|
||||
|
||||
// 0: Sphere/Ring
|
||||
// 1: Random Item / Capsule
|
||||
// 2: Eggbox
|
||||
// 3: Paperitem
|
||||
// See p_local.h for pickup types
|
||||
|
||||
if (weapon != 2 && player->instaWhipCharge)
|
||||
if (weapon != PICKUP_EGGBOX && player->instaWhipCharge)
|
||||
return false;
|
||||
|
||||
if (weapon == 1 && !player->cangrabitems)
|
||||
if (weapon == PICKUP_ITEMBOX && !player->cangrabitems)
|
||||
return false;
|
||||
|
||||
if (weapon)
|
||||
if (weapon == PICKUP_RINGORSPHERE)
|
||||
{
|
||||
// No picking up rings while SPB is targetting you
|
||||
if (player->pflags & PF_RINGLOCK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// No picking up rings while stunned
|
||||
if (player->stunned > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Item slot already taken up
|
||||
if (weapon == 2)
|
||||
if (weapon == PICKUP_EGGBOX)
|
||||
{
|
||||
// Invulnerable
|
||||
if (player->flashing > 0)
|
||||
|
|
@ -156,11 +167,11 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon)
|
|||
// Item slot already taken up
|
||||
if (player->itemRoulette.active == true
|
||||
|| player->ringboxdelay > 0
|
||||
|| (weapon != 3 && player->itemamount)
|
||||
|| (weapon != PICKUP_PAPERITEM && player->itemamount)
|
||||
|| (player->itemflags & IF_ITEMOUT))
|
||||
return false;
|
||||
|
||||
if (weapon == 3 && K_GetShieldFromItem(player->itemtype) != KSHIELD_NONE)
|
||||
if (weapon == PICKUP_PAPERITEM && K_GetShieldFromItem(player->itemtype) != KSHIELD_NONE)
|
||||
return false; // No stacking shields!
|
||||
}
|
||||
}
|
||||
|
|
@ -171,7 +182,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon)
|
|||
// Allow players to pick up only one pickup from each set of pickups.
|
||||
// Anticheese pickup types are different than-P_CanPickupItem weapon, because that system is
|
||||
// already slightly scary without introducing special cases for different types of the same pickup.
|
||||
// 1 = floating item, 2 = perma ring, 3 = capsule
|
||||
// See p_local.h for cheese types.
|
||||
boolean P_IsPickupCheesy(player_t *player, UINT8 type)
|
||||
{
|
||||
extern consvar_t cv_debugcheese;
|
||||
|
|
@ -414,7 +425,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (special->scale < special->destscale/2)
|
||||
return;
|
||||
|
||||
if (!P_CanPickupItem(player, 3) || (player->itemamount && player->itemtype != special->threshold))
|
||||
if (!P_CanPickupItem(player, PICKUP_PAPERITEM) || (player->itemamount && player->itemtype != special->threshold))
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
|
|
@ -434,9 +445,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
special->flags &= ~MF_SPECIAL;
|
||||
return;
|
||||
case MT_RANDOMITEM: {
|
||||
UINT8 cheesetype = (special->flags2 & MF2_BOSSDEAD) ? 2 : 1; // perma ring box
|
||||
UINT8 cheesetype = (special->flags2 & MF2_BOSSDEAD) ? CHEESE_RINGBOX : CHEESE_ITEMBOX; // perma ring box
|
||||
|
||||
if (!P_CanPickupItem(player, 1))
|
||||
if (!P_CanPickupItem(player, PICKUP_ITEMBOX))
|
||||
return;
|
||||
if (P_IsPickupCheesy(player, cheesetype))
|
||||
return;
|
||||
|
|
@ -476,7 +487,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
}
|
||||
case MT_SPHEREBOX:
|
||||
if (!P_CanPickupItem(player, 0))
|
||||
if (!P_CanPickupItem(player, PICKUP_RINGORSPHERE))
|
||||
return;
|
||||
|
||||
special->momx = special->momy = special->momz = 0;
|
||||
|
|
@ -496,15 +507,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
break;
|
||||
case KITEM_SUPERRING:
|
||||
if (player->pflags & PF_RINGLOCK) // no cheaty rings
|
||||
return;
|
||||
if (player->instaWhipCharge)
|
||||
if (!P_CanPickupItem(player, PICKUP_RINGORSPHERE)) // no cheaty rings
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
if (!P_CanPickupItem(player, 1))
|
||||
if (!P_CanPickupItem(player, PICKUP_ITEMCAPSULE))
|
||||
return;
|
||||
if (P_IsPickupCheesy(player, 3))
|
||||
if (P_IsPickupCheesy(player, CHEESE_ITEMCAPSULE))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
|
@ -561,7 +570,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
}
|
||||
case MT_EMERALD:
|
||||
if (!P_CanPickupItem(player, 0) || P_PlayerInPain(player))
|
||||
if (!P_CanPickupItem(player, PICKUP_RINGORSPHERE) || P_PlayerInPain(player))
|
||||
return;
|
||||
|
||||
if (special->threshold > 0)
|
||||
|
|
@ -620,7 +629,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
|
||||
case MT_CDUFO: // SRB2kart
|
||||
if (special->fuse || !P_CanPickupItem(player, 1))
|
||||
if (special->fuse || !P_CanPickupItem(player, PICKUP_ITEMBOX))
|
||||
return;
|
||||
|
||||
K_StartItemRoulette(player, false);
|
||||
|
|
@ -684,19 +693,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (special->extravalue1)
|
||||
return;
|
||||
|
||||
// No picking up rings while SPB is targetting you
|
||||
if (player->pflags & PF_RINGLOCK)
|
||||
return;
|
||||
|
||||
// Prepping instawhip? Don't ruin it by collecting rings
|
||||
if (player->instaWhipCharge)
|
||||
return;
|
||||
|
||||
// Don't immediately pick up spilled rings
|
||||
if (special->threshold > 0 || P_PlayerInPain(player) || player->spindash) // player->spindash: Otherwise, players can pick up rings that are thrown out of them from invinc spindash penalty
|
||||
return;
|
||||
|
||||
if (!(P_CanPickupItem(player, 0)))
|
||||
if (!(P_CanPickupItem(player, PICKUP_RINGORSPHERE)))
|
||||
return;
|
||||
|
||||
// Reached the cap, don't waste 'em!
|
||||
|
|
@ -718,7 +719,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
|
||||
case MT_BLUESPHERE:
|
||||
if (!(P_CanPickupItem(player, 0)))
|
||||
if (!(P_CanPickupItem(player, PICKUP_RINGORSPHERE)))
|
||||
return;
|
||||
|
||||
P_GivePlayerSpheres(player, 1);
|
||||
|
|
@ -2304,6 +2305,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
case MT_EMFAUCET_DRIP:
|
||||
Obj_EMZDripDeath(target);
|
||||
break;
|
||||
case MT_FLYBOT767:
|
||||
Obj_FlybotDeath(target);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -3004,6 +3008,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
UINT8 type = (damagetype & DMG_TYPEMASK);
|
||||
const boolean hardhit = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can do evil stuff like ALWAYS combo
|
||||
INT16 ringburst = 5;
|
||||
UINT16 stunTics = 0;
|
||||
|
||||
// Check if the player is allowed to be damaged!
|
||||
// If not, then spawn the instashield effect instead.
|
||||
|
|
@ -3394,6 +3399,27 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
player->flipDI = true;
|
||||
}
|
||||
|
||||
// Apply stun!
|
||||
// Feel free to move these calculations higher up if different damage sources should apply variable stun in future
|
||||
#define MIN_STUNTICS (8 * TICRATE)
|
||||
#define MAX_STUNTICS (18 * TICRATE)
|
||||
stunTics = Easing_Linear((player->kartweight - 1) * FRACUNIT / 8, MAX_STUNTICS, MIN_STUNTICS);
|
||||
stunTics >>= player->stunnedCombo; // consecutive hits add half as much stun as the previous hit
|
||||
|
||||
// 1/3 base stun values in battle
|
||||
if (gametyperules & GTR_SPHERES)
|
||||
{
|
||||
stunTics /= 3;
|
||||
}
|
||||
|
||||
if (player->stunnedCombo < UINT8_MAX)
|
||||
{
|
||||
player->stunnedCombo++;
|
||||
}
|
||||
player->stunned = (player->stunned & 0x8000) | min(0x7FFF, (player->stunned & 0x7FFF) + stunTics);
|
||||
#undef MIN_STUNTICS
|
||||
#undef MAX_STUNTICS
|
||||
|
||||
K_DefensiveOverdrive(target->player);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,6 +557,17 @@ void P_CheckTimeLimit(void);
|
|||
void P_CheckPointLimit(void);
|
||||
boolean P_CheckRacers(void);
|
||||
|
||||
// Pickup types
|
||||
#define PICKUP_RINGORSPHERE 0
|
||||
#define PICKUP_ITEMBOX 1
|
||||
#define PICKUP_EGGBOX 2
|
||||
#define PICKUP_PAPERITEM 3
|
||||
#define PICKUP_ITEMCAPSULE 4
|
||||
|
||||
#define CHEESE_ITEMBOX 1
|
||||
#define CHEESE_RINGBOX 2
|
||||
#define CHEESE_ITEMCAPSULE 3
|
||||
|
||||
boolean P_CanPickupItem(player_t *player, UINT8 weapon);
|
||||
boolean P_IsPickupCheesy(player_t *player, UINT8 type);
|
||||
void P_UpdateLastPickup(player_t *player, UINT8 type);
|
||||
|
|
|
|||
|
|
@ -10070,6 +10070,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
break;
|
||||
}
|
||||
|
||||
case MT_FLYBOT767:
|
||||
{
|
||||
Obj_FlybotThink(mobj);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// check mobj against possible water content, before movement code
|
||||
P_MobjCheckWater(mobj);
|
||||
|
|
|
|||
|
|
@ -455,6 +455,8 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT8(save->p, players[i].noEbrakeMagnet);
|
||||
WRITEUINT8(save->p, players[i].tumbleBounces);
|
||||
WRITEUINT16(save->p, players[i].tumbleHeight);
|
||||
WRITEUINT16(save->p, players[i].stunned);
|
||||
WRITEUINT8(save->p, players[i].stunnedCombo);
|
||||
|
||||
WRITEUINT8(save->p, players[i].justDI);
|
||||
WRITEUINT8(save->p, players[i].flipDI);
|
||||
|
|
@ -1095,6 +1097,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].noEbrakeMagnet = READUINT8(save->p);
|
||||
players[i].tumbleBounces = READUINT8(save->p);
|
||||
players[i].tumbleHeight = READUINT16(save->p);
|
||||
players[i].stunned = READUINT16(save->p);
|
||||
players[i].stunnedCombo = READUINT8(save->p);
|
||||
|
||||
players[i].justDI = READUINT8(save->p);
|
||||
players[i].flipDI = (boolean)READUINT8(save->p);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue