Minor (but important!) polishing

- Thunder Shield now attracts rings
- Colorize the ring counter at max yellow
- Rings in the collecting animation are considered for determining if you can't pick up rings anymore, preventing a LOT of rings being deleted from the map over time.
- Flung rings don't lose speed over time anymore
- Flund rings last way longer
- Using rings is much less touchy (holding the button from before an item roulette will let you continue using them until you let go, using certain items won't make you use a couple rings afterwards)
- 0 rings is now counted as debt when getting hit, making debt easier to get out of (getting hit by a spike now would put you at -2 instead of -5)
- Move Super Ring toward the end of the item (so I don't have to modify gfx.kart to fix dropped items)
This commit is contained in:
TehRealSalt 2019-03-09 04:33:46 -05:00
parent 4a68f98dc2
commit db8f23561d
6 changed files with 545 additions and 471 deletions

View file

@ -234,7 +234,6 @@ typedef enum
{ {
KITEM_SAD = -1, KITEM_SAD = -1,
KITEM_NONE = 0, KITEM_NONE = 0,
KITEM_SUPERRING,
KITEM_SNEAKER, KITEM_SNEAKER,
KITEM_ROCKETSNEAKER, KITEM_ROCKETSNEAKER,
KITEM_INVINCIBILITY, KITEM_INVINCIBILITY,
@ -250,6 +249,7 @@ typedef enum
KITEM_THUNDERSHIELD, KITEM_THUNDERSHIELD,
KITEM_HYUDORO, KITEM_HYUDORO,
KITEM_POGOSPRING, KITEM_POGOSPRING,
KITEM_SUPERRING,
KITEM_KITCHENSINK, KITEM_KITCHENSINK,
NUMKARTITEMS, NUMKARTITEMS,
@ -298,6 +298,8 @@ typedef enum
k_boostcharge, // Charge-up for boosting at the start of the race k_boostcharge, // Charge-up for boosting at the start of the race
k_startboost, // Boost you get from start of race or respawn drop dash k_startboost, // Boost you get from start of race or respawn drop dash
k_rings, // Number of held rings k_rings, // Number of held rings
k_pickuprings, // Number of rings being picked up before added to the counter (prevents rings from being deleted forever over 20)
k_userings, // Have to be not holding the item button to change from using rings to using items (or vice versa), to prevent some weirdness with the button
k_ringdelay, // 3 tic delay between every ring usage k_ringdelay, // 3 tic delay between every ring usage
k_ringboost, // Ring boost timer k_ringboost, // Ring boost timer
k_jmp, // In Mario Kart, letting go of the jump button stops the drift k_jmp, // In Mario Kart, letting go of the jump button stops the drift

View file

@ -8355,6 +8355,8 @@ static const char *const KARTSTUFF_LIST[] = {
"BOOSTCHARGE", "BOOSTCHARGE",
"STARTBOOST", "STARTBOOST",
"RINGS", "RINGS",
"PICKUPRINGS",
"USERINGS",
"RINGDELAY", "RINGDELAY",
"RINGBOOST", "RINGBOOST",
"JMP", "JMP",
@ -8943,7 +8945,6 @@ struct {
// kartitems_t // kartitems_t
{"KITEM_SAD",KITEM_SAD}, // Actual items (can be set for k_itemtype) {"KITEM_SAD",KITEM_SAD}, // Actual items (can be set for k_itemtype)
{"KITEM_NONE",KITEM_NONE}, {"KITEM_NONE",KITEM_NONE},
{"KITEM_SUPERRING",KITEM_SUPERRING},
{"KITEM_SNEAKER",KITEM_SNEAKER}, {"KITEM_SNEAKER",KITEM_SNEAKER},
{"KITEM_ROCKETSNEAKER",KITEM_ROCKETSNEAKER}, {"KITEM_ROCKETSNEAKER",KITEM_ROCKETSNEAKER},
{"KITEM_INVINCIBILITY",KITEM_INVINCIBILITY}, {"KITEM_INVINCIBILITY",KITEM_INVINCIBILITY},
@ -8959,6 +8960,7 @@ struct {
{"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD}, {"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD},
{"KITEM_HYUDORO",KITEM_HYUDORO}, {"KITEM_HYUDORO",KITEM_HYUDORO},
{"KITEM_POGOSPRING",KITEM_POGOSPRING}, {"KITEM_POGOSPRING",KITEM_POGOSPRING},
{"KITEM_SUPERRING",KITEM_SUPERRING},
{"KITEM_KITCHENSINK",KITEM_KITCHENSINK}, {"KITEM_KITCHENSINK",KITEM_KITCHENSINK},
{"NUMKARTITEMS",NUMKARTITEMS}, {"NUMKARTITEMS",NUMKARTITEMS},
{"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch) {"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch)

View file

@ -1136,6 +1136,24 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
} }
// SPECIAL CASE No. 4: // SPECIAL CASE No. 4:
// Being in ring debt occasionally forces Super Ring on you
if (player->kartstuff[k_rings] <= 0 && cv_superring.value)
{
INT32 debtamount = min(20, abs(player->kartstuff[k_rings])+1);
if (P_RandomChance((debtamount*FRACUNIT)/20))
{
K_KartGetItemResult(player, KITEM_SUPERRING);
player->kartstuff[k_itemblink] = TICRATE;
player->kartstuff[k_itemblinkmode] = (mashed ? 1 : 0);
player->kartstuff[k_itemroulette] = 0;
player->kartstuff[k_roulettetype] = 0;
if (P_IsLocalPlayer(player))
S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf));
return;
}
}
// SPECIAL CASE No. 5:
// Force SPB onto 2nd if they get too far behind // Force SPB onto 2nd if they get too far behind
if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*6) if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*6)
&& spbplace == -1 && !indirectitemcooldown && !dontforcespb && spbplace == -1 && !indirectitemcooldown && !dontforcespb
@ -1148,6 +1166,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
player->kartstuff[k_roulettetype] = 0; player->kartstuff[k_roulettetype] = 0;
if (P_IsLocalPlayer(player)) if (P_IsLocalPlayer(player))
S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf));
return;
} }
// NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables. // NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables.
@ -1418,6 +1437,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
{ {
mobj1->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; mobj1->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1;
mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]); mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]);
//mobj1->player->kartstuff[k_spinouttype] = 1; // Enforce type
} }
else if (mobj2->player) // Player VS player bumping only else if (mobj2->player) // Player VS player bumping only
{ {
@ -1440,6 +1460,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
{ {
mobj2->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; mobj2->player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1;
mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]); mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]);
//mobj2->player->kartstuff[k_spinouttype] = 1; // Enforce type
} }
else if (mobj1->player) // Player VS player bumping only else if (mobj1->player) // Player VS player bumping only
{ {
@ -1742,6 +1763,7 @@ void K_RespawnChecker(player_t *player)
player->mo->colorized = false; player->mo->colorized = false;
player->kartstuff[k_dropdash] = 0; player->kartstuff[k_dropdash] = 0;
player->kartstuff[k_respawn] = 0; player->kartstuff[k_respawn] = 0;
//P_PlayRinglossSound(player->mo);
P_PlayerRingBurst(player, 3); P_PlayerRingBurst(player, 3);
} }
} }
@ -4804,6 +4826,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
ring->extravalue1 = 1; // Ring collect animation timer ring->extravalue1 = 1; // Ring collect animation timer
ring->angle = player->mo->angle; // animation angle ring->angle = player->mo->angle; // animation angle
P_SetTarget(&ring->target, player->mo); // toucher for thinker P_SetTarget(&ring->target, player->mo); // toucher for thinker
player->kartstuff[k_pickuprings]++;
if (player->kartstuff[k_superring] <= 3) if (player->kartstuff[k_superring] <= 3)
ring->cvmem = 1; // play caching when collected ring->cvmem = 1; // play caching when collected
} }
@ -5428,7 +5451,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
else if (cmd->buttons & BT_ATTACK) else if (cmd->buttons & BT_ATTACK)
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_ATTACKDOWN;
if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) && leveltime > starttime
&& player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_squishedtimer] == 0 && player->kartstuff[k_respawn] == 0) && player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_squishedtimer] == 0 && player->kartstuff[k_respawn] == 0)
{ {
// First, the really specific, finicky items that function without the item being directly in your item slot. // First, the really specific, finicky items that function without the item being directly in your item slot.
@ -5464,418 +5487,436 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
S_StartSound(player->mo, sfx_s254); S_StartSound(player->mo, sfx_s254);
} }
} }
// Eggman Monitor exploding
else if (player->kartstuff[k_eggmanexplode])
{
if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanexplode] <= 3*TICRATE && player->kartstuff[k_eggmanexplode] > 1)
player->kartstuff[k_eggmanexplode] = 1;
}
// Eggman Monitor throwing
else if (player->kartstuff[k_eggmanheld])
{
if (ATTACK_IS_DOWN)
{
K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_eggmanheld] = 0;
K_UpdateHnextList(player, true);
}
}
// Rocket Sneaker usage
else if (player->kartstuff[k_rocketsneakertimer] > 1)
{
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO)
{
K_DoSneaker(player, 2);
K_PlayBoostTaunt(player->mo);
player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE;
if (player->kartstuff[k_rocketsneakertimer] < 1)
player->kartstuff[k_rocketsneakertimer] = 1;
}
}
// Grow Canceling
else if (player->kartstuff[k_growshrinktimer] > 0)
{
if (cmd->buttons & BT_ATTACK)
{
player->kartstuff[k_growcancel]++;
if (player->kartstuff[k_growcancel] > 26)
K_RemoveGrowShrink(player);
}
else
player->kartstuff[k_growcancel] = 0;
}
// Ring boosting
else if (player->kartstuff[k_itemtype] == KITEM_NONE)
{
if ((player->pflags & PF_ATTACKDOWN) && !HOLDING_ITEM && NO_HYUDORO
&& !player->kartstuff[k_itemroulette] && !player->kartstuff[k_ringdelay]
&& player->kartstuff[k_rings] > 0)
{
mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING);
ring->extravalue1 = 1; // Ring use animation timer
ring->extravalue2 = 1; // Ring use animation flag
P_SetTarget(&ring->target, player->mo); // user
player->kartstuff[k_rings]--;
player->kartstuff[k_ringdelay] = 3;
}
}
else if (player->kartstuff[k_itemamount] <= 0)
{
player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
}
else else
{ {
switch (player->kartstuff[k_itemtype]) // Ring boosting
if (player->kartstuff[k_userings])
{ {
case KITEM_SUPERRING: if ((player->pflags & PF_ATTACKDOWN) && !HOLDING_ITEM && NO_HYUDORO
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) && !player->kartstuff[k_itemroulette] && !player->kartstuff[k_ringdelay]
&& player->kartstuff[k_rings] > 0)
{
mobj_t *ring = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RING);
ring->extravalue1 = 1; // Ring use animation timer
ring->extravalue2 = 1; // Ring use animation flag
P_SetTarget(&ring->target, player->mo); // user
player->kartstuff[k_rings]--;
player->kartstuff[k_ringdelay] = 3;
}
}
// Other items
else
{
// Eggman Monitor exploding
if (player->kartstuff[k_eggmanexplode])
{
if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanexplode] <= 3*TICRATE && player->kartstuff[k_eggmanexplode] > 1)
player->kartstuff[k_eggmanexplode] = 1;
}
// Eggman Monitor throwing
else if (player->kartstuff[k_eggmanheld])
{
if (ATTACK_IS_DOWN)
{ {
player->kartstuff[k_superring] += (10*3); K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0);
player->kartstuff[k_itemamount]--; K_PlayAttackTaunt(player->mo);
player->kartstuff[k_eggmanheld] = 0;
K_UpdateHnextList(player, true);
} }
break; }
case KITEM_SNEAKER: // Rocket Sneaker usage
else if (player->kartstuff[k_rocketsneakertimer] > 1)
{
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO)
{ {
K_DoSneaker(player, 1); K_DoSneaker(player, 2);
K_PlayBoostTaunt(player->mo); K_PlayBoostTaunt(player->mo);
player->kartstuff[k_itemamount]--; player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE;
if (player->kartstuff[k_rocketsneakertimer] < 1)
player->kartstuff[k_rocketsneakertimer] = 1;
} }
break; }
case KITEM_ROCKETSNEAKER: // Grow Canceling
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO else if (player->kartstuff[k_growshrinktimer] > 0)
&& player->kartstuff[k_rocketsneakertimer] == 0) {
if (cmd->buttons & BT_ATTACK)
{ {
INT32 moloop; player->kartstuff[k_growcancel]++;
mobj_t *mo = NULL; if (player->kartstuff[k_growcancel] > 26)
mobj_t *prev = player->mo; K_RemoveGrowShrink(player);
K_PlayBoostTaunt(player->mo);
//player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s3k3a);
//K_DoSneaker(player, 2);
player->kartstuff[k_rocketsneakertimer] = (itemtime*3);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, true);
for (moloop = 0; moloop < 2; moloop++)
{
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER);
mo->flags |= MF_NOCLIPTHING;
mo->angle = player->mo->angle;
mo->threshold = 10;
mo->movecount = moloop%2;
mo->movedir = mo->lastlook = moloop+1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&mo->hprev, prev);
P_SetTarget(&prev->hnext, mo);
prev = mo;
}
} }
break; else
case KITEM_INVINCIBILITY: player->kartstuff[k_growcancel] = 0;
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple }
else if (player->kartstuff[k_itemamount] <= 0)
{
player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
}
else
{
switch (player->kartstuff[k_itemtype])
{ {
if (!player->kartstuff[k_invincibilitytimer]) case KITEM_SNEAKER:
{ if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO)
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH);
P_SetTarget(&overlay->target, player->mo);
overlay->destscale = player->mo->scale;
P_SetScale(overlay, player->mo->scale);
}
player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds
P_RestoreMusic(player);
if (!P_IsLocalPlayer(player))
S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc));
K_PlayPowerGloatSound(player->mo);
player->kartstuff[k_itemamount]--;
}
break;
case KITEM_BANANA:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
INT32 moloop;
mobj_t *mo;
mobj_t *prev = player->mo;
//K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s254);
for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
{
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BANANA_SHIELD);
if (!mo)
{ {
player->kartstuff[k_itemamount] = moloop; K_DoSneaker(player, 1);
break; K_PlayBoostTaunt(player->mo);
player->kartstuff[k_itemamount]--;
} }
mo->flags |= MF_NOCLIPTHING; break;
mo->threshold = 10; case KITEM_ROCKETSNEAKER:
mo->movecount = player->kartstuff[k_itemamount]; if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
mo->movedir = moloop+1; && player->kartstuff[k_rocketsneakertimer] == 0)
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&mo->hprev, prev);
P_SetTarget(&prev->hnext, mo);
prev = mo;
}
}
else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown
{
K_ThrowKartItem(player, false, MT_BANANA, -1, 0);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, false);
}
break;
case KITEM_EGGMAN:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
mobj_t *mo;
player->kartstuff[k_itemamount]--;
player->kartstuff[k_eggmanheld] = 1;
S_StartSound(player->mo, sfx_s254);
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD);
if (mo)
{
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = 1;
mo->movedir = 1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&player->mo->hnext, mo);
}
}
break;
case KITEM_ORBINAUT:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
angle_t newangle;
INT32 moloop;
mobj_t *mo = NULL;
mobj_t *prev = player->mo;
//K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s3k3a);
for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
{
newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90;
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD);
if (!mo)
{ {
player->kartstuff[k_itemamount] = moloop; INT32 moloop;
break; mobj_t *mo = NULL;
mobj_t *prev = player->mo;
K_PlayBoostTaunt(player->mo);
//player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s3k3a);
//K_DoSneaker(player, 2);
player->kartstuff[k_rocketsneakertimer] = (itemtime*3);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, true);
for (moloop = 0; moloop < 2; moloop++)
{
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER);
mo->flags |= MF_NOCLIPTHING;
mo->angle = player->mo->angle;
mo->threshold = 10;
mo->movecount = moloop%2;
mo->movedir = mo->lastlook = moloop+1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&mo->hprev, prev);
P_SetTarget(&prev->hnext, mo);
prev = mo;
}
} }
mo->flags |= MF_NOCLIPTHING; break;
mo->angle = newangle; case KITEM_INVINCIBILITY:
mo->threshold = 10; if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple
mo->movecount = player->kartstuff[k_itemamount];
mo->movedir = mo->lastlook = moloop+1;
mo->color = player->skincolor;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&mo->hprev, prev);
P_SetTarget(&prev->hnext, mo);
prev = mo;
}
}
else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown
{
K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, false);
}
break;
case KITEM_JAWZ:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
angle_t newangle;
INT32 moloop;
mobj_t *mo = NULL;
mobj_t *prev = player->mo;
//K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s3k3a);
for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
{
newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90;
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD);
if (!mo)
{ {
player->kartstuff[k_itemamount] = moloop; if (!player->kartstuff[k_invincibilitytimer])
break; {
mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH);
P_SetTarget(&overlay->target, player->mo);
overlay->destscale = player->mo->scale;
P_SetScale(overlay, player->mo->scale);
}
player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds
P_RestoreMusic(player);
if (!P_IsLocalPlayer(player))
S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc));
K_PlayPowerGloatSound(player->mo);
player->kartstuff[k_itemamount]--;
} }
mo->flags |= MF_NOCLIPTHING; break;
mo->angle = newangle; case KITEM_BANANA:
mo->threshold = 10; if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
mo->movecount = player->kartstuff[k_itemamount]; {
mo->movedir = mo->lastlook = moloop+1; INT32 moloop;
P_SetTarget(&mo->target, player->mo); mobj_t *mo;
P_SetTarget(&mo->hprev, prev); mobj_t *prev = player->mo;
P_SetTarget(&prev->hnext, mo);
prev = mo; //K_PlayAttackTaunt(player->mo);
} player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s254);
for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
{
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BANANA_SHIELD);
if (!mo)
{
player->kartstuff[k_itemamount] = moloop;
break;
}
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = player->kartstuff[k_itemamount];
mo->movedir = moloop+1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&mo->hprev, prev);
P_SetTarget(&prev->hnext, mo);
prev = mo;
}
}
else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown
{
K_ThrowKartItem(player, false, MT_BANANA, -1, 0);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, false);
}
break;
case KITEM_EGGMAN:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
mobj_t *mo;
player->kartstuff[k_itemamount]--;
player->kartstuff[k_eggmanheld] = 1;
S_StartSound(player->mo, sfx_s254);
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD);
if (mo)
{
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = 1;
mo->movedir = 1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&player->mo->hnext, mo);
}
}
break;
case KITEM_ORBINAUT:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
angle_t newangle;
INT32 moloop;
mobj_t *mo = NULL;
mobj_t *prev = player->mo;
//K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s3k3a);
for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
{
newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90;
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD);
if (!mo)
{
player->kartstuff[k_itemamount] = moloop;
break;
}
mo->flags |= MF_NOCLIPTHING;
mo->angle = newangle;
mo->threshold = 10;
mo->movecount = player->kartstuff[k_itemamount];
mo->movedir = mo->lastlook = moloop+1;
mo->color = player->skincolor;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&mo->hprev, prev);
P_SetTarget(&prev->hnext, mo);
prev = mo;
}
}
else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown
{
K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, false);
}
break;
case KITEM_JAWZ:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
angle_t newangle;
INT32 moloop;
mobj_t *mo = NULL;
mobj_t *prev = player->mo;
//K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s3k3a);
for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
{
newangle = (player->mo->angle + ANGLE_157h) + FixedAngle(((360 / player->kartstuff[k_itemamount]) * moloop) << FRACBITS) + ANGLE_90;
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD);
if (!mo)
{
player->kartstuff[k_itemamount] = moloop;
break;
}
mo->flags |= MF_NOCLIPTHING;
mo->angle = newangle;
mo->threshold = 10;
mo->movecount = player->kartstuff[k_itemamount];
mo->movedir = mo->lastlook = moloop+1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&mo->hprev, prev);
P_SetTarget(&prev->hnext, mo);
prev = mo;
}
}
else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Jawz thrown
{
if (player->kartstuff[k_throwdir] == 1 || player->kartstuff[k_throwdir] == 0)
K_ThrowKartItem(player, true, MT_JAWZ, 1, 0);
else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in
K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, false);
}
break;
case KITEM_MINE:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
mobj_t *mo;
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s254);
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SSMINE_SHIELD);
if (mo)
{
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = 1;
mo->movedir = 1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&player->mo->hnext, mo);
}
}
else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld])
{
K_ThrowKartItem(player, false, MT_SSMINE, 1, 1);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
player->kartstuff[k_itemheld] = 0;
K_UpdateHnextList(player, true);
}
break;
case KITEM_BALLHOG:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->kartstuff[k_itemamount]--;
K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0);
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_SPB:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->kartstuff[k_itemamount]--;
K_ThrowKartItem(player, true, MT_SPB, 1, 0);
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_GROW:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
&& player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage
{
K_PlayPowerGloatSound(player->mo);
player->mo->scalespeed = mapobjectscale/TICRATE;
player->mo->destscale = (3*mapobjectscale)/2;
if (cv_kartdebugshrink.value && !modeattacking && !player->bot)
player->mo->destscale = (6*player->mo->destscale)/8;
player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds
P_RestoreMusic(player);
if (!P_IsLocalPlayer(player))
S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow));
S_StartSound(player->mo, sfx_kc5a);
player->kartstuff[k_itemamount]--;
}
break;
case KITEM_SHRINK:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
K_DoShrink(player);
player->kartstuff[k_itemamount]--;
K_PlayPowerGloatSound(player->mo);
}
break;
case KITEM_THUNDERSHIELD:
if (player->kartstuff[k_curshield] != 1)
{
mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD);
P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2));
P_SetTarget(&shield->target, player->mo);
S_StartSound(shield, sfx_s3k41);
player->kartstuff[k_curshield] = 1;
}
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
K_DoThunderShield(player);
player->kartstuff[k_itemamount]--;
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_HYUDORO:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->kartstuff[k_itemamount]--;
K_DoHyudoroSteal(player); // yes. yes they do.
}
break;
case KITEM_POGOSPRING:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
&& !player->kartstuff[k_pogospring])
{
K_PlayBoostTaunt(player->mo);
K_DoPogoSpring(player->mo, 32<<FRACBITS, 2);
player->kartstuff[k_pogospring] = 1;
player->kartstuff[k_itemamount]--;
}
break;
case KITEM_SUPERRING:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->kartstuff[k_superring] += (10*3);
player->kartstuff[k_itemamount]--;
}
break;
case KITEM_KITCHENSINK:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
mobj_t *mo;
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s254);
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SINK_SHIELD);
if (mo)
{
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = 1;
mo->movedir = 1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&player->mo->hnext, mo);
}
}
else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Sink thrown
{
K_ThrowKartItem(player, false, MT_SINK, 1, 2);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
player->kartstuff[k_itemheld] = 0;
K_UpdateHnextList(player, true);
}
break;
case KITEM_SAD:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
&& !player->kartstuff[k_sadtimer])
{
player->kartstuff[k_sadtimer] = stealtime;
player->kartstuff[k_itemamount]--;
}
break;
default:
break;
} }
else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Jawz thrown }
{
if (player->kartstuff[k_throwdir] == 1 || player->kartstuff[k_throwdir] == 0)
K_ThrowKartItem(player, true, MT_JAWZ, 1, 0);
else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in
K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
K_UpdateHnextList(player, false);
}
break;
case KITEM_MINE:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
mobj_t *mo;
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s254);
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SSMINE_SHIELD);
if (mo)
{
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = 1;
mo->movedir = 1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&player->mo->hnext, mo);
}
}
else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld])
{
K_ThrowKartItem(player, false, MT_SSMINE, 1, 1);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
player->kartstuff[k_itemheld] = 0;
K_UpdateHnextList(player, true);
}
break;
case KITEM_BALLHOG:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->kartstuff[k_itemamount]--;
K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0);
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_SPB:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->kartstuff[k_itemamount]--;
K_ThrowKartItem(player, true, MT_SPB, 1, 0);
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_GROW:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
&& player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage
{
K_PlayPowerGloatSound(player->mo);
player->mo->scalespeed = mapobjectscale/TICRATE;
player->mo->destscale = (3*mapobjectscale)/2;
if (cv_kartdebugshrink.value && !modeattacking && !player->bot)
player->mo->destscale = (6*player->mo->destscale)/8;
player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds
P_RestoreMusic(player);
if (!P_IsLocalPlayer(player))
S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow));
S_StartSound(player->mo, sfx_kc5a);
player->kartstuff[k_itemamount]--;
}
break;
case KITEM_SHRINK:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
K_DoShrink(player);
player->kartstuff[k_itemamount]--;
K_PlayPowerGloatSound(player->mo);
}
break;
case KITEM_THUNDERSHIELD:
if (player->kartstuff[k_curshield] != 1)
{
mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD);
P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2));
P_SetTarget(&shield->target, player->mo);
S_StartSound(shield, sfx_s3k41);
player->kartstuff[k_curshield] = 1;
}
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
K_DoThunderShield(player);
player->kartstuff[k_itemamount]--;
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_HYUDORO:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
player->kartstuff[k_itemamount]--;
K_DoHyudoroSteal(player); // yes. yes they do.
}
break;
case KITEM_POGOSPRING:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
&& !player->kartstuff[k_pogospring])
{
K_PlayBoostTaunt(player->mo);
K_DoPogoSpring(player->mo, 32<<FRACBITS, 2);
player->kartstuff[k_pogospring] = 1;
player->kartstuff[k_itemamount]--;
}
break;
case KITEM_KITCHENSINK:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
mobj_t *mo;
player->kartstuff[k_itemheld] = 1;
S_StartSound(player->mo, sfx_s254);
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SINK_SHIELD);
if (mo)
{
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = 1;
mo->movedir = 1;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&player->mo->hnext, mo);
}
}
else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Sink thrown
{
K_ThrowKartItem(player, false, MT_SINK, 1, 2);
K_PlayAttackTaunt(player->mo);
player->kartstuff[k_itemamount]--;
player->kartstuff[k_itemheld] = 0;
K_UpdateHnextList(player, true);
}
break;
case KITEM_SAD:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
&& !player->kartstuff[k_sadtimer])
{
player->kartstuff[k_sadtimer] = stealtime;
player->kartstuff[k_itemamount]--;
}
break;
default:
break;
} }
} }
// Prevent ring misfire // Prevent ring misfire
if (player->kartstuff[k_itemtype] != KITEM_NONE) if (!ATTACK_IS_DOWN)
player->kartstuff[k_ringdelay] = 15; {
if (player->kartstuff[k_itemtype] == KITEM_NONE
&& !(player->kartstuff[k_growshrinktimer]
|| player->kartstuff[k_rocketsneakertimer]
|| player->kartstuff[k_eggmanheld]
|| player->kartstuff[k_eggmanexplode]
|| player->kartstuff[k_rocketsneakertimer]
|| player->kartstuff[k_growshrinktimer]))
player->kartstuff[k_userings] = 1;
else
player->kartstuff[k_userings] = 0;
}
// No more! // No more!
if (!player->kartstuff[k_itemamount]) if (!player->kartstuff[k_itemamount])
@ -6732,8 +6773,6 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
{ {
switch (item) switch (item)
{ {
case KITEM_SUPERRING:
return (tiny ? "K_ISRING" : "K_ITRING");
case KITEM_SNEAKER: case KITEM_SNEAKER:
case KRITEM_TRIPLESNEAKER: case KRITEM_TRIPLESNEAKER:
return (tiny ? "K_ISSHOE" : "K_ITSHOE"); return (tiny ? "K_ISSHOE" : "K_ITSHOE");
@ -6768,6 +6807,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
return (tiny ? "K_ISHYUD" : "K_ITHYUD"); return (tiny ? "K_ISHYUD" : "K_ITHYUD");
case KITEM_POGOSPRING: case KITEM_POGOSPRING:
return (tiny ? "K_ISPOGO" : "K_ITPOGO"); return (tiny ? "K_ISPOGO" : "K_ITPOGO");
case KITEM_SUPERRING:
return (tiny ? "K_ISRING" : "K_ITRING");
case KITEM_KITCHENSINK: case KITEM_KITCHENSINK:
return (tiny ? "K_ISSINK" : "K_ITSINK"); return (tiny ? "K_ISSINK" : "K_ITSINK");
case KRITEM_TRIPLEORBINAUT: case KRITEM_TRIPLEORBINAUT:
@ -7124,9 +7165,6 @@ static void K_drawKartItem(void)
switch(stplyr->kartstuff[k_itemtype]) switch(stplyr->kartstuff[k_itemtype])
{ {
case KITEM_SUPERRING:
localpatch = kp_superring[offset];
break;
case KITEM_SNEAKER: case KITEM_SNEAKER:
localpatch = kp_sneaker[offset]; localpatch = kp_sneaker[offset];
break; break;
@ -7175,6 +7213,9 @@ static void K_drawKartItem(void)
case KITEM_POGOSPRING: case KITEM_POGOSPRING:
localpatch = kp_pogospring[offset]; localpatch = kp_pogospring[offset];
break; break;
case KITEM_SUPERRING:
localpatch = kp_superring[offset];
break;
case KITEM_KITCHENSINK: case KITEM_KITCHENSINK:
localpatch = kp_kitchensink[offset]; localpatch = kp_kitchensink[offset];
break; break;
@ -7875,39 +7916,39 @@ static void K_drawKartRingsAndLives(void)
INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT); INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT);
UINT8 firstnum = ((abs(stplyr->kartstuff[k_rings]) / 10) % 10); UINT8 firstnum = ((abs(stplyr->kartstuff[k_rings]) / 10) % 10);
UINT8 secondnum = (abs(stplyr->kartstuff[k_rings]) % 10); UINT8 secondnum = (abs(stplyr->kartstuff[k_rings]) % 10);
UINT8 *debtmap = NULL; UINT8 *ringmap = NULL;
if (stplyr->kartstuff[k_rings] <= 0 && (leveltime/5 & 1)) // Rings
debtmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE); if (stplyr->kartstuff[k_rings] <= 0 && (leveltime/5 & 1)) // In debt
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
else if (stplyr->kartstuff[k_rings] >= 20) // Maxed out
ringmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE);
if (netgame) if (netgame)
V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[1]); V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[1]);
else else
V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[0]); V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[0]);
V_DrawMappedPatch(LAPS_X+7, LAPS_Y-16, V_HUDTRANS|splitflags, kp_ring[0], debtmap); V_DrawMappedPatch(LAPS_X+7, LAPS_Y-16, V_HUDTRANS|splitflags, kp_ring[0], (stplyr->kartstuff[k_rings] <= 0 ? ringmap : NULL)); // Don't do maxed out gold mapping
if (stplyr->kartstuff[k_rings] < 0) if (stplyr->kartstuff[k_rings] < 0) // Draw the minus for ring debt
{ {
V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringdebtminus, debtmap); V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringdebtminus, ringmap);
V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], debtmap); V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], ringmap);
V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], debtmap); V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], ringmap);
} }
else else
{ {
V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], debtmap); V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], ringmap);
V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], debtmap); V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], ringmap);
} }
// Lives
if (!netgame) if (!netgame)
{ {
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE); UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
if (stplyr->mo->colorized)
colormap = R_GetTranslationColormap(TC_RAINBOW, stplyr->mo->color, GTC_CACHE);
V_DrawMappedPatch(LAPS_X+46, LAPS_Y-16, V_HUDTRANS|splitflags, facerankprefix[stplyr->skin], colormap); V_DrawMappedPatch(LAPS_X+46, LAPS_Y-16, V_HUDTRANS|splitflags, facerankprefix[stplyr->skin], colormap);
V_DrawScaledPatch(LAPS_X+63, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[(stplyr->lives % 10)]); V_DrawScaledPatch(LAPS_X+63, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[(stplyr->lives % 10)]); // make sure this doesn't overflow
} }
} }

View file

@ -747,20 +747,24 @@ static boolean P_LookForShield(mobj_t *actor)
if (player->health <= 0 || !player->mo) if (player->health <= 0 || !player->mo)
continue; // dead continue; // dead
if (!P_CheckSight(actor, player->mo))
continue; // can't see
//When in CTF, don't pull rings that you cannot pick up. //When in CTF, don't pull rings that you cannot pick up.
if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) || if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) ||
(actor->type == MT_BLUETEAMRING && player->ctfteam != 2)) (actor->type == MT_BLUETEAMRING && player->ctfteam != 2))
continue; continue;
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT if ((player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) && ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20)
&& (P_AproxDistance(P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y), actor->z-player->mo->z) < FixedMul(RING_DIST/4, player->mo->scale))) && P_AproxDistance(actor->x-player->mo->x, actor->y-player->mo->y) < FixedMul(RING_DIST/4, player->mo->scale)
&& P_AproxDistance(0, actor->z-player->mo->z) < FixedMul(RING_DIST/8, player->mo->scale))
{ {
P_SetTarget(&actor->tracer, player->mo); P_SetTarget(&actor->tracer, player->mo);
return true; return true;
} }
} }
//return false; return false;
} }
#ifdef WEIGHTEDRECYCLER #ifdef WEIGHTEDRECYCLER
@ -3654,6 +3658,7 @@ void A_AttractChase(mobj_t *actor)
if (actor->extravalue1 >= 16) if (actor->extravalue1 >= 16)
{ {
P_GivePlayerRings(actor->target->player, 1); P_GivePlayerRings(actor->target->player, 1);
actor->target->player->kartstuff[k_pickuprings]--;
if (actor->cvmem) // caching if (actor->cvmem) // caching
S_StartSound(actor->target, sfx_s1c5); S_StartSound(actor->target, sfx_s1c5);
else else
@ -3682,69 +3687,76 @@ void A_AttractChase(mobj_t *actor)
if (actor->threshold > 0) if (actor->threshold > 0)
actor->threshold--; actor->threshold--;
// spilled rings flicker before disappearing // spilled rings flicker before disappearing, and get capped to a certain speed
if (leveltime & 1 && actor->type == (mobjtype_t)actor->info->reactiontime && actor->fuse && actor->fuse < 2*TICRATE)
actor->flags2 |= MF2_DONTDRAW;
else
actor->flags2 &= ~MF2_DONTDRAW;
// Flung rings lose speed over time
if (actor->type == (mobjtype_t)actor->info->reactiontime) if (actor->type == (mobjtype_t)actor->info->reactiontime)
{ {
const fixed_t destspeed = FRACUNIT; const fixed_t maxspeed = 4<<FRACBITS;
fixed_t oldspeed = R_PointToDist2(0, 0, actor->momx, actor->momy); fixed_t oldspeed = R_PointToDist2(0, 0, actor->momx, actor->momy);
if (oldspeed > destspeed) if (oldspeed > maxspeed)
{ {
fixed_t newspeed = max(destspeed, oldspeed - (FRACUNIT / TICRATE)); fixed_t newspeed = max(maxspeed, oldspeed-FRACUNIT);
actor->momx = FixedMul(FixedDiv(actor->momx, oldspeed), newspeed); actor->momx = FixedMul(FixedDiv(actor->momx, oldspeed), newspeed);
actor->momy = FixedMul(FixedDiv(actor->momy, oldspeed), newspeed); actor->momy = FixedMul(FixedDiv(actor->momy, oldspeed), newspeed);
} }
if (actor->fuse && actor->fuse < 3*TICRATE && leveltime & 1)
actor->flags2 |= MF2_DONTDRAW;
else
actor->flags2 &= ~MF2_DONTDRAW;
} }
// Turn flingrings back into regular rings if attracted. if (actor->tracer && actor->tracer->player && actor->tracer->health
if (actor->tracer && actor->tracer->player && P_CheckSight(actor, actor->tracer)
&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT && actor->tracer->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD
&& actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) && (actor->tracer->player->kartstuff[k_rings]+actor->tracer->player->kartstuff[k_pickuprings]) < 20)
{ {
mobj_t *newring; fixed_t dist;
newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime); angle_t hang, vang;
newring->momx = actor->momx;
newring->momy = actor->momy; // If a flung ring gets attracted by a shield, change it into a normal ring.
newring->momz = actor->momz; if (actor->type == (mobjtype_t)actor->info->reactiontime)
P_RemoveMobj(actor); {
return; P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance);
P_RemoveMobj(actor);
return;
}
// Keep stuff from going down inside floors and junk
actor->flags &= ~MF_NOCLIPHEIGHT;
// Let attracted rings move through walls and such.
actor->flags |= MF_NOCLIP;
// flag to show it's been attracted once before
actor->cusval = 1;
// P_Attract is too "smart" for Kart; keep it simple, stupid!
dist = P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z);
hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
vang = R_PointToAngle2(actor->z , 0, actor->tracer->z, dist);
actor->momx -= actor->momx>>4, actor->momy -= actor->momy>>4, actor->momz -= actor->momz>>4;
actor->momx += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hang>>ANGLETOFINESHIFT), 2*actor->scale));
actor->momy += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINESINE(hang>>ANGLETOFINESHIFT), 2*actor->scale));
actor->momz += FixedMul(FINECOSINE(vang>>ANGLETOFINESHIFT), 2*actor->scale);
} }
else
P_LookForShield(actor); // Go find 'em, boy!
if (!actor->tracer
|| !actor->tracer->player
|| !actor->tracer->health
|| !P_CheckSight(actor, actor->tracer)) // You have to be able to SEE it...sorta
{ {
// Lost attracted rings don't through walls anymore. // Turn rings back into flung rings if lost
actor->flags &= ~MF_NOCLIP; if (actor->cusval && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
P_SetTarget(&actor->tracer, NULL); {
return; mobj_t *newring;
newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime);
P_InstaThrust(newring, P_RandomRange(0,7) * ANGLE_45, 2<<FRACBITS);
newring->momz = 5<<FRACBITS;
newring->fuse = 120*TICRATE;
P_RemoveMobj(actor);
return;
}
else
P_LookForShield(actor); // Go find 'em, boy!
} }
// If a FlingRing gets attracted by a shield, change it into a normal ring.
if (actor->type == (mobjtype_t)actor->info->reactiontime)
{
P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance);
P_RemoveMobj(actor);
return;
}
// Keep stuff from going down inside floors and junk
actor->flags &= ~MF_NOCLIPHEIGHT;
// Let attracted rings move through walls and such.
actor->flags |= MF_NOCLIP;
P_Attract(actor, actor->tracer, false);
} }
} }

View file

@ -697,14 +697,16 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return; return;
// Reached the cap, don't waste 'em! // Reached the cap, don't waste 'em!
if (player->kartstuff[k_rings] >= 20) if ((player->kartstuff[k_rings] + player->kartstuff[k_pickuprings]) >= 20)
return; return;
special->momx = special->momy = special->momz = 0; special->momx = special->momy = special->momz = 0;
// SRB2Kart
special->extravalue1 = 1; // Ring collect animation timer special->extravalue1 = 1; // Ring collect animation timer
special->angle = R_PointToAngle2(toucher->x, toucher->y, special->x, special->y); // animation angle special->angle = R_PointToAngle2(toucher->x, toucher->y, special->x, special->y); // animation angle
P_SetTarget(&special->target, toucher); // toucher for thinker P_SetTarget(&special->target, toucher); // toucher for thinker
player->kartstuff[k_pickuprings]++;
return; return;
case MT_COIN: case MT_COIN:
@ -3294,7 +3296,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
return; return;
// Cap the maximum loss automatically to 2 in ring debt // Cap the maximum loss automatically to 2 in ring debt
if (player->kartstuff[k_rings] < 0 && num_rings > 2) if (player->kartstuff[k_rings] <= 0 && num_rings > 2)
num_rings = 2; num_rings = 2;
P_GivePlayerRings(player, -num_rings); P_GivePlayerRings(player, -num_rings);
@ -3313,7 +3315,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType); mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType);
mo->threshold = 10; mo->threshold = 10;
mo->fuse = 15*TICRATE; mo->fuse = 120*TICRATE;
P_SetTarget(&mo->target, player->mo); P_SetTarget(&mo->target, player->mo);
mo->destscale = player->mo->scale; mo->destscale = player->mo->scale;

View file

@ -10729,6 +10729,8 @@ void P_PrecipitationEffects(void)
// //
void P_RespawnSpecials(void) void P_RespawnSpecials(void)
{ {
UINT8 p, pcount = 0;
tic_t time = 168*TICRATE;
fixed_t x, y, z; fixed_t x, y, z;
subsector_t *ss; subsector_t *ss;
mobj_t *mo = NULL; mobj_t *mo = NULL;
@ -10787,9 +10789,22 @@ void P_RespawnSpecials(void)
if (iquehead == iquetail) if (iquehead == iquetail)
return; return;
// wait time depends on player count
for (p = 0; p < MAXPLAYERS; p++)
{
if (!playeringame[p] || players[p].spectator)
pcount++;
}
if (pcount > 1)
time -= pcount * (8*TICRATE);
else if (pcount == 1) // No respawn when alone
return;
else
time = 30*TICRATE; // Respawn things in empty dedicated servers
// the first item in the queue is the first to respawn // the first item in the queue is the first to respawn
// wait at least 30 seconds if (leveltime - itemrespawntime[iquetail] < time)
if (leveltime - itemrespawntime[iquetail] < (tic_t)cv_itemrespawntime.value*TICRATE)
return; return;
mthing = itemrespawnque[iquetail]; mthing = itemrespawnque[iquetail];