Merge branch 'instashield' into 'master'

Instashield (and Guard!)

See merge request KartKrew/Kart!1242
This commit is contained in:
Oni 2023-05-30 01:36:45 +00:00
commit 3f8ca964c7
25 changed files with 763 additions and 32 deletions

View file

@ -740,6 +740,12 @@ struct player_t
mobj_t *stumbleIndicator; mobj_t *stumbleIndicator;
mobj_t *sliptideZipIndicator; mobj_t *sliptideZipIndicator;
mobj_t *whip;
UINT8 instaShieldCooldown;
UINT8 guardCooldown;
INT16 incontrol; // -1 to -175 when spinning out or tumbling, 1 to 175 when not. Use to check for combo hits or emergency inputs.
uint8_t public_key[PUBKEYLENGTH]; uint8_t public_key[PUBKEYLENGTH];

View file

@ -3287,6 +3287,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_SLIPTIDEZIP", "S_SLIPTIDEZIP",
"S_INSTAWHIP",
"S_BLOCKRING",
"S_BLOCKBODY",
// Signpost sparkles // Signpost sparkles
"S_SIGNSPARK1", "S_SIGNSPARK1",
"S_SIGNSPARK2", "S_SIGNSPARK2",
@ -4011,6 +4015,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_INSTASHIELDB7", "S_INSTASHIELDB7",
"S_POWERCLASH", // Invinc/Grow no damage collide VFX "S_POWERCLASH", // Invinc/Grow no damage collide VFX
"S_GUARDBREAK", // Guard break
"S_PLAYERARROW", // Above player arrow "S_PLAYERARROW", // Above player arrow
"S_PLAYERARROW_BOX", "S_PLAYERARROW_BOX",
@ -5318,6 +5323,10 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_SLIPTIDEZIP", "MT_SLIPTIDEZIP",
"MT_INSTAWHIP",
"MT_BLOCKRING",
"MT_BLOCKBODY",
"MT_SIGNSPARKLE", "MT_SIGNSPARKLE",
"MT_FASTLINE", "MT_FASTLINE",
@ -5487,7 +5496,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_INSTASHIELDB", "MT_INSTASHIELDB",
"MT_POWERCLASH", // Invinc/Grow no damage clash VFX "MT_POWERCLASH", // Invinc/Grow no damage clash VFX
"MT_GUARDBREAK", // Guard break
"MT_PLAYERARROW", "MT_PLAYERARROW",
"MT_PLAYERWANTED", "MT_PLAYERWANTED",

View file

@ -2675,6 +2675,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
P_SetTarget(&players[player].follower, NULL); P_SetTarget(&players[player].follower, NULL);
P_SetTarget(&players[player].awayview.mobj, NULL); P_SetTarget(&players[player].awayview.mobj, NULL);
P_SetTarget(&players[player].stumbleIndicator, NULL); P_SetTarget(&players[player].stumbleIndicator, NULL);
P_SetTarget(&players[player].whip, NULL);
P_SetTarget(&players[player].ringShooter, NULL); P_SetTarget(&players[player].ringShooter, NULL);
P_SetTarget(&players[player].followmobj, NULL); P_SetTarget(&players[player].followmobj, NULL);

View file

@ -555,6 +555,10 @@ char sprnames[NUMSPRITES + 1][5] =
"SLPT", // Sliptide zip indicator "SLPT", // Sliptide zip indicator
"IWHP", // Instawhip
"GRNG", // Guard ring
"GBDY", // Guard body
"WIPD", // Wipeout dust trail "WIPD", // Wipeout dust trail
"DRIF", // Drift Sparks "DRIF", // Drift Sparks
"BDRF", // Brake drift sparks "BDRF", // Brake drift sparks
@ -634,6 +638,7 @@ char sprnames[NUMSPRITES + 1][5] =
"ISTB", // instashield layer B "ISTB", // instashield layer B
"PWCL", // Invinc/grow clash VFX "PWCL", // Invinc/grow clash VFX
"GBRK", // Guard break
"ARRO", // player arrows "ARRO", // player arrows
"ITEM", "ITEM",
@ -3946,6 +3951,10 @@ state_t states[NUMSTATES] =
{SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SLIPTIDEZIP {SPR_SLPT, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SLIPTIDEZIP
{SPR_IWHP, FF_FULLBRIGHT|FF_FLOORSPRITE|FF_ANIMATE|0, -1, {NULL}, 6, 2, S_NULL}, // S_INSTAWHIP
{SPR_GRNG, FF_FULLBRIGHT|FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_BLOCKRING
{SPR_GBDY, FF_FULLBRIGHT|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, {NULL}, 0, 0, S_SIGNSPARK2}, // S_SIGNSPARK1
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3 {SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_SIGNSPARK4}, // S_SIGNSPARK3
@ -4627,6 +4636,7 @@ state_t states[NUMSTATES] =
{SPR_ISTB, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_NULL}, // S_INSTASHIELDB7 {SPR_ISTB, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_NULL}, // S_INSTASHIELDB7
{SPR_PWCL, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 10, {NULL}, 9, 1, S_NULL}, // S_POWERCLASH {SPR_PWCL, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 10, {NULL}, 9, 1, S_NULL}, // S_POWERCLASH
{SPR_GBRK, FF_ADD|FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 24, {NULL}, 5, 4, S_NULL}, // S_GUARDBREAK
// Above player arrow // Above player arrow
{SPR_ARRO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_PLAYERARROW {SPR_ARRO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_PLAYERARROW
@ -22632,6 +22642,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_INSTAWHIP
-1, // doomednum
S_INSTAWHIP, // 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
90*FRACUNIT, // radius
90*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
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 { // MT_SIGNSPARKLE
-1, // doomednum -1, // doomednum
@ -26089,6 +26180,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_GUARDBREAK
-1, // doomednum
S_GUARDBREAK, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // 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
8, // speed
8*FRACUNIT, // radius
8*FRACUNIT, // height
2, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_PLAYERARROW { // MT_PLAYERARROW
-1, // doomednum -1, // doomednum
S_PLAYERARROW, // spawnstate S_PLAYERARROW, // spawnstate

View file

@ -1108,6 +1108,10 @@ typedef enum sprite
SPR_SLPT, // Sliptide zip indicator SPR_SLPT, // Sliptide zip indicator
SPR_IWHP, // Instawhip
SPR_GRNG, // Guard ring
SPR_GBDY, // Guard body
SPR_WIPD, // Wipeout dust trail SPR_WIPD, // Wipeout dust trail
SPR_DRIF, // Drift Sparks SPR_DRIF, // Drift Sparks
SPR_BDRF, // Brake drift sparks SPR_BDRF, // Brake drift sparks
@ -1187,6 +1191,7 @@ typedef enum sprite
SPR_ISTB, // instashield layer B SPR_ISTB, // instashield layer B
SPR_PWCL, // Invinc/grow clash VFX SPR_PWCL, // Invinc/grow clash VFX
SPR_GBRK, // Guard break
SPR_ARRO, // player arrows SPR_ARRO, // player arrows
SPR_ITEM, SPR_ITEM,
@ -4357,6 +4362,10 @@ typedef enum state
S_SLIPTIDEZIP, S_SLIPTIDEZIP,
S_INSTAWHIP,
S_BLOCKRING,
S_BLOCKBODY,
// Signpost sparkles // Signpost sparkles
S_SIGNSPARK1, S_SIGNSPARK1,
S_SIGNSPARK2, S_SIGNSPARK2,
@ -5080,6 +5089,7 @@ typedef enum state
S_INSTASHIELDB7, S_INSTASHIELDB7,
S_POWERCLASH, // Grow/Invinc clash VFX S_POWERCLASH, // Grow/Invinc clash VFX
S_GUARDBREAK,
S_PLAYERARROW, // Above player arrow S_PLAYERARROW, // Above player arrow
S_PLAYERARROW_BOX, S_PLAYERARROW_BOX,
@ -6423,6 +6433,10 @@ typedef enum mobj_type
MT_MAGICIANBOX, MT_MAGICIANBOX,
MT_SLIPTIDEZIP, MT_SLIPTIDEZIP,
MT_INSTAWHIP,
MT_BLOCKRING,
MT_BLOCKBODY,
MT_SIGNSPARKLE, MT_SIGNSPARKLE,
MT_FASTLINE, MT_FASTLINE,
@ -6592,6 +6606,7 @@ typedef enum mobj_type
MT_INSTASHIELDB, MT_INSTASHIELDB,
MT_POWERCLASH, // Grow/Invinc clash VFX MT_POWERCLASH, // Grow/Invinc clash VFX
MT_GUARDBREAK,
MT_PLAYERARROW, MT_PLAYERARROW,
MT_PLAYERWANTED, MT_PLAYERWANTED,

View file

@ -197,9 +197,9 @@ mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT
P_Thrust(emerald, P_Thrust(emerald,
FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle, FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle,
24 * mapobjectscale); 36 * mapobjectscale);
emerald->momz = flip * 24 * mapobjectscale; emerald->momz = flip * 36 * mapobjectscale;
if (emerald->eflags & MFE_UNDERWATER) if (emerald->eflags & MFE_UNDERWATER)
emerald->momz = (117 * emerald->momz) / 200; emerald->momz = (117 * emerald->momz) / 200;
@ -265,6 +265,9 @@ void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType)
UINT8 i; UINT8 i;
SINT8 flip = P_MobjFlip(player->mo); SINT8 flip = P_MobjFlip(player->mo);
if (player->incontrol < TICRATE)
return;
for (i = 0; i < 14; i++) for (i = 0; i < 14; i++)
{ {
UINT32 emeraldFlag = (1 << i); UINT32 emeraldFlag = (1 << i);
@ -275,6 +278,7 @@ void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType)
P_SetTarget(&emerald->target, player->mo); P_SetTarget(&emerald->target, player->mo);
player->emeralds &= ~emeraldFlag; player->emeralds &= ~emeraldFlag;
break; // Drop only one emerald. Emerald wins are hard enough!
} }
} }
} }

View file

@ -1362,6 +1362,18 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd)
{ {
INT32 saferingsval = 16 - K_GetKartRingPower(player, false); INT32 saferingsval = 16 - K_GetKartRingPower(player, false);
if (leveltime < starttime)
{
// Don't use rings during POSITION!!
return;
}
if ((cmd->buttons & BT_ACCELERATE) == 0)
{
// Don't use rings if you're not trying to accelerate.
return;
}
if (P_IsObjectOnGround(player->mo) == false) if (P_IsObjectOnGround(player->mo) == false)
{ {
// Don't use while mid-air. // Don't use while mid-air.
@ -1380,6 +1392,70 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd)
} }
} }
/*--------------------------------------------------
static void K_BotItemInstashield(player_t *player, ticcmd_t *cmd)
Item usage for instashield.
Input Arguments:-
player - Bot to do this for.
cmd - Bot's ticcmd to edit.
Return:-
None
--------------------------------------------------*/
static void K_BotItemInstashield(player_t *player, ticcmd_t *cmd)
{
const fixed_t radius = FixedMul(mobjinfo[MT_INSTAWHIP].radius, player->mo->scale);
size_t i = SIZE_MAX;
if (K_ItemButtonWasDown(player) == true)
{
// Release the button, dude.
return;
}
if (player->instaShieldCooldown || leveltime < starttime || player->spindash)
{
// Instashield is on cooldown.
return;
}
// Find players within the instashield's range.
for (i = 0; i < MAXPLAYERS; i++)
{
player_t *target = NULL;
fixed_t dist = INT32_MAX;
if (!playeringame[i])
{
continue;
}
target = &players[i];
if (P_MobjWasRemoved(target->mo) == true
|| player == target
|| target->spectator == true
|| target->flashing != 0)
{
continue;
}
dist = P_AproxDistance(P_AproxDistance(
player->mo->x - target->mo->x,
player->mo->y - target->mo->y),
(player->mo->z - target->mo->z) / 4
);
if (dist <= radius)
{
// Use it!!
cmd->buttons |= BT_ATTACK;
break;
}
}
}
/*-------------------------------------------------- /*--------------------------------------------------
static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd)
@ -1453,12 +1529,16 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
{ {
if (player->pflags & PF_USERINGS) if (player->pflags & PF_USERINGS)
{ {
// Use rings! if (player->rings > 0)
if (leveltime > starttime)
{ {
// Use rings!
K_BotItemRings(player, cmd); K_BotItemRings(player, cmd);
} }
else
{
// Use the instashield!
K_BotItemInstashield(player, cmd);
}
} }
else else
{ {

View file

@ -787,6 +787,140 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
return true; return true;
} }
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
{
int victimHitlag = 10;
int attackerHitlag = 4;
// 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)
{
player_t *victimPlayer = victim->player;
//if (victim != attacker && !P_PlayerInPain(victimPlayer) && victimPlayer->flashing == 0)
if (victim != attacker && victim->hitlag == 0)
{
// If both players have a whip, hits are order-of-execution dependent and that sucks.
// Player expectation is a clash here.
if (victimPlayer->whip && !P_MobjWasRemoved(victimPlayer->whip))
{
victimPlayer->whip->extravalue2 = 1;
shield->extravalue2 = 1;
K_DoPowerClash(victim, attacker);
victim->renderflags &= ~RF_DONTDRAW;
attacker->renderflags &= ~RF_DONTDRAW;
angle_t thrangle = R_PointToAngle2(attacker->x, attacker->y, victim->x, victim->y);
P_Thrust(victim, thrangle, FRACUNIT*7);
P_Thrust(attacker, ANGLE_180 + thrangle, FRACUNIT*7);
return false;
}
// Instawhip _always_ loses to guard.
if (K_PlayerGuard(victimPlayer))
//if (true)
{
victimHitlag = 3*victimHitlag;
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);
// A little extra juice, so successful reads are usually positive or zero on spheres.
victimPlayer->spheres = std::min(victimPlayer->spheres + 10, 40);
shield->renderflags &= ~RF_DONTDRAW;
shield->flags |= MF_NOCLIPTHING;
// Attacker should be free to all reasonable followups.
attacker->renderflags &= ~RF_DONTDRAW;
attackerPlayer->spindashboost = 0;
attackerPlayer->sneakertimer = 0;
attackerPlayer->instaShieldCooldown = TICRATE*2;
attackerPlayer->guardCooldown = TICRATE*2;
attackerPlayer->flashing = 0;
// Localized broly for a local event.
mobj_t *broly = Obj_SpawnBrolyKi(victim, victimHitlag);
broly->extravalue2 = 16*mapobjectscale;
P_PlayVictorySound(victim);
P_DamageMobj(attacker, victim, victim, 1, DMG_STING);
S_StartSound(victim, sfx_mbv92);
K_AddHitLag(attacker, victimHitlag, true);
K_AddHitLag(victim, attackerHitlag, false);
K_DoPowerClash(shield, victim); // REJECTED
attacker->hitlag = victimHitlag; // No, seriously, we do not care about K_AddHitLag's idea of a normal maximum
shield->hitlag = attacker->hitlag;
shield->extravalue2 = 1;
return true;
}
// if you're here, you're getting hit
// 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(victim);
P_PlayerRingBurst(victimPlayer, 5);
P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a special exception in P_DamageMobj for type==MT_INSTAWHIP
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 (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 || victim->type == MT_SPECIAL_UFO)
{
// Monitor hack. We can hit monitors once per instawhip, no multihit shredding!
// Damage values in Obj_MonitorGetDamage.
if (victim->type == MT_MONITOR)
{
if (shield->extravalue1 == 1)
return false;
shield->extravalue1 = 1;
}
P_DamageMobj(victim, shield, attacker, 1, DMG_NORMAL);
K_AddHitLag(attacker, attackerHitlag, false);
shield->hitlag = attacker->hitlag;
}
return false;
}
}
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
{ {
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
@ -872,12 +1006,13 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|| (t1->player->invincibilitytimer > 0) || (t1->player->invincibilitytimer > 0)
|| (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD) || (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD)
|| (t1->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t1->player)) || (t1->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t1->player))
|| (t1->player->bubbleblowup > 0); || (t1->player->bubbleblowup > 0)
|| (t1->player->spheres > 0 && K_PlayerEBrake(t1->player));
}; };
if (canClash(t1, t2) && canClash(t2, t1)) if (canClash(t1, t2) && canClash(t2, t1))
{ {
K_DoPowerClash(t1->player, t2->player); K_DoPowerClash(t1, t2);
return false; return false;
} }
@ -975,7 +1110,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
bool stung = false; 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); P_DamageMobj(t2, t1, t1, 1, DMG_STING|DMG_WOMBO);
stung = true; stung = true;

View file

@ -24,6 +24,8 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2);
void K_LightningShieldAttack(mobj_t *actor, fixed_t size); void K_LightningShieldAttack(mobj_t *actor, fixed_t size);
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2); boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim);
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2); boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);
boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2); boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2);

View file

@ -933,6 +933,14 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2)
K_SpawnBumpForObjs(mobj1, mobj2); K_SpawnBumpForObjs(mobj1, mobj2);
if (mobj1->type == MT_PLAYER && mobj2->type == MT_PLAYER)
{
if (K_PlayerGuard(mobj1->player))
K_DoGuardBreak(mobj1, mobj2);
if (K_PlayerGuard(mobj2->player))
K_DoGuardBreak(mobj2, mobj1);
}
K_PlayerJustBumped(mobj1->player); K_PlayerJustBumped(mobj1->player);
K_PlayerJustBumped(mobj2->player); K_PlayerJustBumped(mobj2->player);
@ -1979,6 +1987,7 @@ void K_SpawnMagicianParticles(mobj_t *mo, int spread)
dust->frame |= FF_SUBTRACT|FF_TRANS90; dust->frame |= FF_SUBTRACT|FF_TRANS90;
dust->color = color; dust->color = color;
dust->colorized = true; dust->colorized = true;
dust->hitlag = 0;
} }
} }
@ -3606,28 +3615,54 @@ void K_DoInstashield(player_t *player)
P_SetTarget(&layerb->target, player->mo); P_SetTarget(&layerb->target, player->mo);
} }
void K_DoPowerClash(player_t *t1, player_t *t2) { void K_DoPowerClash(mobj_t *t1, mobj_t *t2) {
mobj_t *clash; mobj_t *clash;
// short-circuit instashield for vfx visibility // short-circuit instashield for vfx visibility
t1->instashield = 1; if (t1->player)
t2->instashield = 1; t1->player->instashield = 1;
if (t2->player)
t2->player->instashield = 1;
S_StartSound(t1->mo, sfx_parry); S_StartSound(t1, sfx_parry);
K_AddHitLag(t1->mo, 6, false); K_AddHitLag(t1, 6, false);
K_AddHitLag(t2->mo, 6, false); K_AddHitLag(t2, 6, false);
clash = P_SpawnMobj((t1->mo->x/2) + (t2->mo->x/2), (t1->mo->y/2) + (t2->mo->y/2), (t1->mo->z/2) + (t2->mo->z/2), MT_POWERCLASH); clash = P_SpawnMobj((t1->x/2) + (t2->x/2), (t1->y/2) + (t2->y/2), (t1->z/2) + (t2->z/2), MT_POWERCLASH);
// needs to handle mixed scale collisions (t1 grow t2 invinc)... // needs to handle mixed scale collisions (t1 grow t2 invinc)...
clash->z = clash->z + (t1->mo->height/4) + (t2->mo->height/4); clash->z = clash->z + (t1->height/4) + (t2->height/4);
clash->angle = R_PointToAngle2(clash->x, clash->y, t1->mo->x, t1->mo->y) + ANGLE_90; clash->angle = R_PointToAngle2(clash->x, clash->y, t1->x, t1->y) + ANGLE_90;
// Shrink over time (accidental behavior that looked good) // Shrink over time (accidental behavior that looked good)
clash->destscale = (t1->mo->scale/2) + (t2->mo->scale/2); clash->destscale = (t1->scale) + (t2->scale);
P_SetScale(clash, 3*clash->destscale/2); P_SetScale(clash, 3*clash->destscale/2);
} }
void K_DoGuardBreak(mobj_t *t1, mobj_t *t2) {
mobj_t *clash;
if (!(t1->player && t2->player))
return;
// short-circuit instashield for vfx visibility
t1->player->instaShieldCooldown = 2*TICRATE;
t1->player->guardCooldown = 2*TICRATE;
S_StartSound(t1, sfx_gbrk);
K_AddHitLag(t1, 24, true);
P_DamageMobj(t1, t2, t2, 1, DMG_STING);
clash = P_SpawnMobj((t1->x/2) + (t2->x/2), (t1->y/2) + (t2->y/2), (t1->z/2) + (t2->z/2), MT_GUARDBREAK);
// needs to handle mixed scale collisions
clash->z = clash->z + (t1->height/4) + (t2->height/4);
clash->angle = R_PointToAngle2(clash->x, clash->y, t1->x, t1->y) + ANGLE_90;
clash->color = t1->color;
clash->destscale = 3*((t1->scale) + (t2->scale))/2;
}
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 damage) void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 damage)
{ {
UINT8 points = 1; UINT8 points = 1;
@ -7777,7 +7812,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
// where's the < 0 check? see below the following block! // 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 2 seconds when playing.
tic_t digestionpower = ((10 - player->kartspeed) + (10 - player->kartweight))-1; // 1 to 17 tic_t digestionpower = ((10 - player->kartspeed) + (10 - player->kartweight))-1; // 1 to 17
// currently 0-34 // currently 0-34
@ -7789,7 +7824,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
} }
else else
{ {
spheredigestion -= digestionpower; spheredigestion -= digestionpower/2;
} }
if ((player->spheres > 0) && (player->spheredigestion > 0)) if ((player->spheres > 0) && (player->spheredigestion > 0))
@ -7807,6 +7842,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->spheres--; player->spheres--;
player->spheredigestion = spheredigestion; player->spheredigestion = spheredigestion;
} }
if (K_PlayerGuard(player) && (player->ebrakefor%6 == 0))
player->spheres--;
} }
else else
{ {
@ -7877,6 +7915,19 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->gateBoost) if (player->gateBoost)
player->gateBoost--; player->gateBoost--;
if (player->instaShieldCooldown)
{
player->instaShieldCooldown--;
if (!P_IsObjectOnGround(player->mo))
player->instaShieldCooldown = max(player->instaShieldCooldown, 1);
}
if (player->guardCooldown)
player->guardCooldown--;
if (player->whip && P_MobjWasRemoved(player->whip))
P_SetTarget(&player->whip, NULL);
if (player->startboost > 0 && onground == true) if (player->startboost > 0 && onground == true)
{ {
player->startboost--; player->startboost--;
@ -7980,6 +8031,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->tiregrease) if (player->tiregrease)
player->tiregrease--; player->tiregrease--;
if (player->spinouttimer || player->tumbleBounces)
{
if (player->incontrol > 0)
player->incontrol = 0;
player->incontrol--;
}
else
{
if (player->incontrol < 0)
player->incontrol = 0;
player->incontrol++;
}
player->incontrol = min(player->incontrol, 5*TICRATE);
player->incontrol = max(player->incontrol, -5*TICRATE);
if (player->tumbleBounces > 0) if (player->tumbleBounces > 0)
{ {
K_HandleTumbleSound(player); K_HandleTumbleSound(player);
@ -8097,6 +8164,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->pflags &= ~PF_DRIFTINPUT; player->pflags &= ~PF_DRIFTINPUT;
} }
if (K_PlayerGuard(player))
player->instaShieldCooldown = max(player->instaShieldCooldown, 12);
// Roulette Code // Roulette Code
K_KartItemRoulette(player, cmd); K_KartItemRoulette(player, cmd);
@ -9784,6 +9854,11 @@ boolean K_PlayerEBrake(player_t *player)
return false; return false;
} }
boolean K_PlayerGuard(player_t *player)
{
return (K_PlayerEBrake(player) && player->spheres > 0 && player->guardCooldown == 0);
}
SINT8 K_Sliptiding(player_t *player) SINT8 K_Sliptiding(player_t *player)
{ {
if (player->mo->eflags & MFE_UNDERWATER) if (player->mo->eflags & MFE_UNDERWATER)
@ -9825,6 +9900,26 @@ void K_KartEbrakeVisuals(player_t *p)
if (!S_SoundPlaying(p->mo, sfx_s3kd9s)) if (!S_SoundPlaying(p->mo, sfx_s3kd9s))
S_ReducedVFXSound(p->mo, sfx_s3kd9s, p); 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;
if (K_PlayerGuard(p))
S_StartSound(body, sfx_s1af);
}
// HOLD! bubble. // HOLD! bubble.
if (!p->ebrakefor) if (!p->ebrakefor)
{ {
@ -10538,6 +10633,28 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
// Ring boosting // Ring boosting
if (player->pflags & PF_USERINGS) if (player->pflags & PF_USERINGS)
{ {
if (ATTACK_IS_DOWN && player->rings <= 0)
{
if (player->instaShieldCooldown || leveltime < starttime || player->spindash)
{
S_StartSound(player->mo, sfx_kc50);
}
else
{
player->instaShieldCooldown = 50;
player->guardCooldown = 50;
S_StartSound(player->mo, sfx_iwhp);
mobj_t *whip = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INSTAWHIP);
P_SetTarget(&player->whip, whip);
P_SetScale(whip, player->mo->scale);
P_SetTarget(&whip->target, player->mo);
K_MatchGenericExtraFlags(whip, player->mo);
whip->fuse = 12; // Changing instawhip animation duration? Look here
player->flashing = max(player->flashing, 12);
player->mo->momz += 4*mapobjectscale;
}
}
if ((cmd->buttons & BT_ATTACK) && !player->ringdelay && player->rings > 0) if ((cmd->buttons & BT_ATTACK) && !player->ringdelay && player->rings > 0)
{ {
mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING); mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING);
@ -11841,7 +11958,7 @@ UINT32 K_PointLimitForGametype(void)
{ {
if (D_IsPlayerHumanAndGaming(i)) if (D_IsPlayerHumanAndGaming(i))
{ {
ptsCap += 3; ptsCap += 5;
} }
} }
} }

View file

@ -90,7 +90,8 @@ void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage);
void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDamage); void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics, boolean fromDamage);
void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload); void K_AwardPlayerRings(player_t *player, INT32 rings, boolean overload);
void K_DoInstashield(player_t *player); void K_DoInstashield(player_t *player);
void K_DoPowerClash(player_t *t1, player_t *t2); void K_DoPowerClash(mobj_t *t1, mobj_t *t2);
void K_DoGuardBreak(mobj_t *t1, mobj_t *t2);
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved); void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved);
void K_RemoveGrowShrink(player_t *player); void K_RemoveGrowShrink(player_t *player);
boolean K_IsBigger(mobj_t *compare, mobj_t *other); boolean K_IsBigger(mobj_t *compare, mobj_t *other);
@ -178,6 +179,7 @@ SINT8 K_GetForwardMove(player_t *player);
fixed_t K_GetNewSpeed(player_t *player); fixed_t K_GetNewSpeed(player_t *player);
fixed_t K_3dKartMovement(player_t *player); fixed_t K_3dKartMovement(player_t *player);
boolean K_PlayerEBrake(player_t *player); boolean K_PlayerEBrake(player_t *player);
boolean K_PlayerGuard(player_t *player);
SINT8 K_Sliptiding(player_t *player); SINT8 K_Sliptiding(player_t *player);
boolean K_FastFallBounce(player_t *player); boolean K_FastFallBounce(player_t *player);
fixed_t K_PlayerBaseFriction(player_t *player, fixed_t original); fixed_t K_PlayerBaseFriction(player_t *player, fixed_t original);

View file

@ -107,6 +107,14 @@ void Obj_LoopEndpointCollide(mobj_t *special, mobj_t *toucher);
void Obj_BeginDropTargetMorph(mobj_t *target, skincolornum_t color); void Obj_BeginDropTargetMorph(mobj_t *target, skincolornum_t color);
boolean Obj_DropTargetMorphThink(mobj_t *morph); 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);
void Obj_GuardBreakThink(mobj_t *fx);
/* Ring Shooter */ /* Ring Shooter */
boolean Obj_RingShooterThinker(mobj_t *mo); boolean Obj_RingShooterThinker(mobj_t *mo);
boolean Obj_PlayerRingShooterFreeze(player_t *const player); boolean Obj_PlayerRingShooterFreeze(player_t *const player);

View file

@ -319,6 +319,10 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->sliptideZipDelay); lua_pushinteger(L, plr->sliptideZipDelay);
else if (fastcmp(field,"sliptideZipBoost")) else if (fastcmp(field,"sliptideZipBoost"))
lua_pushinteger(L, plr->sliptideZipBoost); lua_pushinteger(L, plr->sliptideZipBoost);
else if (fastcmp(field,"instaShieldCooldown"))
lua_pushinteger(L, plr->instaShieldCooldown);
else if (fastcmp(field,"guardCooldown"))
lua_pushinteger(L, plr->guardCooldown);
/* /*
else if (fastcmp(field,"itemroulette")) else if (fastcmp(field,"itemroulette"))
lua_pushinteger(L, plr->itemroulette); lua_pushinteger(L, plr->itemroulette);
@ -713,6 +717,10 @@ static int player_set(lua_State *L)
plr->sliptideZipDelay = luaL_checkinteger(L, 3); plr->sliptideZipDelay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"sliptideZipBoost")) else if (fastcmp(field,"sliptideZipBoost"))
plr->sliptideZipBoost = luaL_checkinteger(L, 3); plr->sliptideZipBoost = luaL_checkinteger(L, 3);
else if (fastcmp(field,"instaShieldCooldown"))
plr->instaShieldCooldown = luaL_checkinteger(L, 3);
else if (fastcmp(field,"guardCooldown"))
plr->guardCooldown = luaL_checkinteger(L, 3);
/* /*
else if (fastcmp(field,"itemroulette")) else if (fastcmp(field,"itemroulette"))
plr->itemroulette = luaL_checkinteger(L, 3); plr->itemroulette = luaL_checkinteger(L, 3);

View file

@ -17,4 +17,6 @@ target_sources(SRB2SDL2 PRIVATE
ring-shooter.c ring-shooter.c
audience.c audience.c
random-item.c random-item.c
instawhip.c
block.c
) )

84
src/objects/block.c Normal file
View file

@ -0,0 +1,84 @@
#include "../doomdef.h"
#include "../info.h"
#include "../k_objects.h"
#include "../p_local.h"
#include "../k_kart.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_MoveOrigin(ring, mo->x, mo->y, mo->z + mo->height/2);
ring->flags |= MF_NOCLIPTHING;
ring->color = mo->color;
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * player->spheres;
P_SetScale(ring, baseScale);
// 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 (!K_PlayerGuard(player))
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);
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * player->spheres;
P_SetScale(body, baseScale);
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 (!K_PlayerGuard(player))
body->renderflags |= RF_DONTDRAW;
}
}
void Obj_GuardBreakThink (mobj_t *fx)
{
if (leveltime%2)
fx->renderflags &= ~RF_DONTDRAW;
else
fx->renderflags |= RF_DONTDRAW;
}

42
src/objects/instawhip.c Normal file
View file

@ -0,0 +1,42 @@
#include "../doomdef.h"
#include "../info.h"
#include "../k_objects.h"
#include "../p_local.h"
void Obj_InstaWhipThink (mobj_t *whip)
{
if (P_MobjWasRemoved(whip->target))
{
P_RemoveMobj(whip);
}
else
{
mobj_t *mo = whip->target;
player_t *player = mo->player;
// Follow player
whip->flags &= ~(MF_NOCLIPTHING);
P_SetScale(whip, whip->target->scale);
P_MoveOrigin(whip, mo->x, mo->y, mo->z + mo->height/2);
whip->flags |= MF_NOCLIPTHING;
// Twirl
whip->angle = whip->target->angle + (ANG30 * 2 * whip->fuse);
whip->target->player->drawangle = whip->angle;
if (player->follower)
player->follower->angle = whip->angle;
player->pflags |= PF_GAINAX;
player->glanceDir = -2;
// Visuals
whip->renderflags |= RF_NOSPLATBILLBOARD;
if (whip->renderflags & RF_DONTDRAW)
whip->renderflags &= ~RF_DONTDRAW;
else
whip->renderflags |= RF_DONTDRAW;
if (whip->extravalue2) // Whip has no hitbox but removing it is a pain in the ass
whip->renderflags |= RF_DONTDRAW;
}
}

View file

@ -440,9 +440,15 @@ adjust_monitor_drop
( mobj_t * monitor, ( mobj_t * monitor,
mobj_t * drop) mobj_t * drop)
{ {
P_InstaThrust(drop, drop->angle, 4*mapobjectscale); if (drop->type == MT_EMERALD)
{
drop->momz *= 8; drop->momx = drop->momy = drop->momz = 0;
}
else
{
P_InstaThrust(drop, drop->angle, 8*mapobjectscale);
drop->momz *= 8;
}
K_FlipFromObject(drop, monitor); K_FlipFromObject(drop, monitor);
@ -615,7 +621,16 @@ Obj_MonitorGetDamage
} }
else else
{ {
damage = FRACUNIT; // kill instantly if (inflictor->type == MT_INSTAWHIP)
{
damage = FRACUNIT/3;
if (K_IsPlayerWanted(inflictor->target->player))
damage = FRACUNIT; // Emerald hunting time!
}
else
{
damage = FRACUNIT; // kill instantly
}
} }
return damage; return damage;

View file

@ -670,6 +670,7 @@ static UINT8 GetUFODamage(mobj_t *inflictor, UINT8 damageType)
{ {
case MT_JAWZ_SHIELD: case MT_JAWZ_SHIELD:
case MT_ORBINAUT_SHIELD: case MT_ORBINAUT_SHIELD:
case MT_INSTAWHIP:
{ {
// Shields deal chip damage. // Shields deal chip damage.
return 10; return 10;

View file

@ -2188,6 +2188,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (!force) if (!force)
{ {
boolean invincible = true; boolean invincible = true;
boolean clash = false;
sfxenum_t sfx = sfx_None; sfxenum_t sfx = sfx_None;
if (!(gametyperules & GTR_BUMPERS)) if (!(gametyperules & GTR_BUMPERS))
@ -2208,6 +2209,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
{ {
sfx = sfx_grownd; sfx = sfx_grownd;
} }
else if (K_PlayerGuard(player))
{
sfx = sfx_s3k3a;
clash = true;
}
else if (player->hyudorotimer > 0) else if (player->hyudorotimer > 0)
; ;
else else
@ -2249,6 +2255,15 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
S_StartSound(target, sfx); S_StartSound(target, sfx);
} }
if (clash)
{
player->spheres = max(player->spheres - 10, 0);
if (inflictor)
K_DoPowerClash(target, inflictor);
else if (source)
K_DoPowerClash(target, source);
}
// Full invulnerability // Full invulnerability
K_DoInstashield(player); K_DoInstashield(player);
return false; return false;
@ -2306,7 +2321,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
damage = 0; damage = 0;
} }
if (type == DMG_STING || type == DMG_STUMBLE) // 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 && inflictor->type != MT_INSTAWHIP))
{ {
damage = 0; damage = 0;
} }
@ -2426,6 +2443,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
K_PlayPainSound(target, source); K_PlayPainSound(target, source);
} }
if (gametyperules & GTR_BUMPERS)
player->spheres = min(player->spheres + 5, 40);
if ((hardhit == true) || cv_kartdebughuddrop.value) if ((hardhit == true) || cv_kartdebughuddrop.value)
{ {
K_DropItems(player); K_DropItems(player);

View file

@ -741,7 +741,17 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
return BMIT_ABORT; // stop moving return BMIT_ABORT; // stop moving
} }
// SRB2kart 011617 - Colission[sic] code for kart items //{ // SRB2kart 011617 - Colission[sic] code for kart items //
if (tm.thing->type == MT_INSTAWHIP)
{
if (tm.thing->z > thing->z + thing->height)
return BMIT_CONTINUE; // overhead
if (tm.thing->z + tm.thing->height < thing->z)
return BMIT_CONTINUE; // underneath
K_InstaWhipCollide(tm.thing, thing);
return BMIT_CONTINUE;
}
if (thing->type == MT_SPB) if (thing->type == MT_SPB)
{ {

View file

@ -8356,6 +8356,26 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
Obj_GardenTopThink(mobj); Obj_GardenTopThink(mobj);
break; break;
} }
case MT_INSTAWHIP:
{
Obj_InstaWhipThink(mobj);
break;
}
case MT_BLOCKRING:
{
Obj_BlockRingThink(mobj);
break;
}
case MT_BLOCKBODY:
{
Obj_BlockBodyThink(mobj);
break;
}
case MT_GUARDBREAK:
{
Obj_GuardBreakThink(mobj);
break;
}
case MT_GARDENTOPSPARK: case MT_GARDENTOPSPARK:
{ {
Obj_GardenTopSparkThink(mobj); Obj_GardenTopSparkThink(mobj);

View file

@ -74,7 +74,8 @@ typedef enum
HOVERHYUDORO = 0x0020, HOVERHYUDORO = 0x0020,
STUMBLE = 0x0040, STUMBLE = 0x0040,
SLIPTIDEZIP = 0x0080, SLIPTIDEZIP = 0x0080,
RINGSHOOTER = 0x0100 RINGSHOOTER = 0x0100,
WHIP = 0x0200,
} player_saveflags; } player_saveflags;
static inline void P_ArchivePlayer(savebuffer_t *save) static inline void P_ArchivePlayer(savebuffer_t *save)
@ -225,6 +226,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
if (players[i].sliptideZipIndicator) if (players[i].sliptideZipIndicator)
flags |= SLIPTIDEZIP; flags |= SLIPTIDEZIP;
if (players[i].whip)
flags |= WHIP;
if (players[i].ringShooter) if (players[i].ringShooter)
flags |= RINGSHOOTER; flags |= RINGSHOOTER;
@ -251,6 +255,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
if (flags & SLIPTIDEZIP) if (flags & SLIPTIDEZIP)
WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum); WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum);
if (flags & WHIP)
WRITEUINT32(save->p, players[i].whip->mobjnum);
if (flags & RINGSHOOTER) if (flags & RINGSHOOTER)
WRITEUINT32(save->p, players[i].ringShooter->mobjnum); WRITEUINT32(save->p, players[i].ringShooter->mobjnum);
@ -419,6 +426,10 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEMEM(save->p, players[i].public_key, PUBKEYLENGTH); WRITEMEM(save->p, players[i].public_key, PUBKEYLENGTH);
WRITEUINT8(save->p, players[i].instaShieldCooldown);
WRITEUINT8(save->p, players[i].guardCooldown);
WRITEINT16(save->p, players[i].incontrol);
// respawnvars_t // respawnvars_t
WRITEUINT8(save->p, players[i].respawn.state); WRITEUINT8(save->p, players[i].respawn.state);
WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].respawn.wp)); WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].respawn.wp));
@ -635,6 +646,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
if (flags & SLIPTIDEZIP) if (flags & SLIPTIDEZIP)
players[i].sliptideZipIndicator = (mobj_t *)(size_t)READUINT32(save->p); players[i].sliptideZipIndicator = (mobj_t *)(size_t)READUINT32(save->p);
if (flags & WHIP)
players[i].whip = (mobj_t *)(size_t)READUINT32(save->p);
if (flags & RINGSHOOTER) if (flags & RINGSHOOTER)
players[i].ringShooter = (mobj_t *)(size_t)READUINT32(save->p); players[i].ringShooter = (mobj_t *)(size_t)READUINT32(save->p);
@ -804,6 +818,10 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
READMEM(save->p, players[i].public_key, PUBKEYLENGTH); READMEM(save->p, players[i].public_key, PUBKEYLENGTH);
players[i].instaShieldCooldown = READUINT8(save->p);
players[i].guardCooldown = READUINT8(save->p);
players[i].incontrol = READINT16(save->p);
// respawnvars_t // respawnvars_t
players[i].respawn.state = READUINT8(save->p); players[i].respawn.state = READUINT8(save->p);
players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save->p); players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save->p);
@ -4982,6 +5000,13 @@ static void P_RelinkPointers(void)
if (!P_SetTarget(&players[i].sliptideZipIndicator, P_FindNewPosition(temp))) if (!P_SetTarget(&players[i].sliptideZipIndicator, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "sliptideZipIndicator not found on player %d\n", i); CONS_Debug(DBG_GAMELOGIC, "sliptideZipIndicator not found on player %d\n", i);
} }
if (players[i].whip)
{
temp = (UINT32)(size_t)players[i].whip;
players[i].whip = NULL;
if (!P_SetTarget(&players[i].whip, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "whip not found on player %d\n", i);
}
if (players[i].ringShooter) if (players[i].ringShooter)
{ {
temp = (UINT32)(size_t)players[i].ringShooter; temp = (UINT32)(size_t)players[i].ringShooter;

View file

@ -49,7 +49,7 @@
#include "k_kart.h" // HITLAGJITTERS #include "k_kart.h" // HITLAGJITTERS
#include "r_fps.h" #include "r_fps.h"
#define MINZ (FRACUNIT*16) #define MINZ (FRACUNIT*4)
#define BASEYCENTER (BASEVIDHEIGHT/2) #define BASEYCENTER (BASEVIDHEIGHT/2)
typedef struct typedef struct

View file

@ -901,7 +901,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"mbv8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"mbv8f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv90", 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, ""}, {"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, ""}, {"mbv93", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"mbv94", 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, ""}, {"mbv95", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
@ -1184,6 +1184,9 @@ sfxinfo_t S_sfx[NUMSFX] =
{"monch", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"monch", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"etexpl", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Game crash"}, {"etexpl", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Game crash"},
{"iwhp", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Instawhip attack
{"gbrk", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Guard break!
// SRB2Kart - Engine sounds // SRB2Kart - Engine sounds
// Engine class A // Engine class A
{"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""},

View file

@ -1253,6 +1253,9 @@ typedef enum
sfx_monch, sfx_monch,
sfx_etexpl, sfx_etexpl,
sfx_iwhp,
sfx_gbrk,
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy... // Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
// Engine class A - Low Speed, Low Weight // Engine class A - Low Speed, Low Weight
sfx_krta00, sfx_krta00,