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_NONE = 0,
KITEM_SUPERRING,
KITEM_SNEAKER,
KITEM_ROCKETSNEAKER,
KITEM_INVINCIBILITY,
@ -250,6 +249,7 @@ typedef enum
KITEM_THUNDERSHIELD,
KITEM_HYUDORO,
KITEM_POGOSPRING,
KITEM_SUPERRING,
KITEM_KITCHENSINK,
NUMKARTITEMS,
@ -298,6 +298,8 @@ typedef enum
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_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_ringboost, // Ring boost timer
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",
"STARTBOOST",
"RINGS",
"PICKUPRINGS",
"USERINGS",
"RINGDELAY",
"RINGBOOST",
"JMP",
@ -8943,7 +8945,6 @@ struct {
// kartitems_t
{"KITEM_SAD",KITEM_SAD}, // Actual items (can be set for k_itemtype)
{"KITEM_NONE",KITEM_NONE},
{"KITEM_SUPERRING",KITEM_SUPERRING},
{"KITEM_SNEAKER",KITEM_SNEAKER},
{"KITEM_ROCKETSNEAKER",KITEM_ROCKETSNEAKER},
{"KITEM_INVINCIBILITY",KITEM_INVINCIBILITY},
@ -8959,6 +8960,7 @@ struct {
{"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD},
{"KITEM_HYUDORO",KITEM_HYUDORO},
{"KITEM_POGOSPRING",KITEM_POGOSPRING},
{"KITEM_SUPERRING",KITEM_SUPERRING},
{"KITEM_KITCHENSINK",KITEM_KITCHENSINK},
{"NUMKARTITEMS",NUMKARTITEMS},
{"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:
// 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
if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*6)
&& spbplace == -1 && !indirectitemcooldown && !dontforcespb
@ -1148,6 +1166,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
player->kartstuff[k_roulettetype] = 0;
if (P_IsLocalPlayer(player))
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.
@ -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_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
{
@ -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_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
{
@ -1742,6 +1763,7 @@ void K_RespawnChecker(player_t *player)
player->mo->colorized = false;
player->kartstuff[k_dropdash] = 0;
player->kartstuff[k_respawn] = 0;
//P_PlayRinglossSound(player->mo);
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->angle = player->mo->angle; // animation angle
P_SetTarget(&ring->target, player->mo); // toucher for thinker
player->kartstuff[k_pickuprings]++;
if (player->kartstuff[k_superring] <= 3)
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)
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)
{
// 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);
}
}
// 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
{
switch (player->kartstuff[k_itemtype])
// Ring boosting
if (player->kartstuff[k_userings])
{
case KITEM_SUPERRING:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
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;
}
}
// 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);
player->kartstuff[k_itemamount]--;
K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0);
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)
{
K_DoSneaker(player, 1);
K_DoSneaker(player, 2);
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:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
&& player->kartstuff[k_rocketsneakertimer] == 0)
}
// Grow Canceling
else if (player->kartstuff[k_growshrinktimer] > 0)
{
if (cmd->buttons & BT_ATTACK)
{
INT32 moloop;
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;
}
player->kartstuff[k_growcancel]++;
if (player->kartstuff[k_growcancel] > 26)
K_RemoveGrowShrink(player);
}
break;
case KITEM_INVINCIBILITY:
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
player->kartstuff[k_growcancel] = 0;
}
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])
{
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)
case KITEM_SNEAKER:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO)
{
player->kartstuff[k_itemamount] = moloop;
break;
K_DoSneaker(player, 1);
K_PlayBoostTaunt(player->mo);
player->kartstuff[k_itemamount]--;
}
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)
break;
case KITEM_ROCKETSNEAKER:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
&& player->kartstuff[k_rocketsneakertimer] == 0)
{
player->kartstuff[k_itemamount] = moloop;
break;
INT32 moloop;
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;
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)
break;
case KITEM_INVINCIBILITY:
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
{
player->kartstuff[k_itemamount] = moloop;
break;
if (!player->kartstuff[k_invincibilitytimer])
{
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;
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;
}
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;
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
if (player->kartstuff[k_itemtype] != KITEM_NONE)
player->kartstuff[k_ringdelay] = 15;
if (!ATTACK_IS_DOWN)
{
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!
if (!player->kartstuff[k_itemamount])
@ -6732,8 +6773,6 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
{
switch (item)
{
case KITEM_SUPERRING:
return (tiny ? "K_ISRING" : "K_ITRING");
case KITEM_SNEAKER:
case KRITEM_TRIPLESNEAKER:
return (tiny ? "K_ISSHOE" : "K_ITSHOE");
@ -6768,6 +6807,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
return (tiny ? "K_ISHYUD" : "K_ITHYUD");
case KITEM_POGOSPRING:
return (tiny ? "K_ISPOGO" : "K_ITPOGO");
case KITEM_SUPERRING:
return (tiny ? "K_ISRING" : "K_ITRING");
case KITEM_KITCHENSINK:
return (tiny ? "K_ISSINK" : "K_ITSINK");
case KRITEM_TRIPLEORBINAUT:
@ -7124,9 +7165,6 @@ static void K_drawKartItem(void)
switch(stplyr->kartstuff[k_itemtype])
{
case KITEM_SUPERRING:
localpatch = kp_superring[offset];
break;
case KITEM_SNEAKER:
localpatch = kp_sneaker[offset];
break;
@ -7175,6 +7213,9 @@ static void K_drawKartItem(void)
case KITEM_POGOSPRING:
localpatch = kp_pogospring[offset];
break;
case KITEM_SUPERRING:
localpatch = kp_superring[offset];
break;
case KITEM_KITCHENSINK:
localpatch = kp_kitchensink[offset];
break;
@ -7875,39 +7916,39 @@ static void K_drawKartRingsAndLives(void)
INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT);
UINT8 firstnum = ((abs(stplyr->kartstuff[k_rings]) / 10) % 10);
UINT8 secondnum = (abs(stplyr->kartstuff[k_rings]) % 10);
UINT8 *debtmap = NULL;
UINT8 *ringmap = NULL;
if (stplyr->kartstuff[k_rings] <= 0 && (leveltime/5 & 1))
debtmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_CRIMSON, GTC_CACHE);
// Rings
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)
V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[1]);
else
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+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], debtmap);
V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], 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], ringmap);
V_DrawMappedPatch(LAPS_X+35, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], ringmap);
}
else
{
V_DrawMappedPatch(LAPS_X+23, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[firstnum], debtmap);
V_DrawMappedPatch(LAPS_X+29, LAPS_Y-11, V_HUDTRANS|splitflags, kp_facenum[secondnum], 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], ringmap);
}
// Lives
if (!netgame)
{
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE);
if (stplyr->mo->colorized)
colormap = R_GetTranslationColormap(TC_RAINBOW, stplyr->mo->color, GTC_CACHE);
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
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)
continue; // dead
if (!P_CheckSight(actor, player->mo))
continue; // can't see
//When in CTF, don't pull rings that you cannot pick up.
if ((actor->type == MT_REDTEAMRING && player->ctfteam != 1) ||
(actor->type == MT_BLUETEAMRING && player->ctfteam != 2))
continue;
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
&& (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)))
if ((player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) && ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20)
&& 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);
return true;
}
}
//return false;
return false;
}
#ifdef WEIGHTEDRECYCLER
@ -3654,6 +3658,7 @@ void A_AttractChase(mobj_t *actor)
if (actor->extravalue1 >= 16)
{
P_GivePlayerRings(actor->target->player, 1);
actor->target->player->kartstuff[k_pickuprings]--;
if (actor->cvmem) // caching
S_StartSound(actor->target, sfx_s1c5);
else
@ -3682,69 +3687,76 @@ void A_AttractChase(mobj_t *actor)
if (actor->threshold > 0)
actor->threshold--;
// spilled rings flicker before disappearing
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
// spilled rings flicker before disappearing, and get capped to a certain speed
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);
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->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->player->powers[pw_shield] & SH_NOSTACK) != SH_ATTRACT
&& actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
if (actor->tracer && actor->tracer->player && actor->tracer->health
&& P_CheckSight(actor, actor->tracer)
&& actor->tracer->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD
&& (actor->tracer->player->kartstuff[k_rings]+actor->tracer->player->kartstuff[k_pickuprings]) < 20)
{
mobj_t *newring;
newring = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->reactiontime);
newring->momx = actor->momx;
newring->momy = actor->momy;
newring->momz = actor->momz;
P_RemoveMobj(actor);
return;
fixed_t dist;
angle_t hang, vang;
// If a flung ring 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;
// 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);
}
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
else
{
// Lost attracted rings don't through walls anymore.
actor->flags &= ~MF_NOCLIP;
P_SetTarget(&actor->tracer, NULL);
return;
// Turn rings back into flung rings if lost
if (actor->cusval && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
{
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;
// Reached the cap, don't waste 'em!
if (player->kartstuff[k_rings] >= 20)
if ((player->kartstuff[k_rings] + player->kartstuff[k_pickuprings]) >= 20)
return;
special->momx = special->momy = special->momz = 0;
// SRB2Kart
special->extravalue1 = 1; // Ring collect animation timer
special->angle = R_PointToAngle2(toucher->x, toucher->y, special->x, special->y); // animation angle
P_SetTarget(&special->target, toucher); // toucher for thinker
player->kartstuff[k_pickuprings]++;
return;
case MT_COIN:
@ -3294,7 +3296,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
return;
// 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;
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->threshold = 10;
mo->fuse = 15*TICRATE;
mo->fuse = 120*TICRATE;
P_SetTarget(&mo->target, player->mo);
mo->destscale = player->mo->scale;

View file

@ -10729,6 +10729,8 @@ void P_PrecipitationEffects(void)
//
void P_RespawnSpecials(void)
{
UINT8 p, pcount = 0;
tic_t time = 168*TICRATE;
fixed_t x, y, z;
subsector_t *ss;
mobj_t *mo = NULL;
@ -10787,9 +10789,22 @@ void P_RespawnSpecials(void)
if (iquehead == iquetail)
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
// wait at least 30 seconds
if (leveltime - itemrespawntime[iquetail] < (tic_t)cv_itemrespawntime.value*TICRATE)
if (leveltime - itemrespawntime[iquetail] < time)
return;
mthing = itemrespawnque[iquetail];