Merge remote-tracking branch 'origin/master' into capsules

This commit is contained in:
lachablock 2021-06-14 12:20:53 +10:00
commit debfb41423
17 changed files with 742 additions and 624 deletions

View file

@ -232,6 +232,9 @@ typedef enum
khud_cardanimation, // Used to determine the position of some full-screen Battle Mode graphics
khud_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly
// Tricks
khud_trickcool,
NUMKARTHUD
} karthudtype_t;
@ -241,6 +244,7 @@ typedef enum
// CONSTANTS FOR TRICK PANELS
#define TRICKMOMZRAMP (30)
#define TRICKLAG (9)
#define TRICKDELAY (TICRATE/4)
#define TUMBLEBOUNCES 3
@ -450,9 +454,14 @@ typedef struct player_s
UINT8 jawztargetdelay; // (0 to 5) - Delay for Jawz target switching, to make it less twitchy
UINT8 trickpanel; // Trick panel state
UINT8 tricktime; // Increases while you're tricking. You can't input any trick until it's reached a certain threshold
fixed_t trickmomx;
fixed_t trickmomy;
fixed_t trickmomz;
fixed_t trickboostpower; // Save the rough speed multiplier. Used for upwards tricks.
UINT8 trickboostdecay; // used to know how long you've waited
UINT8 trickboost; // Trick boost. This one is weird and has variable speed. Dear god.
UINT32 roundscore; // battle score this round
UINT8 emeralds;

View file

@ -750,6 +750,8 @@ char sprnames[NUMSPRITES + 1][5] =
"SDDS", // Spindash dust
"SDWN", // Spindash wind
"TRCK",
"FLBM",
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later

View file

@ -1291,6 +1291,8 @@ typedef enum sprite
SPR_SDDS, // Spindash dust
SPR_SDWN, // Spindash wind
SPR_TRCK,
SPR_FLBM, // Finish line beam
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later

View file

@ -162,6 +162,8 @@ static patch_t *kp_cpu;
static patch_t *kp_nametagstem;
static patch_t *kp_trickcool[2];
void K_LoadKartHUDGraphics(void)
{
INT32 i, j;
@ -601,6 +603,9 @@ void K_LoadKartHUDGraphics(void)
kp_cpu = (patch_t *) W_CachePatchName("K_CPU", PU_HUDGFX);
kp_nametagstem = (patch_t *) W_CachePatchName("K_NAMEST", PU_HUDGFX);
kp_trickcool[0] = W_CachePatchName("K_COOL1", PU_HUDGFX);
kp_trickcool[1] = W_CachePatchName("K_COOL2", PU_HUDGFX);
}
// For the item toggle menu
@ -679,6 +684,9 @@ INT32 ITEM2_X, ITEM2_Y;
INT32 LAPS2_X, LAPS2_Y;
INT32 POSI2_X, POSI2_Y;
// trick "cool"
INT32 TCOOL_X, TCOOL_Y;
void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 dupy)
{
@ -982,6 +990,10 @@ static void K_initKartHUD(void)
WANT_X = BASEVIDWIDTH - 55; // 270
WANT_Y = BASEVIDHEIGHT- 71; // 176
// trick COOL
TCOOL_X = (BASEVIDWIDTH)/2;
TCOOL_Y = (BASEVIDHEIGHT)/2 -10;
if (r_splitscreen) // Splitscreen
{
ITEM_X = 5;
@ -1024,6 +1036,8 @@ static void K_initKartHUD(void)
MINI_X = (3*BASEVIDWIDTH/4);
MINI_Y = (3*BASEVIDHEIGHT/4);
TCOOL_X = (BASEVIDWIDTH)/4;
if (r_splitscreen > 2) // 4P-only
{
MINI_X = (BASEVIDWIDTH/2);
@ -3951,6 +3965,32 @@ static void K_drawLapStartAnim(void)
}
}
// stretch for "COOOOOL" popup.
// I can't be fucked to find out any math behind this so have a table lmao
static fixed_t stretch[6][2] = {
{FRACUNIT/4, FRACUNIT*4},
{FRACUNIT/2, FRACUNIT*2},
{FRACUNIT, FRACUNIT},
{FRACUNIT*4, FRACUNIT/2},
{FRACUNIT*8, FRACUNIT/4},
{FRACUNIT*4, FRACUNIT/2},
};
static void K_drawTrickCool(void)
{
tic_t timer = TICRATE - stplyr->karthud[khud_trickcool];
if (timer <= 6)
{
V_DrawStretchyFixedPatch(TCOOL_X<<FRACBITS, TCOOL_Y<<FRACBITS, stretch[timer-1][0], stretch[timer-1][1], V_HUDTRANS|V_SPLITSCREEN, kp_trickcool[splitscreen ? 1 : 0], NULL);
}
else if (leveltime & 1)
{
V_DrawFixedPatch(TCOOL_X<<FRACBITS, (TCOOL_Y<<FRACBITS) - (timer-10)*FRACUNIT/2, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_trickcool[splitscreen ? 1 : 0], NULL);
}
}
void K_drawKartFreePlay(void)
{
// no splitscreen support because it's not FREE PLAY if you have more than one player in-game
@ -4023,6 +4063,7 @@ static void K_drawDistributionDebugger(void)
kp_superring[1],
kp_kitchensink[1],
kp_sneaker[1],
kp_sneaker[1],
kp_banana[1],
kp_banana[1],
@ -4062,28 +4103,32 @@ static void K_drawDistributionDebugger(void)
}
}
if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items
pdis = (15 * pdis) / 14;
if (spbplace != -1 && stplyr->position == spbplace+1) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell
if (spbplace != -1 && stplyr->position == spbplace+1)
{
// SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell
pdis = (3 * pdis) / 2;
spbrush = true;
}
pdis = K_ScaleItemDistance(pdis, pingame, spbrush);
if (stplyr->bot && stplyr->botvars.rival)
{
// Rival has better odds :)
pdis = (15 * pdis) / 14;
}
pdis = ((28 + (8-pingame)) * pdis) / 28; // scale with player count
useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper, spbrush);
for (i = 1; i < NUMKARTRESULTS; i++)
{
const INT32 itemodds = K_KartGetItemOdds(useodds, i, 0, spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival));
INT32 itemodds = K_KartGetItemOdds(
useodds, i,
stplyr->distancetofinish,
0,
spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival)
);
if (itemodds <= 0)
continue;
@ -4105,6 +4150,9 @@ static void K_drawDistributionDebugger(void)
case KRITEM_DUALJAWZ:
amount = 2;
break;
case KRITEM_DUALSNEAKER:
amount = 2;
break;
default:
amount = 3;
break;
@ -4315,6 +4363,10 @@ void K_drawKartHUD(void)
K_drawLapStartAnim();
}
// trick panel cool trick
if (stplyr->karthud[khud_trickcool])
K_drawTrickCool();
if (modeattacking || freecam) // everything after here is MP and debug only
return;

View file

@ -348,7 +348,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
/*Mine*/ { 0, 2, 3, 1, 0, 0, 0, 0 }, // Mine
/*Land Mine*/ { 4, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
/*Ballhog*/ { 0, 0, 2, 1, 0, 0, 0, 0 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 1, 2, 3, 4, 2, 2, 0 }, // Self-Propelled Bomb
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
/*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow
/*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink
/*Thunder Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Thunder Shield
@ -400,6 +400,9 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
};
#define DISTVAR (2048) // Magic number distance for use with item roulette tiers
#define SPBSTARTDIST (5*DISTVAR) // Distance when SPB is forced onto 2nd place
#define SPBFORCEDIST (15*DISTVAR) // Distance when SPB is forced onto 2nd place
#define ENDDIST (12*DISTVAR) // Distance when the game stops giving you bananas
// Array of states to pick the starting point of the animation, based on the actual time left for invincibility.
static INT32 K_SparkleTrailStartStates[KART_NUMINVSPARKLESANIM][2] = {
@ -491,6 +494,57 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem)
}
}
fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush)
{
const UINT8 basePlayer = 8; // The player count we design most of the game around.
UINT8 playerCount = (spbrush ? 2 : numPlayers);
fixed_t playerScaling = 0;
// Then, it multiplies it further if the player count isn't equal to basePlayer.
// This is done to make low player count races more interesting and high player count rates more fair.
// (If you're in SPB mode and in 2nd place, it acts like it's a 1v1, so the catch-up game is not weakened.)
if (playerCount < basePlayer)
{
// Less than basePlayer: increase odds significantly.
// 2P: x2.5
playerScaling = (basePlayer - playerCount) * (FRACUNIT / 4);
}
else if (playerCount > basePlayer)
{
// More than basePlayer: reduce odds slightly.
// 16P: x0.75
playerScaling = (basePlayer - playerCount) * (FRACUNIT / 32);
}
return playerScaling;
}
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush)
{
if (mapobjectscale != FRACUNIT)
{
// Bring back to normal scale.
distance = FixedDiv(distance * FRACUNIT, mapobjectscale) / FRACUNIT;
}
if (franticitems == true)
{
// Frantic items pretends everyone's farther apart, for crazier items.
distance = (15 * distance) / 14;
}
if (numPlayers > 0)
{
// Items get crazier with the fewer players that you have.
distance = FixedMul(
distance * FRACUNIT,
FRACUNIT + (K_ItemOddsScale(numPlayers, spbrush) / 2)
) / FRACUNIT;
}
return distance;
}
/** \brief Item Roulette for Kart
\param player player object passed from P_KartPlayerThink
@ -498,13 +552,26 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem)
\return void
*/
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush, boolean bot, boolean rival)
INT32 K_KartGetItemOdds(
UINT8 pos, SINT8 item,
UINT32 ourDist,
fixed_t mashed,
boolean spbrush, boolean bot, boolean rival)
{
INT32 newodds;
INT32 i;
UINT8 pingame = 0, pexiting = 0;
SINT8 first = -1, second = -1;
INT32 secondist = 0;
UINT32 firstDist = UINT32_MAX;
UINT32 secondToFirst = UINT32_MAX;
boolean powerItem = false;
boolean cooldownOnStart = false;
boolean indirectItem = false;
boolean notNearEnd = false;
INT32 shieldtype = KSHIELD_NONE;
I_Assert(item > KITEM_NONE); // too many off by one scenarioes.
@ -513,6 +580,24 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush,
if (!KartItemCVars[item-1]->value && !modeattacking)
return 0;
/*
if (bot)
{
// TODO: Item use on bots should all be passed-in functions.
// Instead of manually inserting these, it should return 0
// for any items without an item use function supplied
switch (item)
{
case KITEM_SNEAKER:
break;
default:
return 0;
}
}
*/
(void)bot;
if (gametype == GT_BATTLE)
{
I_Assert(pos < 6); // DO NOT allow positions past the bounds of the table
@ -557,140 +642,149 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush,
if (first != -1 && second != -1) // calculate 2nd's distance from 1st, for SPB
{
secondist = players[second].distancetofinish - players[first].distancetofinish;
if (franticitems)
secondist = (15 * secondist) / 14;
secondist = ((28 + (8-pingame)) * secondist) / 28;
}
firstDist = players[first].distancetofinish;
// POWERITEMODDS handles all of the "frantic item" related functionality, for all of our powerful items.
// First, it multiplies it by 2 if franticitems is true; easy-peasy.
// Next, it multiplies it again if it's in SPB mode and 2nd needs to apply pressure to 1st.
// Then, it multiplies it further if the player count isn't equal to 8.
// This is done to make low player count races more interesting and high player count rates more fair.
// (2P normal would be about halfway between 8P normal and 8P frantic.)
// (This scaling is not done for SPB Rush, so that catchup strength is not weakened.)
// Lastly, it *divides* it by your mashed value, which was determined in K_KartItemRoulette, for lesser items needed in a pinch.
#define PLAYERSCALING (8 - (spbrush ? 2 : pingame))
#define POWERITEMODDS(odds) {\
if (franticitems) \
odds *= 2; \
if (rival) \
odds *= 2; \
odds = FixedMul(odds * FRACUNIT, FRACUNIT + ((PLAYERSCALING * FRACUNIT) / 25)) / FRACUNIT; \
if (mashed > 0) \
odds = FixedDiv(odds * FRACUNIT, FRACUNIT + mashed) / FRACUNIT; \
}
#define COOLDOWNONSTART (leveltime < (30*TICRATE)+starttime)
/*
if (bot)
{
// TODO: Item use on bots should all be passed-in functions.
// Instead of manually inserting these, it should return 0
// for any items without an item use function supplied
switch (item)
if (mapobjectscale != FRACUNIT)
{
case KITEM_SNEAKER:
case KITEM_ROCKETSNEAKER:
case KITEM_INVINCIBILITY:
case KITEM_BANANA:
case KITEM_EGGMAN:
case KITEM_ORBINAUT:
case KITEM_JAWZ:
case KITEM_MINE:
case KITEM_LANDMINE:
case KITEM_BALLHOG:
case KITEM_SPB:
case KITEM_GROW:
case KITEM_SHRINK:
case KITEM_HYUDORO:
case KITEM_SUPERRING:
case KITEM_THUNDERSHIELD:
case KITEM_BUBBLESHIELD:
case KITEM_FLAMESHIELD:
case KRITEM_DUALSNEAKER:
case KRITEM_TRIPLESNEAKER:
case KRITEM_TRIPLEBANANA:
case KRITEM_TENFOLDBANANA:
case KRITEM_TRIPLEORBINAUT:
case KRITEM_QUADORBINAUT:
case KRITEM_DUALJAWZ:
break;
default:
return 0;
firstDist = FixedDiv(firstDist * FRACUNIT, mapobjectscale) / FRACUNIT;
}
secondToFirst = K_ScaleItemDistance(
players[second].distancetofinish - players[first].distancetofinish,
pingame, spbrush
);
}
*/
(void)bot;
switch (item)
{
case KITEM_BANANA:
case KITEM_EGGMAN:
case KITEM_SUPERRING:
notNearEnd = true;
break;
case KITEM_ROCKETSNEAKER:
case KITEM_JAWZ:
case KITEM_LANDMINE:
case KITEM_BALLHOG:
case KRITEM_TRIPLESNEAKER:
case KRITEM_TRIPLEBANANA:
case KRITEM_TENFOLDBANANA:
case KRITEM_TRIPLEORBINAUT:
case KRITEM_QUADORBINAUT:
case KRITEM_DUALJAWZ:
POWERITEMODDS(newodds);
powerItem = true;
break;
case KRITEM_TRIPLEBANANA:
case KRITEM_TENFOLDBANANA:
powerItem = true;
notNearEnd = true;
break;
case KITEM_INVINCIBILITY:
case KITEM_MINE:
case KITEM_GROW:
case KITEM_BUBBLESHIELD:
case KITEM_FLAMESHIELD:
if (COOLDOWNONSTART)
newodds = 0;
else
POWERITEMODDS(newodds);
cooldownOnStart = true;
powerItem = true;
break;
case KITEM_SPB:
if ((indirectitemcooldown > 0) || COOLDOWNONSTART
|| (first != -1 && players[first].distancetofinish < 8*DISTVAR)) // No SPB near the end of the race
cooldownOnStart = true;
indirectItem = true;
notNearEnd = true;
if (firstDist < ENDDIST) // No SPB near the end of the race
{
newodds = 0;
}
else
{
INT32 multiplier = (secondist - (5*DISTVAR)) / DISTVAR;
const INT32 distFromStart = max(0, secondToFirst - SPBSTARTDIST);
const INT32 distRange = SPBFORCEDIST - SPBSTARTDIST;
const INT32 mulMax = 3;
INT32 multiplier = (distFromStart * mulMax) / distRange;
if (multiplier < 0)
multiplier = 0;
if (multiplier > 3)
multiplier = 3;
if (multiplier > mulMax)
multiplier = mulMax;
newodds *= multiplier;
}
break;
case KITEM_SHRINK:
if ((indirectitemcooldown > 0) || COOLDOWNONSTART || (pingame-1 <= pexiting))
cooldownOnStart = true;
powerItem = true;
indirectItem = true;
notNearEnd = true;
if (pingame-1 <= pexiting)
newodds = 0;
else
POWERITEMODDS(newodds);
break;
case KITEM_THUNDERSHIELD:
if (spbplace != -1 || COOLDOWNONSTART)
cooldownOnStart = true;
powerItem = true;
if (spbplace != -1)
newodds = 0;
else
POWERITEMODDS(newodds);
break;
case KITEM_HYUDORO:
if ((hyubgone > 0) || COOLDOWNONSTART)
cooldownOnStart = true;
notNearEnd = true;
if (hyubgone > 0)
newodds = 0;
break;
default:
break;
}
#undef POWERITEMODDS
if (newodds == 0)
{
// Nothing else we want to do with odds matters at this point :p
return newodds;
}
if ((indirectItem == true) && (indirectitemcooldown > 0))
{
// Too many items that act indirectly in a match can feel kind of bad.
newodds = 0;
}
else if ((cooldownOnStart == true) && (leveltime < (30*TICRATE)+starttime))
{
// This item should not appear at the beginning of a race. (Usually really powerful crowd-breaking items)
newodds = 0;
}
else if ((notNearEnd == true) && (ourDist < ENDDIST))
{
// This item should not appear at the end of a race. (Usually trap items that lose their effectiveness)
newodds = 0;
}
else if (powerItem == true)
{
// This item is a "power item". This activates "frantic item" toggle related functionality.
fixed_t fracOdds = newodds * FRACUNIT;
if (franticitems == true)
{
// First, power items multiply their odds by 2 if frantic items are on; easy-peasy.
fracOdds *= 2;
}
if (rival == true)
{
// The Rival bot gets frantic-like items, also :p
fracOdds *= 2;
}
fracOdds = FixedMul(fracOdds, FRACUNIT + K_ItemOddsScale(pingame, spbrush));
if (mashed > 0)
{
// Lastly, it *divides* it based on your mashed value, so that power items are less likely when you mash.
fracOdds = FixedDiv(fracOdds, FRACUNIT + mashed);
}
newodds = fracOdds / FRACUNIT;
}
return newodds;
}
@ -721,7 +815,12 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum
for (j = 1; j < NUMKARTRESULTS; j++)
{
if (K_KartGetItemOdds(i, j, mashed, spbrush, player->bot, (player->bot && player->botvars.rival)) > 0)
if (K_KartGetItemOdds(
i, j,
player->distancetofinish,
mashed,
spbrush, player->bot, (player->bot && player->botvars.rival)
) > 0)
{
available = true;
break;
@ -872,28 +971,21 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
}
}
if (mapobjectscale != FRACUNIT)
pdis = FixedDiv(pdis * FRACUNIT, mapobjectscale) / FRACUNIT;
if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items
{
pdis = (15 * pdis) / 14;
}
if (spbplace != -1 && player->position == spbplace+1) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell
if (spbplace != -1 && player->position == spbplace+1)
{
// SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell
pdis = (3 * pdis) / 2;
spbrush = true;
}
pdis = K_ScaleItemDistance(pdis, pingame, spbrush);
if (player->bot && player->botvars.rival)
{
// Rival has better odds :)
pdis = (15 * pdis) / 14;
}
pdis = ((28 + (8-pingame)) * pdis) / 28; // scale with player count
// SPECIAL CASE No. 1:
// Fake Eggman items
if (player->roulettetype == 2)
@ -994,17 +1086,17 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
// SPECIAL CASE No. 5:
// Force SPB onto 2nd if they get too far behind
if ((gametyperules & GTR_CIRCUIT) && player->position == 2 && pdis > (DISTVAR*8)
if ((gametyperules & GTR_CIRCUIT) && player->position == 2 && pdis > SPBFORCEDIST
&& spbplace == -1 && !indirectitemcooldown && !dontforcespb
&& cv_selfpropelledbomb.value)
{
K_KartGetItemResult(player, KITEM_SPB);
player->karthud[khud_itemblink] = TICRATE;
player->karthud[khud_itemblinkmode] = (mashed ? 1 : 0);
player->karthud[khud_itemblinkmode] = 2;
player->itemroulette = 0;
player->roulettetype = 0;
if (P_IsDisplayPlayer(player))
S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf));
S_StartSound(NULL, sfx_itrolk);
return;
}
@ -1017,7 +1109,14 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
useodds = K_FindUseodds(player, mashed, pdis, bestbumper, spbrush);
for (i = 1; i < NUMKARTRESULTS; i++)
spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(useodds, i, mashed, spbrush, player->bot, (player->bot && player->botvars.rival)));
{
spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(
useodds, i,
player->distancetofinish,
mashed,
spbrush, player->bot, (player->bot && player->botvars.rival))
);
}
// Award the player whatever power is rolled
if (totalspawnchance > 0)
@ -2672,6 +2771,11 @@ static void K_GetKartBoostPower(player_t *player)
}
}
if (player->trickboost) // Trick pannel up-boost
{
ADDBOOST(player->trickboostpower, 5*FRACUNIT, 0); // <trickboostpower>% speed, 500% accel, 0% handling
}
if (player->ringboost) // Ring Boost
{
ADDBOOST(FRACUNIT/5, 4*FRACUNIT, 0); // + 20% top speed, + 400% acceleration, +0% handling
@ -4994,7 +5098,10 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound)
thrust = FixedMul(thrust, 9*FRACUNIT/8);
}
mo->player->trickmomx = mo->player->trickmomy = mo->player->trickmomz = 0; // Reset post-hitlag momentums.
mo->player->trickmomx = mo->player->trickmomy = mo->player->trickmomz = mo->player->tricktime = 0; // Reset post-hitlag momentums and timer
// Setup the boost for potential upwards trick, at worse, make it your regular max speed. (boost = curr speed*1.25)
mo->player->trickboostpower = max(FixedDiv(mo->player->speed, K_GetKartSpeed(mo->player, false)) - FRACUNIT, 0)*125/100;
//CONS_Printf("Got boost: %d%\n", mo->player->trickboostpower*100 / FRACUNIT);
}
mo->momz = FixedMul(thrust, vscale);
@ -5291,7 +5398,15 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
useodds = amount;
for (i = 1; i < NUMKARTRESULTS; i++)
spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(useodds, i, 0, false, false, false));
{
spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(
useodds, i,
UINT32_MAX,
0,
false, false, false
)
);
}
if (totalspawnchance > 0)
{
@ -6217,6 +6332,9 @@ void K_KartPlayerHUDUpdate(player_t *player)
if (player->karthud[khud_tauntvoices])
player->karthud[khud_tauntvoices]--;
if (player->karthud[khud_trickcool])
player->karthud[khud_trickcool]--;
if (!(player->pflags & PF_FAULT))
player->karthud[khud_fault] = 0;
else if (player->karthud[khud_fault] > 0 && player->karthud[khud_fault] < 2*TICRATE)
@ -6410,7 +6528,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
// Speed lines
if (player->sneakertimer || player->ringboost
|| player->driftboost || player->startboost
|| player->eggmanexplode)
|| player->eggmanexplode || player->trickboost)
{
if (player->invincibilitytimer)
K_SpawnInvincibilitySpeedLines(player->mo);
@ -6651,6 +6769,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
}
if (player->trickboost)
player->trickboost--;
if (player->flamedash)
player->flamedash--;
@ -7394,9 +7515,9 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
return 0;
}
if (player->trickpanel != 0)
if (player->trickpanel != 0 && player->trickpanel < 4)
{
// No turning during trick panel
// No turning during trick panel unless you did the upwards trick (4)
return 0;
}
@ -8255,6 +8376,86 @@ void K_AdjustPlayerFriction(player_t *player)
}
}
//
// K_trickPanelTimingVisual
// Spawns the timing visual for trick panels depending on the given player's momz.
// If the player has tricked and is not in hitlag, this will send the half circles flying out.
// if you tumble, they'll fall off instead.
//
#define RADIUSSCALING 6
#define MINRADIUS 12
static void K_trickPanelTimingVisual(player_t *player, fixed_t momz)
{
fixed_t pos, tx, ty, tz;
mobj_t *flame;
angle_t hang = R_PointToAnglePlayer(player, player->mo->x, player->mo->y) + ANG1*90; // horizontal angle
angle_t vang = -FixedAngle(momz)*12 + (ANG1*45); // vertical angle dependant on momz, we want it to line up at 45 degrees at the perfect frame to trick at
fixed_t dist = FixedMul(max(MINRADIUS<<FRACBITS, abs(momz)*RADIUSSCALING), player->mo->scale); // distance.
UINT8 i;
// Do you like trig? cool, me neither.
for (i=0; i < 2; i++)
{
pos = FixedMul(dist, FINESINE(vang>>ANGLETOFINESHIFT));
tx = player->mo->x + FixedMul(pos, FINECOSINE(hang>>ANGLETOFINESHIFT));
ty = player->mo->y + FixedMul(pos, FINESINE(hang>>ANGLETOFINESHIFT));
tz = player->mo->z + player->mo->height/2 + FixedMul(dist, FINECOSINE(vang>>ANGLETOFINESHIFT));
// All coordinates set, spawn our fire, now.
flame = P_SpawnMobj(tx, ty, tz, MT_THOK);
P_SetScale(flame, player->mo->scale);
// Visuals
flame->sprite = SPR_TRCK;
flame->frame = i|FF_FULLBRIGHT;
if (player->trickpanel <= 1 && !player->tumbleBounces)
flame->tics = 2;
else
{
flame->tics = TICRATE;
if (player->trickpanel > 1) // we tricked
{
// Send the thing outwards via ghetto maths which involves redoing the whole 3d sphere again, witht the "vertical" angle shifted by 90 degrees.
// There's probably a simplier way to do this the way I want to but this works.
pos = FixedMul(48*player->mo->scale, FINESINE((vang +ANG1*90)>>ANGLETOFINESHIFT));
tx = player->mo->x + FixedMul(pos, FINECOSINE(hang>>ANGLETOFINESHIFT));
ty = player->mo->y + FixedMul(pos, FINESINE(hang>>ANGLETOFINESHIFT));
tz = player->mo->z + player->mo->height/2 + FixedMul(48*player->mo->scale, FINECOSINE((vang +ANG1*90)>>ANGLETOFINESHIFT));
flame->momx = tx -player->mo->x;
flame->momy = ty -player->mo->y;
flame->momz = tz -(player->mo->z+player->mo->height/2);
}
else // we failed the trick, drop the half circles, it'll be funny I promise.
{
flame->flags &= ~MF_NOGRAVITY;
P_SetObjectMomZ(flame, 4<<FRACBITS, false);
P_InstaThrust(flame, R_PointToAngle2(player->mo->x, player->mo->y, flame->x, flame->y), 8*mapobjectscale);
flame->momx += player->mo->momx;
flame->momy += player->mo->momy;
flame->momz += player->mo->momz;
}
}
// make sure this is only drawn for our local player
flame->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player));
vang += FixedAngle(180<<FRACBITS); // Avoid overflow warnings...
}
}
#undef RADIUSSCALING
#undef MINRADIUS
//
// K_MoveKartPlayer
//
@ -8918,6 +9119,43 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
fixed_t basespeed = P_AproxDistance(player->mo->momx, player->mo->momy); // at WORSE, keep your normal speed when tricking.
fixed_t speed = FixedMul(speedmult, P_AproxDistance(player->mo->momx, player->mo->momy));
K_trickPanelTimingVisual(player, momz);
// streaks:
if (momz*P_MobjFlip(player->mo) > 0) // only spawn those while you're going upwards relative to your current gravity
{
// these are all admittedly arbitrary numbers...
INT32 n;
INT32 maxlines = max(1, (momz/FRACUNIT)/16);
INT32 frequency = max(1, 5-(momz/FRACUNIT)/4);
fixed_t sx, sy, sz;
mobj_t *spdl;
if (!(leveltime % frequency))
{
for (n=0; n < maxlines; n++)
{
sx = player->mo->x + P_RandomRange(-24, 24)*player->mo->scale;
sy = player->mo->y + P_RandomRange(-24, 24)*player->mo->scale;
sz = player->mo->z + P_RandomRange(0, 48)*player->mo->scale;
spdl = P_SpawnMobj(sx, sy, sz, MT_FASTLINE);
P_SetTarget(&spdl->target, player->mo);
spdl->angle = R_PointToAngle2(spdl->x, spdl->y, player->mo->x, player->mo->y);
spdl->rollangle = -ANG1*90*P_MobjFlip(player->mo); // angle them downwards relative to the player's gravity...
spdl->spriteyscale = player->trickboostpower+FRACUNIT;
spdl->momx = player->mo->momx;
spdl->momy = player->mo->momy;
}
}
}
// We'll never need to go above that.
if (player->tricktime <= TRICKDELAY)
player->tricktime++;
// debug shit
//CONS_Printf("%d\n", player->mo->momz / mapobjectscale);
if (momz < -10*FRACUNIT) // :youfuckedup:
@ -8927,11 +9165,22 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
player->pflags &= ~PF_TUMBLESOUND;
player->tumbleHeight = 30; // Base tumble bounce height
player->trickpanel = 0;
K_trickPanelTimingVisual(player, momz); // fail trick visual
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
}
else if (!(player->pflags & PF_TRICKDELAY)) // don't allow tricking at the same frame you tumble obv
{
// "COOL" timing n shit.
if (cmd->turning || player->throwdir)
{
if (abs(momz) < FRACUNIT*99) // Let's use that as baseline for PERFECT trick.
{
player->karthud[khud_trickcool] = TICRATE;
}
}
// Uses cmd->turning over steering intentionally.
if (cmd->turning > 0)
{
@ -8945,6 +9194,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
player->trickpanel = 2;
player->mo->hitlag = TRICKLAG;
K_trickPanelTimingVisual(player, momz);
}
else if (cmd->turning < 0)
{
@ -8958,6 +9208,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
player->trickpanel = 3;
player->mo->hitlag = TRICKLAG;
K_trickPanelTimingVisual(player, momz);
}
else if (player->throwdir == 1)
{
@ -8976,6 +9227,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
player->trickpanel = 2;
player->mo->hitlag = TRICKLAG;
K_trickPanelTimingVisual(player, momz);
}
else if (player->throwdir == -1)
{
@ -8989,6 +9241,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
relative = false;
}
// Calculate speed boost decay:
// Base speed boost duration is 35 tics.
// At most, lose 3/4th of your boost.
player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT));
//CONS_Printf("decay: %d\n", player->trickboostdecay);
P_SetObjectMomZ(player->mo, 48*FRACUNIT, relative);
player->trickmomx = player->mo->momx;
@ -8997,8 +9255,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
P_InstaThrust(player->mo, 0, 0); // Sike, you have no speed :)
player->mo->momz = 0;
player->trickpanel = 3;
player->trickpanel = 4;
player->mo->hitlag = TRICKLAG;
K_trickPanelTimingVisual(player, momz);
}
}
}
@ -9013,8 +9272,19 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
}
else if (player->trickpanel == 4 && P_IsObjectOnGround(player->mo)) // Upwards trick landed!
{
//CONS_Printf("apply boost\n");
S_StartSound(player->mo, sfx_s23c);
K_SpawnDashDustRelease(player);
player->trickboost = TICRATE - player->trickboostdecay;
player->trickpanel = player->trickboostdecay = 0;
}
// Wait until we let go off the control stick to remove the delay
if ((player->pflags & PF_TRICKDELAY) && !player->throwdir && !cmd->turning)
// buttons must be neutral after the initial trick delay. This prevents weirdness where slight nudges after blast off would send you flying.
if ((player->pflags & PF_TRICKDELAY) && !player->throwdir && !cmd->turning && (player->tricktime >= TRICKDELAY))
{
player->pflags &= ~PF_TRICKDELAY;
}

View file

@ -34,7 +34,9 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value);
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush, boolean bot, boolean rival);
fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush);
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival);
INT32 K_GetShieldFromItem(INT32 item);
fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against);
boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2);

View file

@ -2098,6 +2098,16 @@ static int lib_rPointToAngle(lua_State *L)
return 1;
}
static int lib_rPointToAnglePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
//HUDSAFE
lua_pushangle(L, R_PointToAnglePlayer(player, x, y));
return 1;
}
static int lib_rPointToAngle2(lua_State *L)
{
fixed_t px2 = luaL_checkfixed(L, 1);
@ -3874,6 +3884,7 @@ static luaL_Reg lib[] = {
// r_defs
{"R_PointToAngle",lib_rPointToAngle},
{"R_PointToAnglePlayer", lib_rPointToAnglePlayer},
{"R_PointToAngle2",lib_rPointToAngle2},
{"R_PointToDist",lib_rPointToDist},
{"R_PointToDist2",lib_rPointToDist2},

View file

@ -354,12 +354,20 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->glanceDir);
else if (fastcmp(field,"trickpanel"))
lua_pushinteger(L, plr->trickpanel);
else if (fastcmp(field,"tricktime"))
lua_pushinteger(L, plr->tricktime);
else if (fastcmp(field,"trickmomx"))
lua_pushfixed(L, plr->trickmomx);
else if (fastcmp(field,"trickmomy"))
lua_pushfixed(L, plr->trickmomy);
else if (fastcmp(field,"trickmomz"))
lua_pushfixed(L, plr->trickmomz);
else if (fastcmp(field,"trickboostpower"))
lua_pushfixed(L, plr->trickboostpower);
else if (fastcmp(field,"trickboostdecay"))
lua_pushinteger(L, plr->trickboostdecay);
else if (fastcmp(field,"trickboost"))
lua_pushinteger(L, plr->trickboost);
else if (fastcmp(field,"roundscore"))
plr->roundscore = luaL_checkinteger(L, 3);
else if (fastcmp(field,"emeralds"))
@ -697,12 +705,20 @@ static int player_set(lua_State *L)
plr->glanceDir = luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickpanel"))
plr->trickpanel = luaL_checkinteger(L, 3);
else if (fastcmp(field,"tricktime"))
plr->tricktime = luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickmomx"))
plr->trickmomx = luaL_checkfixed(L, 3);
else if (fastcmp(field,"trickmomy"))
plr->trickmomy = luaL_checkfixed(L, 3);
else if (fastcmp(field,"trickmomz"))
plr->trickmomz = luaL_checkfixed(L, 3);
else if (fastcmp(field,"trickboostpower"))
plr->trickboostpower = luaL_checkfixed(L, 3);
else if (fastcmp(field,"trickboostdecay"))
plr->trickboostdecay = luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickboost"))
plr->trickboost = luaL_checkinteger(L, 3);
else if (fastcmp(field,"roundscore"))
lua_pushinteger(L, plr->roundscore);
else if (fastcmp(field,"emeralds"))

View file

@ -1109,7 +1109,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
gravityadd = (4*gravityadd)/3;
}
if (mo->player->trickpanel == 2 || mo->player->trickpanel == 3)
if (mo->player->trickpanel >= 2)
{
gravityadd = (5*gravityadd)/2;
}

View file

@ -305,9 +305,13 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].jawztargetdelay);
WRITEUINT8(save_p, players[i].trickpanel);
WRITEUINT8(save_p, players[i].tricktime);
WRITEUINT32(save_p, players[i].trickmomx);
WRITEUINT32(save_p, players[i].trickmomy);
WRITEUINT32(save_p, players[i].trickmomz);
WRITEUINT32(save_p, players[i].trickboostpower);
WRITEUINT8(save_p, players[i].trickboostdecay);
WRITEUINT8(save_p, players[i].trickboost);
WRITEUINT32(save_p, players[i].roundscore);
WRITEUINT8(save_p, players[i].emeralds);
@ -557,9 +561,13 @@ static void P_NetUnArchivePlayers(void)
players[i].jawztargetdelay = READUINT8(save_p);
players[i].trickpanel = READUINT8(save_p);
players[i].tricktime = READUINT8(save_p);
players[i].trickmomx = READUINT32(save_p);
players[i].trickmomy = READUINT32(save_p);
players[i].trickmomz = READUINT32(save_p);
players[i].trickboostpower = READUINT32(save_p);
players[i].trickboostdecay = READUINT8(save_p);
players[i].trickboost = READUINT8(save_p);
players[i].roundscore = READUINT32(save_p);
players[i].emeralds = READUINT8(save_p);

View file

@ -2040,7 +2040,7 @@ void P_MovePlayer(player_t *player)
{
player->drawangle += ANGLE_22h;
}
else if (player->trickpanel == 3)
else if (player->trickpanel >= 3)
{
player->drawangle -= ANGLE_22h;
}
@ -4103,7 +4103,7 @@ DoABarrelRoll (player_t *player)
return;
}
slope = InvAngle(R_GetPitchRollAngle(player->mo));
slope = InvAngle(R_GetPitchRollAngle(player->mo, player));
if (AbsAngle(slope) < ANGLE_11hh)
{

View file

@ -318,18 +318,35 @@ INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line)
angle_t R_PointToAngle(fixed_t x, fixed_t y)
{
return (y -= viewy, (x -= viewx) || y) ?
x >= 0 ?
y >= 0 ?
(x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0
ANGLE_90-tantoangle[SlopeDiv(x,y)] : // octant 1
x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8
ANGLE_270+tantoangle[SlopeDiv(x,y)] : // octant 7
y >= 0 ? (x = -x) > y ? ANGLE_180-tantoangle[SlopeDiv(y,x)] : // octant 3
ANGLE_90 + tantoangle[SlopeDiv(x,y)] : // octant 2
(x = -x) > (y = -y) ? ANGLE_180+tantoangle[SlopeDiv(y,x)] : // octant 4
ANGLE_270-tantoangle[SlopeDiv(x,y)] : // octant 5
0;
return R_PointToAngle2(viewx, viewy, x, y);
}
// Similar to R_PointToAngle, but requires an additional player_t argument.
// If this player is a local displayplayer, this will base off the calculations off of their camera instead, otherwise use viewx/viewy as usual.
// Yes this is kinda ghetto.
angle_t R_PointToAnglePlayer(player_t *player, fixed_t x, fixed_t y)
{
fixed_t refx = viewx, refy = viewy;
camera_t *cam = NULL;
UINT8 i;
for (i = 0; i < r_splitscreen; i++)
{
if (player == &players[displayplayers[i]])
{
cam = &camera[i];
break;
}
}
// use whatever cam we found's coordinates.
if (cam != NULL)
{
refx = cam->x;
refy = cam->y;
}
return R_PointToAngle2(refx, refy, x, y);
}
// This version uses 64-bit variables to avoid overflows with large values.

View file

@ -63,6 +63,7 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ];
INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node);
INT32 R_PointOnSegSide(fixed_t x, fixed_t y, seg_t *line);
angle_t R_PointToAngle(fixed_t x, fixed_t y);
angle_t R_PointToAnglePlayer(player_t *player, fixed_t x, fixed_t y);
angle_t R_PointToAngle64(INT64 x, INT64 y);
angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
angle_t R_PointToAngleEx(INT32 x2, INT32 y2, INT32 x1, INT32 y1);

View file

@ -15,6 +15,7 @@
#include "r_defs.h"
#include "r_picformats.h"
#include "doomdef.h"
#include "d_player.h"
// Patch functions
patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest);
@ -38,9 +39,10 @@ patch_t *Patch_GetRotatedSprite(
size_t frame, size_t spriteangle,
boolean flip, boolean adjustfeet,
void *info, INT32 rotationangle);
INT32 R_GetRollAngle(angle_t rollangle);
angle_t R_GetPitchRollAngle(mobj_t *mobj);
angle_t R_SpriteRotationAngle(mobj_t *mobj);
angle_t R_GetPitchRollAngle(mobj_t *mobj, player_t *viewPlayer);
angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer);
#endif
#endif // __R_PATCH__

View file

@ -21,9 +21,9 @@
fixed_t rollcosang[ROTANGLES];
fixed_t rollsinang[ROTANGLES];
angle_t R_GetPitchRollAngle(mobj_t *mobj)
angle_t R_GetPitchRollAngle(mobj_t *mobj, player_t *viewPlayer)
{
angle_t viewingAngle = R_PointToAngle(mobj->x, mobj->y);
angle_t viewingAngle = R_PointToAnglePlayer(viewPlayer, mobj->x, mobj->y);
fixed_t pitchMul = -FINESINE(viewingAngle >> ANGLETOFINESHIFT);
fixed_t rollMul = FINECOSINE(viewingAngle >> ANGLETOFINESHIFT);
@ -33,9 +33,9 @@ angle_t R_GetPitchRollAngle(mobj_t *mobj)
return rollOrPitch;
}
static angle_t R_PlayerSpriteRotation(player_t *player)
static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
{
angle_t viewingAngle = R_PointToAngle(player->mo->x, player->mo->y);
angle_t viewingAngle = R_PointToAnglePlayer(viewPlayer, player->mo->x, player->mo->y);
angle_t angleDelta = (viewingAngle - player->mo->angle);
angle_t sliptideLift = player->aizdrifttilt;
@ -60,14 +60,14 @@ static angle_t R_PlayerSpriteRotation(player_t *player)
return rollAngle;
}
angle_t R_SpriteRotationAngle(mobj_t *mobj)
angle_t R_SpriteRotationAngle(mobj_t *mobj, player_t *viewPlayer)
{
angle_t rollOrPitch = R_GetPitchRollAngle(mobj);
angle_t rollOrPitch = R_GetPitchRollAngle(mobj, viewPlayer);
angle_t rollAngle = (rollOrPitch + mobj->rollangle);
if (mobj->player)
{
rollAngle += R_PlayerSpriteRotation(mobj->player);
rollAngle += R_PlayerSpriteRotation(mobj->player, viewPlayer);
}
return rollAngle;

View file

@ -1574,7 +1574,7 @@ static void R_ProjectSprite(mobj_t *thing)
patch = W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE);
#ifdef ROTSPRITE
spriterotangle = R_SpriteRotationAngle(thing);
spriterotangle = R_SpriteRotationAngle(thing, NULL);
if (spriterotangle
&& !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE)))

View file

@ -35,7 +35,7 @@
// 3D Sound Interface
#include "hardware/hw3sound.h"
#else
static INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *vol, INT32 *sep, INT32 *pitch, sfxinfo_t *sfxinfo);
static boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *vol, INT32 *sep, INT32 *pitch, sfxinfo_t *sfxinfo);
#endif
CV_PossibleValue_t soundvolume_cons_t[] = {{0, "MIN"}, {MAX_VOLUME, "MAX"}, {0, NULL}};
@ -183,8 +183,6 @@ static INT32 S_getChannel(const void *origin, sfxinfo_t *sfxinfo)
// channel number to use
INT32 cnum;
channel_t *c;
// Find an open channel
for (cnum = 0; cnum < numofchannels; cnum++)
{
@ -196,7 +194,6 @@ static INT32 S_getChannel(const void *origin, sfxinfo_t *sfxinfo)
else if (sfxinfo == channels[cnum].sfxinfo && (sfxinfo->pitch & SF_NOMULTIPLESOUND))
{
return -1;
break;
}
else if (sfxinfo == channels[cnum].sfxinfo && sfxinfo->singularity == true)
{
@ -240,12 +237,6 @@ static INT32 S_getChannel(const void *origin, sfxinfo_t *sfxinfo)
}
}
c = &channels[cnum];
// channel is decided to be cnum.
c->sfxinfo = sfxinfo;
c->origin = origin;
return cnum;
}
@ -501,24 +492,37 @@ void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan)
closedcaptions[set].b = 2; // bob
}
static INT32 S_ScaleVolumeWithSplitscreen(INT32 volume)
{
fixed_t root = INT32_MAX;
if (r_splitscreen == 0)
{
return volume;
}
root = FixedSqrt((r_splitscreen + 1) * (FRACUNIT/3));
return FixedDiv(
volume * FRACUNIT,
root
) / FRACUNIT;
}
void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
{
const INT32 initial_volume = volume;
INT32 sep, pitch, priority, cnum;
const sfxenum_t actual_id = sfx_id;
sfxinfo_t *sfx;
const boolean reverse = (stereoreverse.value ^ encoremode);
const mobj_t *origin = (const mobj_t *)origin_p;
const sfxenum_t actual_id = sfx_id;
const boolean reverse = (stereoreverse.value ^ encoremode);
const INT32 initial_volume = (origin ? S_ScaleVolumeWithSplitscreen(volume) : volume);
listener_t listener = {0,0,0,0};
listener_t listener2 = {0,0,0,0};
listener_t listener3 = {0,0,0,0};
listener_t listener4 = {0,0,0,0};
sfxinfo_t *sfx;
INT32 sep, pitch, priority, cnum;
boolean anyListeners = false;
INT32 i;
mobj_t *listenmobj = democam.soundmobj ? : players[displayplayers[0]].mo;
mobj_t *listenmobj2 = NULL;
mobj_t *listenmobj3 = NULL;
mobj_t *listenmobj4 = NULL;
listener_t listener[MAXSPLITSCREENPLAYERS];
mobj_t *listenmobj[MAXSPLITSCREENPLAYERS];
if (S_SoundDisabled() || !sound_started)
return;
@ -527,27 +531,30 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
if (sfx_id == sfx_None)
return;
if (players[displayplayers[0]].awayviewtics)
listenmobj = players[displayplayers[0]].awayviewmobj;
if (r_splitscreen)
for (i = 0; i <= r_splitscreen; i++)
{
listenmobj2 = players[displayplayers[1]].mo;
if (players[displayplayers[1]].awayviewtics)
listenmobj2 = players[displayplayers[1]].awayviewmobj;
player_t *player = &players[displayplayers[i]];
if (r_splitscreen > 1)
memset(&listener[i], 0, sizeof (listener[i]));
listenmobj[i] = NULL;
if (!player)
{
listenmobj3 = players[displayplayers[2]].mo;
if (players[displayplayers[2]].awayviewtics)
listenmobj3 = players[displayplayers[2]].awayviewmobj;
continue;
}
if (r_splitscreen > 2)
{
listenmobj4 = players[displayplayers[3]].mo;
if (players[displayplayers[3]].awayviewtics)
listenmobj4 = players[displayplayers[3]].awayviewmobj;
}
if (i == 0 && democam.soundmobj)
{
continue;
}
if (player->awayviewtics)
{
listenmobj[i] = player->awayviewmobj;
}
else
{
listenmobj[i] = player->mo;
}
}
@ -559,75 +566,37 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
};
#endif
if (camera[0].chase && !players[displayplayers[0]].awayviewtics)
for (i = 0; i <= r_splitscreen; i++)
{
listener.x = camera[0].x;
listener.y = camera[0].y;
listener.z = camera[0].z;
listener.angle = camera[0].angle;
player_t *player = &players[displayplayers[i]];
if (!player)
{
continue;
}
if (camera[i].chase && !player->awayviewtics)
{
listener[i].x = camera[i].x;
listener[i].y = camera[i].y;
listener[i].z = camera[i].z;
listener[i].angle = camera[i].angle;
anyListeners = true;
}
else if (listenmobj[i])
{
listener[i].x = listenmobj[i]->x;
listener[i].y = listenmobj[i]->y;
listener[i].z = listenmobj[i]->z;
listener[i].angle = listenmobj[i]->angle;
anyListeners = true;
}
}
else if (listenmobj)
if (origin && anyListeners == false)
{
listener.x = listenmobj->x;
listener.y = listenmobj->y;
listener.z = listenmobj->z;
listener.angle = listenmobj->angle;
}
else if (origin)
// If a mobj is trying to make a noise, and no one is around to hear it, does it make a sound?
return;
if (listenmobj2)
{
if (camera[1].chase && !players[displayplayers[1]].awayviewtics)
{
listener2.x = camera[1].x;
listener2.y = camera[1].y;
listener2.z = camera[1].z;
listener2.angle = camera[1].angle;
}
else
{
listener2.x = listenmobj2->x;
listener2.y = listenmobj2->y;
listener2.z = listenmobj2->z;
listener2.angle = listenmobj2->angle;
}
}
if (listenmobj3)
{
if (camera[2].chase && !players[displayplayers[2]].awayviewtics)
{
listener3.x = camera[2].x;
listener3.y = camera[2].y;
listener3.z = camera[2].z;
listener3.angle = camera[2].angle;
}
else
{
listener3.x = listenmobj3->x;
listener3.y = listenmobj3->y;
listener3.z = listenmobj3->z;
listener3.angle = listenmobj3->angle;
}
}
if (listenmobj4)
{
if (camera[3].chase && !players[displayplayers[3]].awayviewtics)
{
listener4.x = camera[3].x;
listener4.y = camera[3].y;
listener4.z = camera[3].z;
listener4.angle = camera[3].angle;
}
else
{
listener4.x = listenmobj4->x;
listener4.y = listenmobj4->y;
listener4.z = listenmobj4->z;
listener4.angle = listenmobj4->angle;
}
}
// check for bogus sound #
@ -647,36 +616,40 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
pitch = NORM_PITCH;
priority = NORM_PRIORITY;
if (r_splitscreen && origin)
volume = FixedDiv(volume<<FRACBITS, FixedSqrt((r_splitscreen+1)<<FRACBITS))>>FRACBITS;
if (r_splitscreen && listenmobj2) // Copy the sound for the split player
for (i = r_splitscreen; i >= 0; i--)
{
// Check to see if it is audible, and if not, modify the params
if (origin && origin != listenmobj2)
// Copy the sound for the splitscreen players!
if (listenmobj[i] == NULL && i != 0)
{
INT32 rc;
rc = S_AdjustSoundParams(listenmobj2, origin, &volume, &sep, &pitch, sfx);
continue;
}
// Check to see if it is audible, and if not, modify the params
if (origin && origin != listenmobj[i])
{
boolean rc = S_AdjustSoundParams(listenmobj[i], origin, &volume, &sep, &pitch, sfx);
if (!rc)
goto dontplay; // Maybe the other player can hear it...
{
continue; // Maybe the other player can hear it...
}
if (origin->x == listener2.x && origin->y == listener2.y)
if (origin->x == listener[i].x && origin->y == listener[i].y)
{
sep = NORM_SEP;
}
}
else if (!origin)
// Do not play origin-less sounds for the second player.
else if (i > 0 && !origin)
{
// Do not play origin-less sounds for the splitscreen players.
// The first player will be able to hear it just fine,
// we really don't want it playing twice.
goto dontplay;
continue;
}
else
{
sep = NORM_SEP;
// try to find a channel
cnum = S_getChannel(origin, sfx);
if (cnum < 0)
return; // If there's no free channels, it's not gonna be free for player 1, either.
}
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
@ -685,191 +658,43 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if (!sfx->data)
sfx->data = I_GetSfx(sfx);
// increase the usefulness
if (sfx->usefulness++ < 0)
sfx->usefulness = -1;
// Avoid channel reverse if surround
if (reverse
#ifdef SURROUND
&& sep != SURROUND_SEP
#endif
)
sep = (~sep) & 255;
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
}
dontplay:
if (r_splitscreen > 1 && listenmobj3) // Copy the sound for the third player
{
// Check to see if it is audible, and if not, modify the params
if (origin && origin != listenmobj3)
{
INT32 rc;
rc = S_AdjustSoundParams(listenmobj3, origin, &volume, &sep, &pitch, sfx);
if (!rc)
goto dontplay3; // Maybe the other player can hear it...
if (origin->x == listener3.x && origin->y == listener3.y)
sep = NORM_SEP;
}
else if (!origin)
// Do not play origin-less sounds for the second player.
// The first player will be able to hear it just fine,
// we really don't want it playing twice.
goto dontplay3;
else
sep = NORM_SEP;
// try to find a channel
cnum = S_getChannel(origin, sfx);
if (cnum < 0)
return; // If there's no free channels, it's not gonna be free for player 1, either.
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
// each time the sound is needed?
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if (!sfx->data)
sfx->data = I_GetSfx(sfx);
}
// increase the usefulness
if (sfx->usefulness++ < 0)
sfx->usefulness = -1;
// Avoid channel reverse if surround
if (reverse
#ifdef SURROUND
&& sep != SURROUND_SEP
#endif
)
sep = (~sep) & 255;
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
}
dontplay3:
if (r_splitscreen > 2 && listenmobj4) // Copy the sound for the split player
{
// Check to see if it is audible, and if not, modify the params
if (origin && origin != listenmobj4)
{
INT32 rc;
rc = S_AdjustSoundParams(listenmobj4, origin, &volume, &sep, &pitch, sfx);
if (!rc)
goto dontplay4; // Maybe the other player can hear it...
if (origin->x == listener4.x && origin->y == listener4.y)
sep = NORM_SEP;
}
else if (!origin)
// Do not play origin-less sounds for the second player.
// The first player will be able to hear it just fine,
// we really don't want it playing twice.
goto dontplay4;
else
sep = NORM_SEP;
// try to find a channel
cnum = S_getChannel(origin, sfx);
if (cnum < 0)
return; // If there's no free channels, it's not gonna be free for player 1, either.
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
// each time the sound is needed?
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if (!sfx->data)
sfx->data = I_GetSfx(sfx);
// increase the usefulness
if (sfx->usefulness++ < 0)
sfx->usefulness = -1;
}
// Avoid channel reverse if surround
if (reverse
#ifdef SURROUND
&& sep != SURROUND_SEP
#endif
)
)
{
sep = (~sep) & 255;
}
// Handle closed caption input.
S_StartCaption(actual_id, cnum, MAXCAPTIONTICS);
// Assigns the handle to one of the channels in the
// mix/output buffer.
// At this point it is determined that a sound can and should be played, so find a free channel to play it on
cnum = S_getChannel(origin, sfx);
if (cnum < 0)
{
return; // If there's no free channels, there won't be any for anymore players either
}
// Now that we know we are going to play a sound, fill out this info
channels[cnum].sfxinfo = sfx;
channels[cnum].origin = origin;
channels[cnum].volume = initial_volume;
channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
}
dontplay4:
// Check to see if it is audible, and if not, modify the params
if (origin && origin != listenmobj)
{
INT32 rc;
rc = S_AdjustSoundParams(listenmobj, origin, &volume, &sep, &pitch, sfx);
if (!rc)
return;
if (origin->x == listener.x && origin->y == listener.y)
sep = NORM_SEP;
}
else
sep = NORM_SEP;
// try to find a channel
cnum = S_getChannel(origin, sfx);
if (cnum < 0)
return;
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
// each time the sound is needed?
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if (!sfx->data)
sfx->data = I_GetSfx(sfx);
// increase the usefulness
if (sfx->usefulness++ < 0)
sfx->usefulness = -1;
// Avoid channel reverse if surround
if (reverse
#ifdef SURROUND
&& sep != SURROUND_SEP
#endif
)
sep = (~sep) & 255;
// Handle closed caption input.
S_StartCaption(actual_id, cnum, MAXCAPTIONTICS);
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels[cnum].volume = initial_volume;
channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
}
void S_StartSound(const void *origin, sfxenum_t sfx_id)
@ -920,23 +745,13 @@ static INT32 actualdigmusicvolume;
void S_UpdateSounds(void)
{
INT32 audible, cnum, volume, sep, pitch;
INT32 cnum, volume, sep, pitch;
boolean audible = false;
channel_t *c;
INT32 i;
listener_t listener;
listener_t listener2;
listener_t listener3;
listener_t listener4;
mobj_t *listenmobj = democam.soundmobj ? : players[displayplayers[0]].mo;
mobj_t *listenmobj2 = NULL;
mobj_t *listenmobj3 = NULL;
mobj_t *listenmobj4 = NULL;
memset(&listener, 0, sizeof(listener_t));
memset(&listener2, 0, sizeof(listener_t));
memset(&listener3, 0, sizeof(listener_t));
memset(&listener4, 0, sizeof(listener_t));
listener_t listener[MAXSPLITSCREENPLAYERS];
mobj_t *listenmobj[MAXSPLITSCREENPLAYERS];
// Update sound/music volumes, if changed manually at console
if (actualsfxvolume != cv_soundvolume.value * USER_VOLUME_SCALE)
@ -949,7 +764,7 @@ void S_UpdateSounds(void)
{
#ifndef NOMUMBLE
// Stop Mumble cutting out. I'm sick of it.
I_UpdateMumble(NULL, listener);
I_UpdateMumble(NULL, listener[0]);
#endif
goto notinlevel;
@ -958,47 +773,35 @@ void S_UpdateSounds(void)
if (dedicated || sound_disabled)
return;
if (players[displayplayers[0]].awayviewtics)
listenmobj = players[displayplayers[0]].awayviewmobj;
if (r_splitscreen)
for (i = 0; i <= r_splitscreen; i++)
{
listenmobj2 = players[displayplayers[1]].mo;
if (players[displayplayers[1]].awayviewtics)
listenmobj2 = players[displayplayers[1]].awayviewmobj;
player_t *player = &players[displayplayers[i]];
if (r_splitscreen > 1)
memset(&listener[i], 0, sizeof (listener[i]));
listenmobj[i] = NULL;
if (!player)
{
listenmobj3 = players[displayplayers[2]].mo;
if (players[displayplayers[2]].awayviewtics)
listenmobj3 = players[displayplayers[2]].awayviewmobj;
continue;
}
if (r_splitscreen > 2)
{
listenmobj4 = players[displayplayers[3]].mo;
if (players[displayplayers[3]].awayviewtics)
listenmobj4 = players[displayplayers[3]].awayviewmobj;
}
if (i == 0 && democam.soundmobj)
{
continue;
}
if (player->awayviewtics)
{
listenmobj[i] = player->awayviewmobj;
}
else
{
listenmobj[i] = player->mo;
}
}
if (camera[0].chase && !players[displayplayers[0]].awayviewtics)
{
listener.x = camera[0].x;
listener.y = camera[0].y;
listener.z = camera[0].z;
listener.angle = camera[0].angle;
}
else if (listenmobj)
{
listener.x = listenmobj->x;
listener.y = listenmobj->y;
listener.z = listenmobj->z;
listener.angle = listenmobj->angle;
}
#ifndef NOMUMBLE
I_UpdateMumble(players[consoleplayer].mo, listener);
I_UpdateMumble(players[consoleplayer].mo, listener[0]);
#endif
#ifdef HW3SOUND
@ -1009,57 +812,28 @@ void S_UpdateSounds(void)
}
#endif
if (listenmobj2)
for (i = 0; i <= r_splitscreen; i++)
{
if (camera[1].chase && !players[displayplayers[1]].awayviewtics)
{
listener2.x = camera[1].x;
listener2.y = camera[1].y;
listener2.z = camera[1].z;
listener2.angle = camera[1].angle;
}
else
{
listener2.x = listenmobj2->x;
listener2.y = listenmobj2->y;
listener2.z = listenmobj2->z;
listener2.angle = listenmobj2->angle;
}
}
player_t *player = &players[displayplayers[i]];
if (listenmobj3)
{
if (camera[2].chase && !players[displayplayers[2]].awayviewtics)
if (!player)
{
listener3.x = camera[2].x;
listener3.y = camera[2].y;
listener3.z = camera[2].z;
listener3.angle = camera[2].angle;
continue;
}
else
{
listener3.x = listenmobj3->x;
listener3.y = listenmobj3->y;
listener3.z = listenmobj3->z;
listener3.angle = listenmobj3->angle;
}
}
if (listenmobj4)
{
if (camera[3].chase && !players[displayplayers[3]].awayviewtics)
if (camera[i].chase && !player->awayviewtics)
{
listener4.x = camera[3].x;
listener4.y = camera[3].y;
listener4.z = camera[3].z;
listener4.angle = camera[3].angle;
listener[i].x = camera[i].x;
listener[i].y = camera[i].y;
listener[i].z = camera[i].z;
listener[i].angle = camera[i].angle;
}
else
else if (listenmobj[i])
{
listener4.x = listenmobj4->x;
listener4.y = listenmobj4->y;
listener4.z = listenmobj4->z;
listener4.angle = listenmobj4->angle;
listener[i].x = listenmobj[i]->x;
listener[i].y = listenmobj[i]->y;
listener[i].z = listenmobj[i]->z;
listener[i].angle = listenmobj[i]->angle;
}
}
@ -1076,83 +850,53 @@ void S_UpdateSounds(void)
pitch = NORM_PITCH;
sep = NORM_SEP;
if (r_splitscreen && c->origin)
volume = FixedDiv(volume<<FRACBITS, FixedSqrt((r_splitscreen+1)<<FRACBITS))>>FRACBITS;
// check non-local sounds for distance clipping
// or modify their params
if (c->origin && ((c->origin != players[displayplayers[0]].mo)
|| (r_splitscreen && c->origin != players[displayplayers[1]].mo)
|| (r_splitscreen > 1 && c->origin != players[displayplayers[2]].mo)
|| (r_splitscreen > 2 && c->origin != players[displayplayers[3]].mo)))
if (c->origin)
{
// Whomever is closer gets the sound, but only in splitscreen.
if (r_splitscreen)
boolean itsUs = false;
for (i = 0; i <= r_splitscreen; i++)
{
if (c->origin == players[displayplayers[i]].mo)
{
itsUs = true;
break;
}
}
if (itsUs == false)
{
const mobj_t *soundmobj = c->origin;
fixed_t recdist = -1;
INT32 i, p = -1;
fixed_t recdist = INT32_MAX;
UINT8 p = 0;
for (i = 0; i <= r_splitscreen; i++)
{
fixed_t thisdist = -1;
fixed_t thisdist = INT32_MAX;
if (i == 0 && listenmobj)
thisdist = P_AproxDistance(listener.x-soundmobj->x, listener.y-soundmobj->y);
else if (i == 1 && listenmobj2)
thisdist = P_AproxDistance(listener2.x-soundmobj->x, listener2.y-soundmobj->y);
else if (i == 2 && listenmobj3)
thisdist = P_AproxDistance(listener3.x-soundmobj->x, listener3.y-soundmobj->y);
else if (i == 3 && listenmobj4)
thisdist = P_AproxDistance(listener4.x-soundmobj->x, listener4.y-soundmobj->y);
else
if (!listenmobj[i])
{
continue;
}
if (recdist == -1 || (thisdist != -1 && thisdist < recdist))
thisdist = P_AproxDistance(listener[i].x - soundmobj->x, listener[i].y - soundmobj->y);
if (thisdist < recdist)
{
recdist = thisdist;
p = i;
}
}
if (p != -1)
if (listenmobj[p])
{
if (p == 1)
{
// Player 2 gets the sound
audible = S_AdjustSoundParams(listenmobj2, c->origin, &volume, &sep, &pitch,
c->sfxinfo);
}
else if (p == 2)
{
// Player 3 gets the sound
audible = S_AdjustSoundParams(listenmobj3, c->origin, &volume, &sep, &pitch,
c->sfxinfo);
}
else if (p == 3)
{
// Player 4 gets the sound
audible = S_AdjustSoundParams(listenmobj4, c->origin, &volume, &sep, &pitch,
c->sfxinfo);
}
else
{
// Player 1 gets the sound
audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch,
c->sfxinfo);
}
if (audible)
I_UpdateSoundParams(c->handle, volume, sep, pitch);
else
S_StopChannel(cnum);
audible = S_AdjustSoundParams(
listenmobj[p], c->origin,
&volume, &sep, &pitch,
c->sfxinfo
);
}
}
else if (listenmobj && !r_splitscreen)
{
// In the case of a single player, he or she always should get updated sound.
audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch,
c->sfxinfo);
if (audible)
I_UpdateSoundParams(c->handle, volume, sep, pitch);
@ -1273,54 +1017,39 @@ fixed_t S_CalculateSoundDistance(fixed_t sx1, fixed_t sy1, fixed_t sz1, fixed_t
// If the sound is not audible, returns a 0.
// Otherwise, modifies parameters and returns 1.
//
INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *vol, INT32 *sep, INT32 *pitch,
boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *vol, INT32 *sep, INT32 *pitch,
sfxinfo_t *sfxinfo)
{
const boolean reverse = (stereoreverse.value ^ encoremode);
fixed_t approx_dist;
angle_t angle;
listener_t listensource;
const boolean reverse = (stereoreverse.value ^ encoremode);
INT32 i;
(void)pitch;
if (!listener)
return false;
if (listener == players[displayplayers[0]].mo && camera[0].chase)
// Init listensource with default listener
listensource.x = listener->x;
listensource.y = listener->y;
listensource.z = listener->z;
listensource.angle = listener->angle;
for (i = 0; i <= r_splitscreen; i++)
{
listensource.x = camera[0].x;
listensource.y = camera[0].y;
listensource.z = camera[0].z;
listensource.angle = camera[0].angle;
}
else if (r_splitscreen && listener == players[displayplayers[1]].mo && camera[1].chase)
{
listensource.x = camera[1].x;
listensource.y = camera[1].y;
listensource.z = camera[1].z;
listensource.angle = camera[1].angle;
}
else if (r_splitscreen > 1 && listener == players[displayplayers[2]].mo && camera[2].chase)
{
listensource.x = camera[2].x;
listensource.y = camera[2].y;
listensource.z = camera[2].z;
listensource.angle = camera[2].angle;
}
else if (r_splitscreen > 2 && listener == players[displayplayers[3]].mo && camera[3].chase)
{
listensource.x = camera[3].x;
listensource.y = camera[3].y;
listensource.z = camera[3].z;
listensource.angle = camera[3].angle;
}
else
{
listensource.x = listener->x;
listensource.y = listener->y;
listensource.z = listener->z;
listensource.angle = listener->angle;
// If listener is a chasecam player, use the camera instead
if (listener == players[displayplayers[i]].mo && camera[i].chase)
{
listensource.x = camera[i].x;
listensource.y = camera[i].y;
listensource.z = camera[i].z;
listensource.angle = camera[i].angle;
break;
}
}
if (sfxinfo->pitch & SF_OUTSIDESOUND) // Rain special case
@ -1370,7 +1099,7 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v
approx_dist = FixedDiv(approx_dist,2*FRACUNIT);
if (approx_dist > S_CLIPPING_DIST)
return 0;
return false;
// angle of source to listener
angle = R_PointToAngle2(listensource.x, listensource.y, source->x, source->y);
@ -1405,9 +1134,6 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v
*vol = FixedMul(*vol * FRACUNIT / 255, n) / S_ATTENUATOR;
}
if (r_splitscreen)
*vol = FixedDiv((*vol)<<FRACBITS, FixedSqrt((r_splitscreen+1)<<FRACBITS))>>FRACBITS;
return (*vol > 0);
}