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 *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];

View file

@ -3287,6 +3287,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_SLIPTIDEZIP",
"S_INSTAWHIP",
"S_BLOCKRING",
"S_BLOCKBODY",
// Signpost sparkles
"S_SIGNSPARK1",
"S_SIGNSPARK2",
@ -4011,6 +4015,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_INSTASHIELDB7",
"S_POWERCLASH", // Invinc/Grow no damage collide VFX
"S_GUARDBREAK", // Guard break
"S_PLAYERARROW", // Above player arrow
"S_PLAYERARROW_BOX",
@ -5318,6 +5323,10 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_SLIPTIDEZIP",
"MT_INSTAWHIP",
"MT_BLOCKRING",
"MT_BLOCKBODY",
"MT_SIGNSPARKLE",
"MT_FASTLINE",
@ -5487,7 +5496,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_INSTASHIELDB",
"MT_POWERCLASH", // Invinc/Grow no damage clash VFX
"MT_GUARDBREAK", // Guard break
"MT_PLAYERARROW",
"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].awayview.mobj, NULL);
P_SetTarget(&players[player].stumbleIndicator, NULL);
P_SetTarget(&players[player].whip, NULL);
P_SetTarget(&players[player].ringShooter, NULL);
P_SetTarget(&players[player].followmobj, NULL);

View file

@ -555,6 +555,10 @@ char sprnames[NUMSPRITES + 1][5] =
"SLPT", // Sliptide zip indicator
"IWHP", // Instawhip
"GRNG", // Guard ring
"GBDY", // Guard body
"WIPD", // Wipeout dust trail
"DRIF", // Drift Sparks
"BDRF", // Brake drift sparks
@ -634,6 +638,7 @@ char sprnames[NUMSPRITES + 1][5] =
"ISTB", // instashield layer B
"PWCL", // Invinc/grow clash VFX
"GBRK", // Guard break
"ARRO", // player arrows
"ITEM",
@ -3946,6 +3951,10 @@ state_t states[NUMSTATES] =
{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, 1, {NULL}, 0, 0, S_SIGNSPARK3}, // S_SIGNSPARK2
{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_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
{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
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
-1, // doomednum
@ -26089,6 +26180,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
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
-1, // doomednum
S_PLAYERARROW, // spawnstate

View file

@ -1108,6 +1108,10 @@ 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
SPR_BDRF, // Brake drift sparks
@ -1187,6 +1191,7 @@ typedef enum sprite
SPR_ISTB, // instashield layer B
SPR_PWCL, // Invinc/grow clash VFX
SPR_GBRK, // Guard break
SPR_ARRO, // player arrows
SPR_ITEM,
@ -4357,6 +4362,10 @@ typedef enum state
S_SLIPTIDEZIP,
S_INSTAWHIP,
S_BLOCKRING,
S_BLOCKBODY,
// Signpost sparkles
S_SIGNSPARK1,
S_SIGNSPARK2,
@ -5080,6 +5089,7 @@ typedef enum state
S_INSTASHIELDB7,
S_POWERCLASH, // Grow/Invinc clash VFX
S_GUARDBREAK,
S_PLAYERARROW, // Above player arrow
S_PLAYERARROW_BOX,
@ -6423,6 +6433,10 @@ typedef enum mobj_type
MT_MAGICIANBOX,
MT_SLIPTIDEZIP,
MT_INSTAWHIP,
MT_BLOCKRING,
MT_BLOCKBODY,
MT_SIGNSPARKLE,
MT_FASTLINE,
@ -6592,6 +6606,7 @@ typedef enum mobj_type
MT_INSTASHIELDB,
MT_POWERCLASH, // Grow/Invinc clash VFX
MT_GUARDBREAK,
MT_PLAYERARROW,
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,
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)
emerald->momz = (117 * emerald->momz) / 200;
@ -265,6 +265,9 @@ void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType)
UINT8 i;
SINT8 flip = P_MobjFlip(player->mo);
if (player->incontrol < TICRATE)
return;
for (i = 0; i < 14; i++)
{
UINT32 emeraldFlag = (1 << i);
@ -275,6 +278,7 @@ void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType)
P_SetTarget(&emerald->target, player->mo);
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);
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)
{
// 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)
@ -1453,12 +1529,16 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
{
if (player->pflags & PF_USERINGS)
{
// Use rings!
if (leveltime > starttime)
if (player->rings > 0)
{
// Use rings!
K_BotItemRings(player, cmd);
}
else
{
// Use the instashield!
K_BotItemInstashield(player, cmd);
}
}
else
{

View file

@ -787,6 +787,140 @@ boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
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)
{
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->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD)
|| (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))
{
K_DoPowerClash(t1->player, t2->player);
K_DoPowerClash(t1, t2);
return false;
}
@ -975,7 +1110,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;

View file

@ -24,6 +24,8 @@ 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 *shield, mobj_t *victim);
boolean K_KitchenSinkCollide(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);
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(mobj2->player);
@ -1979,6 +1987,7 @@ void K_SpawnMagicianParticles(mobj_t *mo, int spread)
dust->frame |= FF_SUBTRACT|FF_TRANS90;
dust->color = color;
dust->colorized = true;
dust->hitlag = 0;
}
}
@ -3606,28 +3615,54 @@ void K_DoInstashield(player_t *player)
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;
// short-circuit instashield for vfx visibility
t1->instashield = 1;
t2->instashield = 1;
if (t1->player)
t1->player->instashield = 1;
if (t2->player)
t2->player->instashield = 1;
S_StartSound(t1->mo, sfx_parry);
K_AddHitLag(t1->mo, 6, false);
K_AddHitLag(t2->mo, 6, false);
S_StartSound(t1, sfx_parry);
K_AddHitLag(t1, 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)...
clash->z = clash->z + (t1->mo->height/4) + (t2->mo->height/4);
clash->angle = R_PointToAngle2(clash->x, clash->y, t1->mo->x, t1->mo->y) + ANGLE_90;
clash->z = clash->z + (t1->height/4) + (t2->height/4);
clash->angle = R_PointToAngle2(clash->x, clash->y, t1->x, t1->y) + ANGLE_90;
// 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);
}
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)
{
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!
{
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
// currently 0-34
@ -7789,7 +7824,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 +7842,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->spheres--;
player->spheredigestion = spheredigestion;
}
if (K_PlayerGuard(player) && (player->ebrakefor%6 == 0))
player->spheres--;
}
else
{
@ -7877,6 +7915,19 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (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)
{
player->startboost--;
@ -7980,6 +8031,22 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (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)
{
K_HandleTumbleSound(player);
@ -8097,6 +8164,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->pflags &= ~PF_DRIFTINPUT;
}
if (K_PlayerGuard(player))
player->instaShieldCooldown = max(player->instaShieldCooldown, 12);
// Roulette Code
K_KartItemRoulette(player, cmd);
@ -9784,6 +9854,11 @@ boolean K_PlayerEBrake(player_t *player)
return false;
}
boolean K_PlayerGuard(player_t *player)
{
return (K_PlayerEBrake(player) && player->spheres > 0 && player->guardCooldown == 0);
}
SINT8 K_Sliptiding(player_t *player)
{
if (player->mo->eflags & MFE_UNDERWATER)
@ -9825,6 +9900,26 @@ 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;
if (K_PlayerGuard(p))
S_StartSound(body, sfx_s1af);
}
// HOLD! bubble.
if (!p->ebrakefor)
{
@ -10538,6 +10633,28 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
// Ring boosting
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)
{
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))
{
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_AwardPlayerRings(player_t *player, INT32 rings, boolean overload);
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_RemoveGrowShrink(player_t *player);
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_3dKartMovement(player_t *player);
boolean K_PlayerEBrake(player_t *player);
boolean K_PlayerGuard(player_t *player);
SINT8 K_Sliptiding(player_t *player);
boolean K_FastFallBounce(player_t *player);
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);
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 */
boolean Obj_RingShooterThinker(mobj_t *mo);
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);
else if (fastcmp(field,"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"))
lua_pushinteger(L, plr->itemroulette);
@ -713,6 +717,10 @@ static int player_set(lua_State *L)
plr->sliptideZipDelay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"sliptideZipBoost"))
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"))
plr->itemroulette = luaL_checkinteger(L, 3);

View file

@ -17,4 +17,6 @@ target_sources(SRB2SDL2 PRIVATE
ring-shooter.c
audience.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 * drop)
{
P_InstaThrust(drop, drop->angle, 4*mapobjectscale);
drop->momz *= 8;
if (drop->type == MT_EMERALD)
{
drop->momx = drop->momy = drop->momz = 0;
}
else
{
P_InstaThrust(drop, drop->angle, 8*mapobjectscale);
drop->momz *= 8;
}
K_FlipFromObject(drop, monitor);
@ -615,7 +621,16 @@ Obj_MonitorGetDamage
}
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;

View file

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

View file

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

View file

@ -741,7 +741,17 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
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)
{

View file

@ -8356,6 +8356,26 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
Obj_GardenTopThink(mobj);
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:
{
Obj_GardenTopSparkThink(mobj);

View file

@ -74,7 +74,8 @@ typedef enum
HOVERHYUDORO = 0x0020,
STUMBLE = 0x0040,
SLIPTIDEZIP = 0x0080,
RINGSHOOTER = 0x0100
RINGSHOOTER = 0x0100,
WHIP = 0x0200,
} player_saveflags;
static inline void P_ArchivePlayer(savebuffer_t *save)
@ -225,6 +226,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
if (players[i].sliptideZipIndicator)
flags |= SLIPTIDEZIP;
if (players[i].whip)
flags |= WHIP;
if (players[i].ringShooter)
flags |= RINGSHOOTER;
@ -251,6 +255,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
if (flags & SLIPTIDEZIP)
WRITEUINT32(save->p, players[i].sliptideZipIndicator->mobjnum);
if (flags & WHIP)
WRITEUINT32(save->p, players[i].whip->mobjnum);
if (flags & RINGSHOOTER)
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);
WRITEUINT8(save->p, players[i].instaShieldCooldown);
WRITEUINT8(save->p, players[i].guardCooldown);
WRITEINT16(save->p, players[i].incontrol);
// respawnvars_t
WRITEUINT8(save->p, players[i].respawn.state);
WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].respawn.wp));
@ -635,6 +646,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
if (flags & SLIPTIDEZIP)
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)
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);
players[i].instaShieldCooldown = READUINT8(save->p);
players[i].guardCooldown = READUINT8(save->p);
players[i].incontrol = READINT16(save->p);
// respawnvars_t
players[i].respawn.state = READUINT8(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)))
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)
{
temp = (UINT32)(size_t)players[i].ringShooter;

View file

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

View file

@ -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, ""},
@ -1184,6 +1184,9 @@ sfxinfo_t S_sfx[NUMSFX] =
{"monch", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"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
// Engine class A
{"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""},

View file

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