mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-10 00:34:32 +00:00
Add guarding while ebraking with spheres
This commit is contained in:
parent
1b16b3f777
commit
dadaab1817
12 changed files with 251 additions and 27 deletions
|
|
@ -3288,6 +3288,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_SLIPTIDEZIP",
|
||||
|
||||
"S_INSTAWHIP",
|
||||
"S_BLOCKRING",
|
||||
"S_BLOCKBODY",
|
||||
|
||||
// Signpost sparkles
|
||||
"S_SIGNSPARK1",
|
||||
|
|
@ -5321,6 +5323,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_SLIPTIDEZIP",
|
||||
|
||||
"MT_INSTAWHIP",
|
||||
"MT_BLOCKRING",
|
||||
"MT_BLOCKBODY",
|
||||
|
||||
"MT_SIGNSPARKLE",
|
||||
|
||||
|
|
|
|||
58
src/info.c
58
src/info.c
|
|
@ -556,6 +556,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"SLPT", // Sliptide zip indicator
|
||||
|
||||
"IWHP", // Instawhip
|
||||
"GRNG", // Guard ring
|
||||
"GBDY", // Guard body
|
||||
|
||||
"WIPD", // Wipeout dust trail
|
||||
"DRIF", // Drift Sparks
|
||||
|
|
@ -3949,6 +3951,8 @@ state_t states[NUMSTATES] =
|
|||
{SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SLIPTIDEZIP
|
||||
|
||||
{SPR_IWHP, FF_FLOORSPRITE|FF_ANIMATE|0, -1, {NULL}, 6, 2, S_NULL}, // S_INSTAWHIP
|
||||
{SPR_GRNG, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_BLOCKRING
|
||||
{SPR_GBDY, FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_BLOCKBODY
|
||||
|
||||
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1
|
||||
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
|
||||
|
|
@ -22663,6 +22667,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BLOCKRING
|
||||
-1, // doomednum
|
||||
S_BLOCKRING, // 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_None, // deathsound
|
||||
0, // speed
|
||||
67*FRACUNIT, // radius
|
||||
67*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BLOCKBODY
|
||||
-1, // doomednum
|
||||
S_BLOCKBODY, // 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_None, // deathsound
|
||||
0, // speed
|
||||
67*FRACUNIT, // radius
|
||||
67*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SIGNSPARKLE
|
||||
-1, // doomednum
|
||||
|
|
|
|||
|
|
@ -1109,6 +1109,8 @@ typedef enum sprite
|
|||
SPR_SLPT, // Sliptide zip indicator
|
||||
|
||||
SPR_IWHP, // Instawhip
|
||||
SPR_GRNG, // Guard ring
|
||||
SPR_GBDY, // Guard body
|
||||
|
||||
SPR_WIPD, // Wipeout dust trail
|
||||
SPR_DRIF, // Drift Sparks
|
||||
|
|
@ -4360,6 +4362,8 @@ typedef enum state
|
|||
S_SLIPTIDEZIP,
|
||||
|
||||
S_INSTAWHIP,
|
||||
S_BLOCKRING,
|
||||
S_BLOCKBODY,
|
||||
|
||||
// Signpost sparkles
|
||||
S_SIGNSPARK1,
|
||||
|
|
@ -6428,6 +6432,8 @@ typedef enum mobj_type
|
|||
MT_SLIPTIDEZIP,
|
||||
|
||||
MT_INSTAWHIP,
|
||||
MT_BLOCKRING,
|
||||
MT_BLOCKBODY,
|
||||
|
||||
MT_SIGNSPARKLE,
|
||||
|
||||
|
|
|
|||
|
|
@ -787,48 +787,96 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
|
|||
return true;
|
||||
}
|
||||
|
||||
boolean K_InstaWhipCollide(mobj_t *t1, mobj_t *t2)
|
||||
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
||||
{
|
||||
const int defenderHitlag = 10;
|
||||
const int victimHitlag = 10;
|
||||
const int attackerHitlag = 4;
|
||||
|
||||
if (t2->player)
|
||||
// EV1 is used to indicate that we should no longer hit monitors.
|
||||
// EV2 indicates we should no longer hit anything.
|
||||
if (shield->extravalue2)
|
||||
return false;
|
||||
|
||||
mobj_t *attacker = shield->target;
|
||||
|
||||
if (!attacker || P_MobjWasRemoved(attacker) || !attacker->player)
|
||||
return false; // How did we even get here?
|
||||
|
||||
player_t *attackerPlayer = attacker->player;
|
||||
|
||||
if (victim->player)
|
||||
{
|
||||
if (t2 != t1->target && !P_PlayerInPain(t2->player) && t2->player->flashing == 0)
|
||||
player_t *victimPlayer = victim->player;
|
||||
|
||||
if (victim != attacker && !P_PlayerInPain(victimPlayer) && victimPlayer->flashing == 0)
|
||||
{
|
||||
if (K_PlayerEBrake(victimPlayer) && victimPlayer->spheres > 0)
|
||||
{
|
||||
if (P_PlayerInPain(attackerPlayer))
|
||||
return false; // never punish shield more than once
|
||||
|
||||
angle_t thrangle = R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
|
||||
attacker->momx = attacker->momy = 0;
|
||||
P_Thrust(attacker, thrangle, FRACUNIT*7);
|
||||
|
||||
victimPlayer->spheres = std::min(victimPlayer->spheres + 10, 40);
|
||||
|
||||
shield->renderflags &= ~RF_DONTDRAW;
|
||||
shield->flags |= MF_NOCLIPTHING;
|
||||
|
||||
attacker->renderflags &= ~RF_DONTDRAW;
|
||||
attackerPlayer->instaShieldCooldown = TICRATE*2;
|
||||
attackerPlayer->flashing = 0;
|
||||
|
||||
P_DamageMobj(attacker, victim, victim, 1, DMG_STING);
|
||||
|
||||
S_StartSound(victim, sfx_mbv92);
|
||||
K_AddHitLag(attacker, 2*victimHitlag, true);
|
||||
K_AddHitLag(victim, attackerHitlag, false);
|
||||
attacker->hitlag = std::min(attacker->hitlag, 2*victimHitlag);
|
||||
shield->hitlag = attacker->hitlag;
|
||||
|
||||
shield->extravalue2 = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Damage is a bit hacky, we want only a small loss-of-control
|
||||
// while still behaving as if it's a "real" hit.
|
||||
P_PlayRinglossSound(t2);
|
||||
P_PlayerRingBurst(t2->player, 5);
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_STUMBLE);
|
||||
P_PlayRinglossSound(victim);
|
||||
P_PlayerRingBurst(victimPlayer, 5);
|
||||
P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a pecial exception in P_DamageMobj for type==MT_INSTAWHIP
|
||||
|
||||
K_AddHitLag(t2, defenderHitlag, true);
|
||||
K_AddHitLag(t1->target, attackerHitlag, false);
|
||||
t1->hitlag = t1->target->hitlag;
|
||||
angle_t thrangle = ANGLE_180 + R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
|
||||
P_Thrust(victim, thrangle, FRACUNIT*10);
|
||||
|
||||
K_AddHitLag(victim, victimHitlag, true);
|
||||
K_AddHitLag(attacker, attackerHitlag, false);
|
||||
shield->hitlag = attacker->hitlag;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_GACHABOM
|
||||
|| t2->type == MT_BANANA || t2->type == MT_EGGMANITEM || t2->type == MT_BALLHOG
|
||||
|| t2->type == MT_SSMINE || t2->type == MT_LANDMINE || t2->type == MT_SINK
|
||||
|| t2->type == MT_GARDENTOP || t2->type == MT_DROPTARGET || t2->type == MT_BATTLECAPSULE
|
||||
|| t2->type == MT_MONITOR)
|
||||
if (victim->type == MT_ORBINAUT || victim->type == MT_JAWZ || victim->type == MT_GACHABOM
|
||||
|| victim->type == MT_BANANA || victim->type == MT_EGGMANITEM || victim->type == MT_BALLHOG
|
||||
|| victim->type == MT_SSMINE || victim->type == MT_LANDMINE || victim->type == MT_SINK
|
||||
|| victim->type == MT_GARDENTOP || victim->type == MT_DROPTARGET || victim->type == MT_BATTLECAPSULE
|
||||
|| victim->type == MT_MONITOR)
|
||||
{
|
||||
// Monitor hack. We can hit monitors once per instawhip, no multihit shredding!
|
||||
// Damage values in Obj_MonitorGetDamage.
|
||||
if (t2->type == MT_MONITOR)
|
||||
if (victim->type == MT_MONITOR)
|
||||
{
|
||||
if (t1->extravalue1 == 1)
|
||||
if (shield->extravalue1 == 1)
|
||||
return false;
|
||||
t1->extravalue1 = 1;
|
||||
shield->extravalue1 = 1;
|
||||
}
|
||||
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
|
||||
K_AddHitLag(t1->target, attackerHitlag, false);
|
||||
t1->hitlag = t1->target->hitlag;
|
||||
P_DamageMobj(victim, shield, attacker, 1, DMG_NORMAL);
|
||||
K_AddHitLag(attacker, attackerHitlag, false);
|
||||
shield = attacker;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1022,7 +1070,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
bool stung = false;
|
||||
|
||||
if (t2->player->rings <= 0)
|
||||
if (t2->player->rings <= 0 && t2->player->spheres <= 0)
|
||||
{
|
||||
P_DamageMobj(t2, t1, t1, 1, DMG_STING|DMG_WOMBO);
|
||||
stung = true;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2);
|
|||
void K_LightningShieldAttack(mobj_t *actor, fixed_t size);
|
||||
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
|
||||
|
||||
boolean K_InstaWhipCollide(mobj_t *t1, mobj_t *t2);
|
||||
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim);
|
||||
|
||||
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);
|
||||
|
||||
|
|
|
|||
24
src/k_kart.c
24
src/k_kart.c
|
|
@ -7777,7 +7777,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
// where's the < 0 check? see below the following block!
|
||||
|
||||
{
|
||||
tic_t spheredigestion = TICRATE; // Base rate of 1 every second when playing.
|
||||
tic_t spheredigestion = TICRATE*2; // Base rate of 1 every second when playing.
|
||||
tic_t digestionpower = ((10 - player->kartspeed) + (10 - player->kartweight))-1; // 1 to 17
|
||||
|
||||
// currently 0-34
|
||||
|
|
@ -7789,7 +7789,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
else
|
||||
{
|
||||
spheredigestion -= digestionpower;
|
||||
spheredigestion -= digestionpower/2;
|
||||
}
|
||||
|
||||
if ((player->spheres > 0) && (player->spheredigestion > 0))
|
||||
|
|
@ -7807,6 +7807,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->spheres--;
|
||||
player->spheredigestion = spheredigestion;
|
||||
}
|
||||
|
||||
if (K_PlayerEBrake(player) && (player->ebrakefor%6 == 0))
|
||||
player->spheres--;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -9833,6 +9836,23 @@ void K_KartEbrakeVisuals(player_t *p)
|
|||
if (!S_SoundPlaying(p->mo, sfx_s3kd9s))
|
||||
S_ReducedVFXSound(p->mo, sfx_s3kd9s, p);
|
||||
|
||||
// Block visuals
|
||||
// (These objects track whether a player is block-eligible on their own, no worries)
|
||||
if (!p->ebrakefor)
|
||||
{
|
||||
mobj_t *ring = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKRING);
|
||||
P_SetTarget(&ring->target, p->mo);
|
||||
P_SetScale(ring, p->mo->scale);
|
||||
K_MatchGenericExtraFlags(ring, p->mo);
|
||||
ring->renderflags &= ~RF_DONTDRAW;
|
||||
|
||||
mobj_t *body = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->z, MT_BLOCKBODY);
|
||||
P_SetTarget(&body->target, p->mo);
|
||||
P_SetScale(body, p->mo->scale);
|
||||
K_MatchGenericExtraFlags(body, p->mo);
|
||||
body->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
|
||||
// HOLD! bubble.
|
||||
if (!p->ebrakefor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@ boolean Obj_DropTargetMorphThink(mobj_t *morph);
|
|||
/* Instawhip */
|
||||
void Obj_InstaWhipThink(mobj_t *whip);
|
||||
|
||||
/* Block VFX */
|
||||
void Obj_BlockRingThink(mobj_t *ring);
|
||||
void Obj_BlockBodyThink(mobj_t *body);
|
||||
|
||||
/* Ring Shooter */
|
||||
boolean Obj_RingShooterThinker(mobj_t *mo);
|
||||
boolean Obj_PlayerRingShooterFreeze(player_t *const player);
|
||||
|
|
|
|||
|
|
@ -18,4 +18,5 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
audience.c
|
||||
random-item.c
|
||||
instawhip.c
|
||||
block.c
|
||||
)
|
||||
|
|
|
|||
68
src/objects/block.c
Normal file
68
src/objects/block.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../info.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../p_local.h"
|
||||
|
||||
void Obj_BlockRingThink (mobj_t *ring)
|
||||
{
|
||||
if (P_MobjWasRemoved(ring->target) || !ring->target->player || !ring->target->player->ebrakefor)
|
||||
{
|
||||
P_RemoveMobj(ring);
|
||||
}
|
||||
else
|
||||
{
|
||||
mobj_t *mo = ring->target;
|
||||
player_t *player = mo->player;
|
||||
|
||||
// Follow player
|
||||
ring->flags &= ~(MF_NOCLIPTHING);
|
||||
P_SetScale(ring, mo->scale);
|
||||
P_MoveOrigin(ring, mo->x, mo->y, mo->z + mo->height/2);
|
||||
ring->flags |= MF_NOCLIPTHING;
|
||||
ring->color = mo->color;
|
||||
|
||||
// Twirl
|
||||
ring->angle = ring->target->angle + (ANG15 * leveltime);
|
||||
// Visuals
|
||||
ring->renderflags |= RF_ADD|RF_PAPERSPRITE;
|
||||
|
||||
if (leveltime%2)
|
||||
ring->renderflags &= ~RF_DONTDRAW;
|
||||
else
|
||||
ring->renderflags |= RF_DONTDRAW;
|
||||
|
||||
if (player->spheres == 0)
|
||||
ring->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_BlockBodyThink (mobj_t *body)
|
||||
{
|
||||
if (P_MobjWasRemoved(body->target) || !body->target->player || !body->target->player->ebrakefor)
|
||||
{
|
||||
P_RemoveMobj(body);
|
||||
}
|
||||
else
|
||||
{
|
||||
mobj_t *mo = body->target;
|
||||
player_t *player = mo->player;
|
||||
|
||||
// Follow player
|
||||
body->flags &= ~(MF_NOCLIPTHING);
|
||||
P_SetScale(body, mo->scale);
|
||||
P_MoveOrigin(body, mo->x, mo->y, mo->z + mo->height/2);
|
||||
body->flags |= MF_NOCLIPTHING;
|
||||
body->color = mo->color;
|
||||
|
||||
// Visuals
|
||||
body->renderflags |= RF_ADD;
|
||||
|
||||
if (leveltime%2 == 0)
|
||||
body->renderflags &= ~RF_DONTDRAW;
|
||||
else
|
||||
body->renderflags |= RF_DONTDRAW;
|
||||
|
||||
if (player->spheres == 0)
|
||||
body->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
|
@ -2208,6 +2208,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
{
|
||||
sfx = sfx_grownd;
|
||||
}
|
||||
else if (player->spheres > 0 && K_PlayerEBrake(player))
|
||||
{
|
||||
sfx = sfx_s3k3a;
|
||||
player->spheres = max(player->spheres - 10, 0);
|
||||
}
|
||||
else if (player->hyudorotimer > 0)
|
||||
;
|
||||
else
|
||||
|
|
@ -2308,7 +2313,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
// Instawhip breaks the rules and does "damaging stumble",
|
||||
// but sting and stumble shouldn't be rewarding Battle hits otherwise.
|
||||
if ((type == DMG_STING || type == DMG_STUMBLE) && inflictor->type != MT_INSTAWHIP )
|
||||
if ((type == DMG_STING || type == DMG_STUMBLE) && (inflictor && inflictor->type != MT_INSTAWHIP))
|
||||
{
|
||||
damage = 0;
|
||||
}
|
||||
|
|
|
|||
10
src/p_mobj.c
10
src/p_mobj.c
|
|
@ -8361,6 +8361,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
Obj_InstaWhipThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BLOCKRING:
|
||||
{
|
||||
Obj_BlockRingThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BLOCKBODY:
|
||||
{
|
||||
Obj_BlockBodyThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_GARDENTOPSPARK:
|
||||
{
|
||||
Obj_GardenTopSparkThink(mobj);
|
||||
|
|
|
|||
|
|
@ -901,7 +901,7 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"mbv8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"mbv90", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"mbv91", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"mbv92", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"mbv92", false, 64, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Changed falloff for use in instashield parry.
|
||||
{"mbv93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"mbv94", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"mbv95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue