mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge remote-tracking branch 'origin/master' into wall-transfer-everything
This commit is contained in:
commit
fe6bfd1ff2
28 changed files with 1916 additions and 912 deletions
|
|
@ -428,6 +428,9 @@ typedef struct player_s
|
|||
UINT8 driftboost; // (0 to 125) - Boost you get from drifting
|
||||
UINT8 strongdriftboost; // (0 to 125) - While active, boost from drifting gives a stronger speed increase
|
||||
|
||||
UINT16 gateBoost; // Juicebox Manta Ring boosts
|
||||
UINT8 gateSound; // Sound effect combo
|
||||
|
||||
SINT8 aizdriftstrat; // (-1 to 1) - Let go of your drift while boosting? Helper for the SICK STRATZ (sliptiding!) you have just unlocked
|
||||
INT32 aizdrifttilt;
|
||||
INT32 aizdriftturn;
|
||||
|
|
|
|||
|
|
@ -322,7 +322,6 @@ actionpointer_t actionpointers[] =
|
|||
{{A_ItemPop}, "A_ITEMPOP"},
|
||||
{{A_JawzChase}, "A_JAWZCHASE"},
|
||||
{{A_JawzExplode}, "A_JAWZEXPLODE"},
|
||||
{{A_SPBChase}, "A_SPBCHASE"},
|
||||
{{A_SSMineSearch}, "A_SSMINESEARCH"},
|
||||
{{A_SSMineExplode}, "A_SSMINEEXPLODE"},
|
||||
{{A_LandMineExplode}, "A_LANDMINEEXPLODE"},
|
||||
|
|
@ -3652,6 +3651,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_SPB20",
|
||||
"S_SPB_DEAD",
|
||||
|
||||
// Juicebox for SPB
|
||||
"S_MANTA1",
|
||||
"S_MANTA2",
|
||||
|
||||
// Lightning Shield
|
||||
"S_LIGHTNINGSHIELD1",
|
||||
"S_LIGHTNINGSHIELD2",
|
||||
|
|
@ -5356,6 +5359,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
|
||||
"MT_SPB", // Self-Propelled Bomb
|
||||
"MT_SPBEXPLOSION",
|
||||
"MT_MANTARING", // Juicebox for SPB
|
||||
|
||||
"MT_LIGHTNINGSHIELD", // Shields
|
||||
"MT_BUBBLESHIELD",
|
||||
|
|
|
|||
|
|
@ -707,7 +707,7 @@ extern boolean comeback;
|
|||
|
||||
extern SINT8 battlewanted[4];
|
||||
extern tic_t wantedcalcdelay;
|
||||
extern tic_t indirectitemcooldown;
|
||||
extern tic_t itemCooldowns[NUMKARTITEMS - 1];
|
||||
extern tic_t mapreset;
|
||||
extern boolean thwompsactive;
|
||||
extern UINT8 lastLowestLap;
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ SINT8 pickedvote; // What vote the host rolls
|
|||
// Server-sided, synched variables
|
||||
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
|
||||
tic_t wantedcalcdelay; // Time before it recalculates WANTED
|
||||
tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded
|
||||
tic_t itemCooldowns[NUMKARTITEMS - 1]; // Cooldowns to prevent item spawning
|
||||
tic_t mapreset; // Map reset delay when enough players have joined an empty game
|
||||
boolean thwompsactive; // Thwomps activate on lap 2
|
||||
UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors
|
||||
|
|
|
|||
78
src/info.c
78
src/info.c
|
|
@ -565,6 +565,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"BHOG", // Ballhog
|
||||
"BHBM", // Ballhog BOOM
|
||||
"SPBM", // Self-Propelled Bomb
|
||||
"TRIS", // SPB Manta Ring start
|
||||
"TRNQ", // SPB Manta Ring loop
|
||||
"THNS", // Lightning Shield
|
||||
"BUBS", // Bubble Shield (not Bubs)
|
||||
"BWVE", // Bubble Shield waves
|
||||
|
|
@ -4199,28 +4201,31 @@ state_t states[NUMSTATES] =
|
|||
{SPR_BHBM, FF_FULLBRIGHT|14, 1, {NULL}, 0, 0, S_BALLHOGBOOM16}, // S_BALLHOGBOOM15
|
||||
{SPR_BHBM, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_NULL}, // S_BALLHOGBOOM16
|
||||
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB2}, // S_SPB1
|
||||
{SPR_SPBM, 1, 1, {A_SPBChase}, 0, 0, S_SPB3}, // S_SPB2
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB4}, // S_SPB3
|
||||
{SPR_SPBM, 2, 1, {A_SPBChase}, 0, 0, S_SPB5}, // S_SPB4
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB6}, // S_SPB5
|
||||
{SPR_SPBM, 3, 1, {A_SPBChase}, 0, 0, S_SPB7}, // S_SPB6
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB8}, // S_SPB7
|
||||
{SPR_SPBM, 4, 1, {A_SPBChase}, 0, 0, S_SPB9}, // S_SPB8
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB10}, // S_SPB9
|
||||
{SPR_SPBM, 5, 1, {A_SPBChase}, 0, 0, S_SPB11}, // S_SPB10
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB12}, // S_SPB11
|
||||
{SPR_SPBM, 6, 1, {A_SPBChase}, 0, 0, S_SPB13}, // S_SPB12
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB14}, // S_SPB13
|
||||
{SPR_SPBM, 7, 1, {A_SPBChase}, 0, 0, S_SPB15}, // S_SPB14
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB16}, // S_SPB15
|
||||
{SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB17}, // S_SPB16
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB18}, // S_SPB17
|
||||
{SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB19}, // S_SPB18
|
||||
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB20}, // S_SPB19
|
||||
{SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB1}, // S_SPB20
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB2}, // S_SPB1
|
||||
{SPR_SPBM, 1, 1, {NULL}, 0, 0, S_SPB3}, // S_SPB2
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB4}, // S_SPB3
|
||||
{SPR_SPBM, 2, 1, {NULL}, 0, 0, S_SPB5}, // S_SPB4
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB6}, // S_SPB5
|
||||
{SPR_SPBM, 3, 1, {NULL}, 0, 0, S_SPB7}, // S_SPB6
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB8}, // S_SPB7
|
||||
{SPR_SPBM, 4, 1, {NULL}, 0, 0, S_SPB9}, // S_SPB8
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB10}, // S_SPB9
|
||||
{SPR_SPBM, 5, 1, {NULL}, 0, 0, S_SPB11}, // S_SPB10
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB12}, // S_SPB11
|
||||
{SPR_SPBM, 6, 1, {NULL}, 0, 0, S_SPB13}, // S_SPB12
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB14}, // S_SPB13
|
||||
{SPR_SPBM, 7, 1, {NULL}, 0, 0, S_SPB15}, // S_SPB14
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB16}, // S_SPB15
|
||||
{SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB17}, // S_SPB16
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB18}, // S_SPB17
|
||||
{SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB19}, // S_SPB18
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB20}, // S_SPB19
|
||||
{SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB1}, // S_SPB20
|
||||
{SPR_SPBM, 8, 175, {NULL}, 0, 0, S_NULL}, // S_SPB_DEAD
|
||||
|
||||
{SPR_TRIS, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_ADD, 9, {NULL}, 2, 3, S_MANTA2}, // S_MANTA1
|
||||
{SPR_TRNQ, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE|FF_ADD, -1, {NULL}, 7, 1, S_NULL}, // S_MANTA2
|
||||
|
||||
{SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD2}, // S_LIGHTNINGSHIELD1
|
||||
{SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD3}, // S_LIGHTNINGSHIELD2
|
||||
{SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD4}, // S_LIGHTNINGSHIELD3
|
||||
|
|
@ -23906,6 +23911,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MANTARING
|
||||
-1, // doomednum
|
||||
S_MANTA1, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
64*FRACUNIT, // radius
|
||||
64*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_LIGHTNINGSHIELD
|
||||
-1, // doomednum
|
||||
S_LIGHTNINGSHIELD1, // spawnstate
|
||||
|
|
@ -28704,13 +28736,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
16<<FRACBITS, // radius
|
||||
16<<FRACBITS, // radius
|
||||
32<<FRACBITS, // height
|
||||
1, // display offset
|
||||
100, // mass
|
||||
DMG_NORMAL, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_DONTENCOREMAP|MF_NOGRAVITY|MF_PAIN, // flags
|
||||
MF_NOGRAVITY|MF_PAIN|MF_NOHITLAGFORME|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,6 @@ enum actionnum
|
|||
A_ITEMPOP,
|
||||
A_JAWZCHASE,
|
||||
A_JAWZEXPLODE,
|
||||
A_SPBCHASE,
|
||||
A_SSMINESEARCH,
|
||||
A_SSMINEEXPLODE,
|
||||
A_LANDMINEEXPLODE,
|
||||
|
|
@ -548,7 +547,6 @@ void A_ChangeHeight();
|
|||
void A_ItemPop();
|
||||
void A_JawzChase();
|
||||
void A_JawzExplode();
|
||||
void A_SPBChase();
|
||||
void A_SSMineSearch();
|
||||
void A_SSMineExplode();
|
||||
void A_LandMineExplode();
|
||||
|
|
@ -1113,6 +1111,8 @@ typedef enum sprite
|
|||
SPR_BHOG, // Ballhog
|
||||
SPR_BHBM, // Ballhog BOOM
|
||||
SPR_SPBM, // Self-Propelled Bomb
|
||||
SPR_TRIS, // SPB Manta Ring start
|
||||
SPR_TRNQ, // SPB Manta Ring loop
|
||||
SPR_THNS, // Thunder Shield
|
||||
SPR_BUBS, // Bubble Shield (not Bubs)
|
||||
SPR_BWVE, // Bubble Shield waves
|
||||
|
|
@ -4650,6 +4650,10 @@ typedef enum state
|
|||
S_SPB20,
|
||||
S_SPB_DEAD,
|
||||
|
||||
// Juicebox for SPB
|
||||
S_MANTA1,
|
||||
S_MANTA2,
|
||||
|
||||
// Thunder Shield
|
||||
S_LIGHTNINGSHIELD1,
|
||||
S_LIGHTNINGSHIELD2,
|
||||
|
|
@ -6390,6 +6394,7 @@ typedef enum mobj_type
|
|||
|
||||
MT_SPB, // SPB stuff
|
||||
MT_SPBEXPLOSION,
|
||||
MT_MANTARING, // Juicebox for SPB
|
||||
|
||||
MT_LIGHTNINGSHIELD, // Shields
|
||||
MT_BUBBLESHIELD,
|
||||
|
|
|
|||
54
src/k_hud.c
54
src/k_hud.c
|
|
@ -4445,7 +4445,6 @@ static void K_drawDistributionDebugger(void)
|
|||
kp_jawz[1],
|
||||
kp_mine[1],
|
||||
kp_landmine[1],
|
||||
kp_droptarget[1],
|
||||
kp_ballhog[1],
|
||||
kp_selfpropelledbomb[1],
|
||||
kp_grow[1],
|
||||
|
|
@ -4457,6 +4456,7 @@ static void K_drawDistributionDebugger(void)
|
|||
kp_pogospring[1],
|
||||
kp_superring[1],
|
||||
kp_kitchensink[1],
|
||||
kp_droptarget[1],
|
||||
|
||||
kp_sneaker[1],
|
||||
kp_sneaker[1],
|
||||
|
|
@ -4471,11 +4471,17 @@ static void K_drawDistributionDebugger(void)
|
|||
UINT32 pdis = 0;
|
||||
INT32 i;
|
||||
INT32 x = -9, y = -9;
|
||||
boolean spbrush = false;
|
||||
|
||||
if (stplyr != &players[displayplayers[0]]) // only for p1
|
||||
return;
|
||||
|
||||
if (K_ForcedSPB(stplyr) == true)
|
||||
{
|
||||
V_DrawScaledPatch(x, y, V_SNAPTOTOP, items[KITEM_SPB]);
|
||||
V_DrawThinString(x+11, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, "EX");
|
||||
return;
|
||||
}
|
||||
|
||||
// The only code duplication from the Kart, just to avoid the actual item function from calculating pingame twice
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
|
@ -4498,14 +4504,7 @@ static void K_drawDistributionDebugger(void)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
pdis = K_ScaleItemDistance(pdis, pingame);
|
||||
|
||||
if (stplyr->bot && stplyr->botvars.rival)
|
||||
{
|
||||
|
|
@ -4513,7 +4512,7 @@ static void K_drawDistributionDebugger(void)
|
|||
pdis = (15 * pdis) / 14;
|
||||
}
|
||||
|
||||
useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper, spbrush);
|
||||
useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
|
|
@ -4521,38 +4520,21 @@ static void K_drawDistributionDebugger(void)
|
|||
useodds, i,
|
||||
stplyr->distancetofinish,
|
||||
0,
|
||||
spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival)
|
||||
stplyr->bot, (stplyr->bot && stplyr->botvars.rival)
|
||||
);
|
||||
INT32 amount = 1;
|
||||
|
||||
if (itemodds <= 0)
|
||||
continue;
|
||||
|
||||
V_DrawScaledPatch(x, y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, items[i]);
|
||||
V_DrawThinString(x+11, y+31, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, va("%d", itemodds));
|
||||
V_DrawScaledPatch(x, y, V_SNAPTOTOP, items[i]);
|
||||
V_DrawThinString(x+11, y+31, V_SNAPTOTOP, va("%d", itemodds));
|
||||
|
||||
// Display amount for multi-items
|
||||
if (i >= NUMKARTITEMS)
|
||||
amount = K_ItemResultToAmount(i);
|
||||
if (amount > 1)
|
||||
{
|
||||
INT32 amount;
|
||||
switch (i)
|
||||
{
|
||||
case KRITEM_TENFOLDBANANA:
|
||||
amount = 10;
|
||||
break;
|
||||
case KRITEM_QUADORBINAUT:
|
||||
amount = 4;
|
||||
break;
|
||||
case KRITEM_DUALJAWZ:
|
||||
amount = 2;
|
||||
break;
|
||||
case KRITEM_DUALSNEAKER:
|
||||
amount = 2;
|
||||
break;
|
||||
default:
|
||||
amount = 3;
|
||||
break;
|
||||
}
|
||||
V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, va("x%d", amount));
|
||||
V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("x%d", amount));
|
||||
}
|
||||
|
||||
x += 32;
|
||||
|
|
@ -4563,7 +4545,7 @@ static void K_drawDistributionDebugger(void)
|
|||
}
|
||||
}
|
||||
|
||||
V_DrawString(0, 0, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, va("USEODDS %d", useodds));
|
||||
V_DrawString(0, 0, V_SNAPTOTOP, va("USEODDS %d", useodds));
|
||||
}
|
||||
|
||||
static void K_drawCheckpointDebugger(void)
|
||||
|
|
|
|||
629
src/k_kart.c
629
src/k_kart.c
|
|
@ -47,7 +47,6 @@
|
|||
// encoremode is Encore Mode (duh), bool
|
||||
// comeback is Battle Mode's karma comeback, also bool
|
||||
// battlewanted is an array of the WANTED player nums, -1 for no player in that slot
|
||||
// indirectitemcooldown is timer before anyone's allowed another Shrink/SPB
|
||||
// mapreset is set when enough players fill an empty server
|
||||
|
||||
void K_TimerReset(void)
|
||||
|
|
@ -326,7 +325,6 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] =
|
|||
&cv_jawz,
|
||||
&cv_mine,
|
||||
&cv_landmine,
|
||||
&cv_droptarget,
|
||||
&cv_ballhog,
|
||||
&cv_selfpropelledbomb,
|
||||
&cv_grow,
|
||||
|
|
@ -338,6 +336,7 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] =
|
|||
&cv_pogospring,
|
||||
&cv_superring,
|
||||
&cv_kitchensink,
|
||||
&cv_droptarget,
|
||||
&cv_dualsneaker,
|
||||
&cv_triplesneaker,
|
||||
&cv_triplebanana,
|
||||
|
|
@ -363,7 +362,7 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
|
|||
/*Mine*/ { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine
|
||||
/*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
|
||||
/*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog
|
||||
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
|
||||
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Self-Propelled Bomb
|
||||
/*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow
|
||||
/*Shrink*/ { 0, 0, 0, 0, 0, 1, 3, 2 }, // Shrink
|
||||
/*Lightning Shield*/ { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
|
||||
|
|
@ -417,8 +416,8 @@ static UINT8 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 SPBSTARTDIST (6*DISTVAR) // Distance when SPB can start appearing
|
||||
#define SPBFORCEDIST (12*DISTVAR) // Distance when SPB is forced onto the next person who rolls an item
|
||||
#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.
|
||||
|
|
@ -448,6 +447,111 @@ INT32 K_GetShieldFromItem(INT32 item)
|
|||
}
|
||||
}
|
||||
|
||||
SINT8 K_ItemResultToType(SINT8 getitem)
|
||||
{
|
||||
if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback)
|
||||
{
|
||||
if (getitem != 0)
|
||||
{
|
||||
CONS_Printf("ERROR: K_GetItemResultToItemType - Item roulette gave bad item (%d) :(\n", getitem);
|
||||
}
|
||||
|
||||
return KITEM_SAD;
|
||||
}
|
||||
|
||||
if (getitem >= NUMKARTITEMS)
|
||||
{
|
||||
switch (getitem)
|
||||
{
|
||||
case KRITEM_DUALSNEAKER:
|
||||
case KRITEM_TRIPLESNEAKER:
|
||||
return KITEM_SNEAKER;
|
||||
|
||||
case KRITEM_TRIPLEBANANA:
|
||||
case KRITEM_TENFOLDBANANA:
|
||||
return KITEM_BANANA;
|
||||
|
||||
case KRITEM_TRIPLEORBINAUT:
|
||||
case KRITEM_QUADORBINAUT:
|
||||
return KITEM_ORBINAUT;
|
||||
|
||||
case KRITEM_DUALJAWZ:
|
||||
return KITEM_JAWZ;
|
||||
|
||||
default:
|
||||
I_Error("Bad item cooldown redirect for result %d\n", getitem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return getitem;
|
||||
}
|
||||
|
||||
UINT8 K_ItemResultToAmount(SINT8 getitem)
|
||||
{
|
||||
switch (getitem)
|
||||
{
|
||||
case KRITEM_DUALSNEAKER:
|
||||
case KRITEM_DUALJAWZ:
|
||||
return 2;
|
||||
|
||||
case KRITEM_TRIPLESNEAKER:
|
||||
case KRITEM_TRIPLEBANANA:
|
||||
case KRITEM_TRIPLEORBINAUT:
|
||||
return 3;
|
||||
|
||||
case KRITEM_QUADORBINAUT:
|
||||
return 4;
|
||||
|
||||
case KITEM_BALLHOG: // Not a special result, but has a special amount
|
||||
return 5;
|
||||
|
||||
case KRITEM_TENFOLDBANANA:
|
||||
return 10;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
tic_t K_GetItemCooldown(SINT8 itemResult)
|
||||
{
|
||||
SINT8 itemType = K_ItemResultToType(itemResult);
|
||||
|
||||
if (itemType < 1 || itemType >= NUMKARTITEMS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return itemCooldowns[itemType - 1];
|
||||
}
|
||||
|
||||
void K_SetItemCooldown(SINT8 itemResult, tic_t time)
|
||||
{
|
||||
SINT8 itemType = K_ItemResultToType(itemResult);
|
||||
|
||||
if (itemType < 1 || itemType >= NUMKARTITEMS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
itemCooldowns[itemType - 1] = max(itemCooldowns[itemType - 1], time);
|
||||
}
|
||||
|
||||
void K_RunItemCooldowns(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
{
|
||||
if (itemCooldowns[i] > 0)
|
||||
{
|
||||
itemCooldowns[i]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** \brief Item Roulette for Kart
|
||||
|
||||
\param player player
|
||||
|
|
@ -457,70 +561,31 @@ INT32 K_GetShieldFromItem(INT32 item)
|
|||
*/
|
||||
static void K_KartGetItemResult(player_t *player, SINT8 getitem)
|
||||
{
|
||||
if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items
|
||||
indirectitemcooldown = 20*TICRATE;
|
||||
if (getitem == KITEM_SPB || getitem == KITEM_SHRINK)
|
||||
{
|
||||
K_SetItemCooldown(getitem, 20*TICRATE);
|
||||
}
|
||||
|
||||
player->botvars.itemdelay = TICRATE;
|
||||
player->botvars.itemconfirm = 0;
|
||||
|
||||
switch (getitem)
|
||||
{
|
||||
// Special roulettes first, then the generic ones are handled by default
|
||||
case KRITEM_DUALSNEAKER: // Sneaker x2
|
||||
player->itemtype = KITEM_SNEAKER;
|
||||
player->itemamount = 2;
|
||||
break;
|
||||
case KRITEM_TRIPLESNEAKER: // Sneaker x3
|
||||
player->itemtype = KITEM_SNEAKER;
|
||||
player->itemamount = 3;
|
||||
break;
|
||||
case KRITEM_TRIPLEBANANA: // Banana x3
|
||||
player->itemtype = KITEM_BANANA;
|
||||
player->itemamount = 3;
|
||||
break;
|
||||
case KRITEM_TENFOLDBANANA: // Banana x10
|
||||
player->itemtype = KITEM_BANANA;
|
||||
player->itemamount = 10;
|
||||
break;
|
||||
case KRITEM_TRIPLEORBINAUT: // Orbinaut x3
|
||||
player->itemtype = KITEM_ORBINAUT;
|
||||
player->itemamount = 3;
|
||||
break;
|
||||
case KRITEM_QUADORBINAUT: // Orbinaut x4
|
||||
player->itemtype = KITEM_ORBINAUT;
|
||||
player->itemamount = 4;
|
||||
break;
|
||||
case KRITEM_DUALJAWZ: // Jawz x2
|
||||
player->itemtype = KITEM_JAWZ;
|
||||
player->itemamount = 2;
|
||||
break;
|
||||
case KITEM_BALLHOG: // Ballhog x5
|
||||
player->itemtype = KITEM_BALLHOG;
|
||||
player->itemamount = 5;
|
||||
break;
|
||||
default:
|
||||
if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback)
|
||||
{
|
||||
if (getitem != 0)
|
||||
CONS_Printf("ERROR: P_KartGetItemResult - Item roulette gave bad item (%d) :(\n", getitem);
|
||||
player->itemtype = KITEM_SAD;
|
||||
}
|
||||
else
|
||||
player->itemtype = getitem;
|
||||
player->itemamount = 1;
|
||||
break;
|
||||
}
|
||||
player->itemtype = K_ItemResultToType(getitem);
|
||||
player->itemamount = K_ItemResultToAmount(getitem);
|
||||
}
|
||||
|
||||
fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush)
|
||||
fixed_t K_ItemOddsScale(UINT8 playerCount)
|
||||
{
|
||||
const UINT8 basePlayer = 8; // The player count we design most of the game around.
|
||||
UINT8 playerCount = (spbrush ? 2 : numPlayers);
|
||||
fixed_t playerScaling = 0;
|
||||
|
||||
if (playerCount < 2)
|
||||
{
|
||||
// Cap to 1v1 scaling
|
||||
playerCount = 2;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
@ -537,12 +602,12 @@ fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush)
|
|||
return playerScaling;
|
||||
}
|
||||
|
||||
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush)
|
||||
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers)
|
||||
{
|
||||
if (mapobjectscale != FRACUNIT)
|
||||
{
|
||||
// Bring back to normal scale.
|
||||
distance = FixedDiv(distance * FRACUNIT, mapobjectscale) / FRACUNIT;
|
||||
distance = FixedDiv(distance, mapobjectscale);
|
||||
}
|
||||
|
||||
if (franticitems == true)
|
||||
|
|
@ -551,14 +616,11 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush)
|
|||
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;
|
||||
}
|
||||
// Items get crazier with the fewer players that you have.
|
||||
distance = FixedMul(
|
||||
distance,
|
||||
FRACUNIT + (K_ItemOddsScale(numPlayers) / 2)
|
||||
);
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
|
@ -574,20 +636,23 @@ INT32 K_KartGetItemOdds(
|
|||
UINT8 pos, SINT8 item,
|
||||
UINT32 ourDist,
|
||||
fixed_t mashed,
|
||||
boolean spbrush, boolean bot, boolean rival)
|
||||
boolean bot, boolean rival)
|
||||
{
|
||||
INT32 newodds;
|
||||
INT32 i;
|
||||
|
||||
UINT8 pingame = 0, pexiting = 0;
|
||||
|
||||
SINT8 first = -1, second = -1;
|
||||
player_t *first = NULL;
|
||||
player_t *second = NULL;
|
||||
|
||||
UINT32 firstDist = UINT32_MAX;
|
||||
UINT32 secondToFirst = UINT32_MAX;
|
||||
UINT32 secondDist = UINT32_MAX;
|
||||
UINT32 secondToFirst = 0;
|
||||
boolean isFirst = false;
|
||||
|
||||
boolean powerItem = false;
|
||||
boolean cooldownOnStart = false;
|
||||
boolean indirectItem = false;
|
||||
boolean notNearEnd = false;
|
||||
|
||||
INT32 shieldtype = KSHIELD_NONE;
|
||||
|
|
@ -596,7 +661,15 @@ INT32 K_KartGetItemOdds(
|
|||
I_Assert(KartItemCVars[NUMKARTRESULTS-2] != NULL); // Make sure this exists
|
||||
|
||||
if (!KartItemCVars[item-1]->value && !modeattacking)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (K_GetItemCooldown(item) > 0)
|
||||
{
|
||||
// Cooldown is still running, don't give another.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
if (bot)
|
||||
|
|
@ -649,28 +722,32 @@ INT32 K_KartGetItemOdds(
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (players[i].mo && gametype == GT_RACE)
|
||||
if (players[i].position == 1)
|
||||
{
|
||||
if (players[i].position == 1 && first == -1)
|
||||
first = i;
|
||||
if (players[i].position == 2 && second == -1)
|
||||
second = i;
|
||||
first = &players[i];
|
||||
}
|
||||
|
||||
if (players[i].position == 2)
|
||||
{
|
||||
second = &players[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (first != -1 && second != -1) // calculate 2nd's distance from 1st, for SPB
|
||||
if (first != NULL) // calculate 2nd's distance from 1st, for SPB
|
||||
{
|
||||
firstDist = players[first].distancetofinish;
|
||||
firstDist = first->distancetofinish;
|
||||
isFirst = (ourDist <= firstDist);
|
||||
}
|
||||
|
||||
if (mapobjectscale != FRACUNIT)
|
||||
{
|
||||
firstDist = FixedDiv(firstDist * FRACUNIT, mapobjectscale) / FRACUNIT;
|
||||
}
|
||||
if (second != NULL)
|
||||
{
|
||||
secondDist = second->distancetofinish;
|
||||
}
|
||||
|
||||
secondToFirst = K_ScaleItemDistance(
|
||||
players[second].distancetofinish - players[first].distancetofinish,
|
||||
pingame, spbrush
|
||||
);
|
||||
if (first != NULL && second != NULL)
|
||||
{
|
||||
secondToFirst = secondDist - firstDist;
|
||||
secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame); // Reversed scaling, so 16P is like 1v1, and 1v1 is like 16P
|
||||
}
|
||||
|
||||
switch (item)
|
||||
|
|
@ -680,6 +757,7 @@ INT32 K_KartGetItemOdds(
|
|||
case KITEM_SUPERRING:
|
||||
notNearEnd = true;
|
||||
break;
|
||||
|
||||
case KITEM_ROCKETSNEAKER:
|
||||
case KITEM_JAWZ:
|
||||
case KITEM_LANDMINE:
|
||||
|
|
@ -692,11 +770,13 @@ INT32 K_KartGetItemOdds(
|
|||
case KRITEM_DUALJAWZ:
|
||||
powerItem = true;
|
||||
break;
|
||||
|
||||
case KRITEM_TRIPLEBANANA:
|
||||
case KRITEM_TENFOLDBANANA:
|
||||
powerItem = true;
|
||||
notNearEnd = true;
|
||||
break;
|
||||
|
||||
case KITEM_INVINCIBILITY:
|
||||
case KITEM_MINE:
|
||||
case KITEM_GROW:
|
||||
|
|
@ -705,40 +785,46 @@ INT32 K_KartGetItemOdds(
|
|||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
break;
|
||||
|
||||
case KITEM_SPB:
|
||||
cooldownOnStart = true;
|
||||
indirectItem = true;
|
||||
notNearEnd = true;
|
||||
|
||||
if (firstDist < ENDDIST) // No SPB near the end of the race
|
||||
if (firstDist < ENDDIST*2 // No SPB when 1st is almost done
|
||||
|| isFirst == true) // No SPB for 1st ever
|
||||
{
|
||||
newodds = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const INT32 distFromStart = max(0, (INT32)secondToFirst - SPBSTARTDIST);
|
||||
const INT32 distRange = SPBFORCEDIST - SPBSTARTDIST;
|
||||
const INT32 mulMax = 3;
|
||||
|
||||
INT32 multiplier = (distFromStart * mulMax) / distRange;
|
||||
const UINT32 dist = max(0, ((signed)secondToFirst) - SPBSTARTDIST);
|
||||
const UINT32 distRange = SPBFORCEDIST - SPBSTARTDIST;
|
||||
const UINT8 maxOdds = 20;
|
||||
fixed_t multiplier = (dist * FRACUNIT) / distRange;
|
||||
|
||||
if (multiplier < 0)
|
||||
{
|
||||
multiplier = 0;
|
||||
if (multiplier > mulMax)
|
||||
multiplier = mulMax;
|
||||
}
|
||||
|
||||
newodds *= multiplier;
|
||||
if (multiplier > FRACUNIT)
|
||||
{
|
||||
multiplier = FRACUNIT;
|
||||
}
|
||||
|
||||
newodds = FixedMul(maxOdds * 4, multiplier);
|
||||
}
|
||||
break;
|
||||
|
||||
case KITEM_SHRINK:
|
||||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
indirectItem = true;
|
||||
notNearEnd = true;
|
||||
|
||||
if (pingame-1 <= pexiting)
|
||||
newodds = 0;
|
||||
break;
|
||||
|
||||
case KITEM_LIGHTNINGSHIELD:
|
||||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
|
|
@ -746,6 +832,7 @@ INT32 K_KartGetItemOdds(
|
|||
if (spbplace != -1)
|
||||
newodds = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -756,12 +843,8 @@ INT32 K_KartGetItemOdds(
|
|||
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))
|
||||
|
||||
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;
|
||||
|
|
@ -788,7 +871,7 @@ INT32 K_KartGetItemOdds(
|
|||
fracOdds *= 2;
|
||||
}
|
||||
|
||||
fracOdds = FixedMul(fracOdds, FRACUNIT + K_ItemOddsScale(pingame, spbrush));
|
||||
fracOdds = FixedMul(fracOdds, FRACUNIT + K_ItemOddsScale(pingame));
|
||||
|
||||
if (mashed > 0)
|
||||
{
|
||||
|
|
@ -804,7 +887,7 @@ INT32 K_KartGetItemOdds(
|
|||
|
||||
//{ SRB2kart Roulette Code - Distance Based, yes waypoints
|
||||
|
||||
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush)
|
||||
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT8 useodds = 0;
|
||||
|
|
@ -832,7 +915,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum
|
|||
i, j,
|
||||
player->distancetofinish,
|
||||
mashed,
|
||||
spbrush, player->bot, (player->bot && player->botvars.rival)
|
||||
player->bot, (player->bot && player->botvars.rival)
|
||||
) > 0)
|
||||
{
|
||||
available = true;
|
||||
|
|
@ -947,6 +1030,80 @@ INT32 K_GetRollingRouletteItem(player_t *player)
|
|||
return translation[(player->itemroulette % roulette_size) / 3];
|
||||
}
|
||||
|
||||
boolean K_ForcedSPB(player_t *player)
|
||||
{
|
||||
player_t *first = NULL;
|
||||
player_t *second = NULL;
|
||||
UINT32 secondToFirst = UINT32_MAX;
|
||||
UINT8 pingame = 0;
|
||||
UINT8 i;
|
||||
|
||||
if (!cv_selfpropelledbomb.value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_CIRCUIT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player->position <= 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spbplace != -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemCooldowns[KITEM_SPB - 1] > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (players[i].exiting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pingame++;
|
||||
|
||||
if (players[i].position == 1)
|
||||
{
|
||||
first = &players[i];
|
||||
}
|
||||
|
||||
if (players[i].position == 2)
|
||||
{
|
||||
second = &players[i];
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (pingame <= 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (first != NULL && second != NULL)
|
||||
{
|
||||
secondToFirst = second->distancetofinish - first->distancetofinish;
|
||||
secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame);
|
||||
}
|
||||
|
||||
return (secondToFirst >= SPBFORCEDIST);
|
||||
}
|
||||
|
||||
static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
|
||||
{
|
||||
INT32 i;
|
||||
|
|
@ -958,8 +1115,6 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
|
|||
INT32 totalspawnchance = 0;
|
||||
UINT8 bestbumper = 0;
|
||||
fixed_t mashed = 0;
|
||||
boolean dontforcespb = false;
|
||||
boolean spbrush = false;
|
||||
|
||||
// This makes the roulette cycle through items - if this is 0, you shouldn't be here.
|
||||
if (!player->itemroulette)
|
||||
|
|
@ -971,17 +1126,13 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
|
|||
{
|
||||
if (!playeringame[i] || players[i].spectator)
|
||||
continue;
|
||||
|
||||
pingame++;
|
||||
if (players[i].exiting)
|
||||
dontforcespb = true;
|
||||
|
||||
if (players[i].bumpers > bestbumper)
|
||||
bestbumper = players[i].bumpers;
|
||||
}
|
||||
|
||||
// No forced SPB in 1v1s, it has to be randomly rolled
|
||||
if (pingame <= 2)
|
||||
dontforcespb = true;
|
||||
|
||||
// This makes the roulette produce the random noises.
|
||||
if ((player->itemroulette % 3) == 1 && P_IsDisplayPlayer(player) && !demo.freecam)
|
||||
{
|
||||
|
|
@ -1029,14 +1180,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
pdis = K_ScaleItemDistance(pdis, pingame);
|
||||
|
||||
if (player->bot && player->botvars.rival)
|
||||
{
|
||||
|
|
@ -1150,10 +1294,8 @@ 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 > SPBFORCEDIST
|
||||
&& spbplace == -1 && !indirectitemcooldown && !dontforcespb
|
||||
&& cv_selfpropelledbomb.value)
|
||||
// Force SPB if 2nd is way too far behind
|
||||
if (K_ForcedSPB(player) == true)
|
||||
{
|
||||
K_KartGetItemResult(player, KITEM_SPB);
|
||||
player->karthud[khud_itemblink] = TICRATE;
|
||||
|
|
@ -1171,7 +1313,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
|
|||
spawnchance[i] = 0;
|
||||
|
||||
// Split into another function for a debug function below
|
||||
useodds = K_FindUseodds(player, mashed, pdis, bestbumper, spbrush);
|
||||
useodds = K_FindUseodds(player, mashed, pdis, bestbumper);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
|
|
@ -1179,7 +1321,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
|
|||
useodds, i,
|
||||
player->distancetofinish,
|
||||
mashed,
|
||||
spbrush, player->bot, (player->bot && player->botvars.rival))
|
||||
player->bot, (player->bot && player->botvars.rival))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -3230,7 +3372,7 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
|
||||
if (player->startboost) // Startup Boost
|
||||
{
|
||||
ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling/2); // + 100% top speed, + 400% acceleration, +25% handling
|
||||
ADDBOOST(FRACUNIT, 4*FRACUNIT, sliptidehandling); // + 100% top speed, + 400% acceleration, +50% handling
|
||||
}
|
||||
|
||||
if (player->driftboost) // Drift Boost
|
||||
|
|
@ -3258,9 +3400,14 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
ADDBOOST(player->trickboostpower, 5*FRACUNIT, 0); // <trickboostpower>% speed, 500% accel, 0% handling
|
||||
}
|
||||
|
||||
if (player->gateBoost) // SPB Juicebox boost
|
||||
{
|
||||
ADDBOOST(3*FRACUNIT/4, 4*FRACUNIT, sliptidehandling/2); // + 75% top speed, + 400% acceleration, +25% handling
|
||||
}
|
||||
|
||||
if (player->ringboost) // Ring Boost
|
||||
{
|
||||
ADDBOOST(FRACUNIT/5, 4*FRACUNIT, 0); // + 20% top speed, + 400% acceleration, +0% handling
|
||||
ADDBOOST(FRACUNIT/4, 4*FRACUNIT, 0); // + 20% top speed, + 400% acceleration, +0% handling
|
||||
}
|
||||
|
||||
if (player->eggmanexplode) // Ready-to-explode
|
||||
|
|
@ -3858,10 +4005,38 @@ angle_t K_StumbleSlope(angle_t angle, angle_t pitch, angle_t roll)
|
|||
return slope;
|
||||
}
|
||||
|
||||
static void K_StumblePlayer(player_t *player)
|
||||
{
|
||||
P_ResetPlayer(player);
|
||||
|
||||
#if 0
|
||||
// Single, medium bounce
|
||||
player->tumbleBounces = TUMBLEBOUNCES;
|
||||
player->tumbleHeight = 30;
|
||||
#else
|
||||
// Two small bounces
|
||||
player->tumbleBounces = TUMBLEBOUNCES-1;
|
||||
player->tumbleHeight = 20;
|
||||
#endif
|
||||
|
||||
player->pflags &= ~PF_TUMBLESOUND;
|
||||
S_StartSound(player->mo, sfx_s3k9b);
|
||||
|
||||
// and then modulate momz like that...
|
||||
player->mo->momz = K_TumbleZ(player->mo, player->tumbleHeight * FRACUNIT);
|
||||
|
||||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
|
||||
if (P_IsDisplayPlayer(player))
|
||||
P_StartQuake(64<<FRACBITS, 10);
|
||||
|
||||
// Reset slope.
|
||||
player->mo->pitch = player->mo->roll = 0;
|
||||
}
|
||||
|
||||
boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, boolean fromAir)
|
||||
{
|
||||
angle_t steepVal = ANGLE_MAX;
|
||||
fixed_t gravityadjust;
|
||||
angle_t oldSlope, newSlope;
|
||||
angle_t slopeDelta;
|
||||
|
||||
|
|
@ -3911,36 +4086,7 @@ boolean K_CheckStumble(player_t *player, angle_t oldPitch, angle_t oldRoll, bool
|
|||
// Oh jeez, you landed on your side.
|
||||
// You get to tumble.
|
||||
|
||||
P_ResetPlayer(player);
|
||||
|
||||
#if 0
|
||||
// Single, medium bounce
|
||||
player->tumbleBounces = TUMBLEBOUNCES;
|
||||
player->tumbleHeight = 30;
|
||||
#else
|
||||
// Two small bounces
|
||||
player->tumbleBounces = TUMBLEBOUNCES-1;
|
||||
player->tumbleHeight = 20;
|
||||
#endif
|
||||
|
||||
player->pflags &= ~PF_TUMBLESOUND;
|
||||
S_StartSound(player->mo, sfx_s3k9b);
|
||||
|
||||
gravityadjust = P_GetMobjGravity(player->mo)/2; // so we'll halve it for our calculations.
|
||||
|
||||
if (player->mo->eflags & MFE_UNDERWATER)
|
||||
gravityadjust /= 2; // halve "gravity" underwater
|
||||
|
||||
// and then modulate momz like that...
|
||||
player->mo->momz = -gravityadjust * player->tumbleHeight;
|
||||
|
||||
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
|
||||
|
||||
if (P_IsDisplayPlayer(player))
|
||||
P_StartQuake(64<<FRACBITS, 10);
|
||||
|
||||
// Reset slope.
|
||||
player->mo->pitch = player->mo->roll = 0;
|
||||
K_StumblePlayer(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4174,23 +4320,45 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state)
|
|||
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer
|
||||
{
|
||||
INT32 ringburst = 10;
|
||||
fixed_t spbMultiplier = FRACUNIT;
|
||||
|
||||
(void)source;
|
||||
|
||||
K_DirectorFollowAttack(player, inflictor, source);
|
||||
|
||||
player->mo->momz = 18*mapobjectscale*P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!!
|
||||
if (inflictor != NULL && P_MobjWasRemoved(inflictor) == false)
|
||||
{
|
||||
if (inflictor->type == MT_SPBEXPLOSION && inflictor->movefactor)
|
||||
{
|
||||
spbMultiplier = inflictor->movefactor;
|
||||
|
||||
if (spbMultiplier <= 0)
|
||||
{
|
||||
// Convert into stumble.
|
||||
K_StumblePlayer(player);
|
||||
return 0;
|
||||
}
|
||||
else if (spbMultiplier < FRACUNIT)
|
||||
{
|
||||
spbMultiplier = FRACUNIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player->mo->momz = 18 * mapobjectscale * P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!!
|
||||
player->mo->momx = player->mo->momy = 0;
|
||||
|
||||
player->spinouttype = KSPIN_EXPLOSION;
|
||||
player->spinouttimer = (3*TICRATE/2)+2;
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor))
|
||||
if (spbMultiplier != FRACUNIT)
|
||||
{
|
||||
if (inflictor->type == MT_SPBEXPLOSION && inflictor->extravalue1)
|
||||
player->mo->momz = FixedMul(player->mo->momz, spbMultiplier);
|
||||
player->spinouttimer = FixedMul(player->spinouttimer, spbMultiplier + ((spbMultiplier - FRACUNIT) / 2));
|
||||
|
||||
ringburst = FixedMul(ringburst * FRACUNIT, spbMultiplier) / FRACUNIT;
|
||||
if (ringburst > 20)
|
||||
{
|
||||
player->spinouttimer = ((5*player->spinouttimer)/2)+1;
|
||||
player->mo->momz *= 2;
|
||||
ringburst = 20;
|
||||
}
|
||||
}
|
||||
|
|
@ -4760,9 +4928,10 @@ static void K_SpawnDriftElectricity(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
void K_SpawnDriftElectricSparks(player_t *player)
|
||||
void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave)
|
||||
{
|
||||
SINT8 hdir, vdir, i;
|
||||
int shockscale = shockwave ? 2 : 1;
|
||||
|
||||
mobj_t *mo = player->mo;
|
||||
angle_t momangle = K_MomentumAngle(mo) + ANGLE_180;
|
||||
|
|
@ -4772,12 +4941,7 @@ void K_SpawnDriftElectricSparks(player_t *player)
|
|||
fixed_t z = FixedDiv(mo->height, 2 * mo->scale); // P_SpawnMobjFromMobj will rescale
|
||||
|
||||
fixed_t sparkspeed = mobjinfo[MT_DRIFTELECTRICSPARK].speed;
|
||||
fixed_t sparkradius = 2 * mobjinfo[MT_DRIFTELECTRICSPARK].radius;
|
||||
UINT16 color = K_DriftSparkColor(player, player->driftcharge);
|
||||
|
||||
// if the sparks are spawned from first blood rather than drift boost, color will be SKINCOLOR_NONE. ew!
|
||||
if (color == SKINCOLOR_NONE)
|
||||
color = SKINCOLOR_SILVER;
|
||||
fixed_t sparkradius = 2 * shockscale * mobjinfo[MT_DRIFTELECTRICSPARK].radius;
|
||||
|
||||
for (hdir = -1; hdir <= 1; hdir += 2)
|
||||
{
|
||||
|
|
@ -4800,6 +4964,11 @@ void K_SpawnDriftElectricSparks(player_t *player)
|
|||
spark->momx += mo->momx; // copy player speed
|
||||
spark->momy += mo->momy;
|
||||
spark->momz += P_GetMobjZMovement(mo);
|
||||
spark->destscale = shockscale * spark->scale;
|
||||
P_SetScale(spark, shockscale * spark->scale);
|
||||
|
||||
if (shockwave)
|
||||
spark->frame |= FF_ADD;
|
||||
|
||||
sparkangle += ANGLE_90;
|
||||
}
|
||||
|
|
@ -5904,39 +6073,45 @@ void K_DoSneaker(player_t *player, INT32 type)
|
|||
|
||||
static void K_DoShrink(player_t *user)
|
||||
{
|
||||
mobj_t *mobj, *next;
|
||||
|
||||
S_StartSound(user->mo, sfx_kc46); // Sound the BANG!
|
||||
|
||||
Obj_CreateShrinkPohbees(user);
|
||||
|
||||
// kill everything in the kitem list while we're at it:
|
||||
for (mobj = kitemcap; mobj; mobj = next)
|
||||
#if 0
|
||||
{
|
||||
next = mobj->itnext;
|
||||
mobj_t *mobj, *next;
|
||||
|
||||
// check if the item is being held by a player behind us before removing it.
|
||||
// check if the item is a "shield" first, bc i'm p sure thrown items keep the player that threw em as target anyway
|
||||
|
||||
if (mobj->type == MT_BANANA_SHIELD || mobj->type == MT_JAWZ_SHIELD ||
|
||||
mobj->type == MT_SSMINE_SHIELD || mobj->type == MT_EGGMANITEM_SHIELD ||
|
||||
mobj->type == MT_SINK_SHIELD || mobj->type == MT_ORBINAUT_SHIELD ||
|
||||
mobj->type == MT_DROPTARGET_SHIELD)
|
||||
// kill everything in the kitem list while we're at it:
|
||||
for (mobj = kitemcap; mobj; mobj = next)
|
||||
{
|
||||
if (mobj->target && mobj->target->player)
|
||||
next = mobj->itnext;
|
||||
|
||||
if (mobj->type == MT_SPB)
|
||||
{
|
||||
if (mobj->target->player->position > user->position)
|
||||
continue; // this guy's behind us, don't take his stuff away!
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the item is being held by a player behind us before removing it.
|
||||
// check if the item is a "shield" first, bc i'm p sure thrown items keep the player that threw em as target anyway
|
||||
|
||||
if (mobj->type == MT_BANANA_SHIELD || mobj->type == MT_JAWZ_SHIELD ||
|
||||
mobj->type == MT_SSMINE_SHIELD || mobj->type == MT_EGGMANITEM_SHIELD ||
|
||||
mobj->type == MT_SINK_SHIELD || mobj->type == MT_ORBINAUT_SHIELD ||
|
||||
mobj->type == MT_DROPTARGET_SHIELD)
|
||||
{
|
||||
if (mobj->target && mobj->target->player)
|
||||
{
|
||||
if (mobj->target->player->position > user->position)
|
||||
continue; // this guy's behind us, don't take his stuff away!
|
||||
}
|
||||
}
|
||||
|
||||
mobj->destscale = 0;
|
||||
mobj->flags &= ~(MF_SOLID|MF_SHOOTABLE|MF_SPECIAL);
|
||||
mobj->flags |= MF_NOCLIPTHING; // Just for safety
|
||||
}
|
||||
|
||||
mobj->destscale = 0;
|
||||
mobj->flags &= ~(MF_SOLID|MF_SHOOTABLE|MF_SPECIAL);
|
||||
mobj->flags |= MF_NOCLIPTHING; // Just for safety
|
||||
|
||||
if (mobj->type == MT_SPB)
|
||||
spbplace = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound)
|
||||
|
|
@ -6354,8 +6529,7 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
useodds, i,
|
||||
UINT32_MAX,
|
||||
0,
|
||||
false, false, false
|
||||
)
|
||||
false, false)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -6371,46 +6545,8 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
// K_KartGetItemResult requires a player
|
||||
// but item roulette will need rewritten to change this
|
||||
|
||||
switch (i)
|
||||
{
|
||||
// Special roulettes first, then the generic ones are handled by default
|
||||
case KRITEM_DUALSNEAKER: // Sneaker x2
|
||||
newType = KITEM_SNEAKER;
|
||||
newAmount = 2;
|
||||
break;
|
||||
case KRITEM_TRIPLESNEAKER: // Sneaker x3
|
||||
newType = KITEM_SNEAKER;
|
||||
newAmount = 3;
|
||||
break;
|
||||
case KRITEM_TRIPLEBANANA: // Banana x3
|
||||
newType = KITEM_BANANA;
|
||||
newAmount = 3;
|
||||
break;
|
||||
case KRITEM_TENFOLDBANANA: // Banana x10
|
||||
newType = KITEM_BANANA;
|
||||
newAmount = 10;
|
||||
break;
|
||||
case KRITEM_TRIPLEORBINAUT: // Orbinaut x3
|
||||
newType = KITEM_ORBINAUT;
|
||||
newAmount = 3;
|
||||
break;
|
||||
case KRITEM_QUADORBINAUT: // Orbinaut x4
|
||||
newType = KITEM_ORBINAUT;
|
||||
newAmount = 4;
|
||||
break;
|
||||
case KRITEM_DUALJAWZ: // Jawz x2
|
||||
newType = KITEM_JAWZ;
|
||||
newAmount = 2;
|
||||
break;
|
||||
case KITEM_BALLHOG: // Ballhog x5
|
||||
newType = KITEM_BALLHOG;
|
||||
newAmount = 5;
|
||||
break;
|
||||
default:
|
||||
newType = i;
|
||||
newAmount = 1;
|
||||
break;
|
||||
}
|
||||
newType = K_ItemResultToType(i);
|
||||
newAmount = K_ItemResultToAmount(i);
|
||||
|
||||
if (newAmount > 1)
|
||||
{
|
||||
|
|
@ -7596,7 +7732,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
// Speed lines
|
||||
if (player->sneakertimer || player->ringboost
|
||||
|| player->driftboost || player->startboost
|
||||
|| player->eggmanexplode || player->trickboost)
|
||||
|| player->eggmanexplode || player->trickboost
|
||||
|| player->gateBoost)
|
||||
{
|
||||
#if 0
|
||||
if (player->invincibilitytimer)
|
||||
|
|
@ -7846,6 +7983,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
if (player->strongdriftboost)
|
||||
player->strongdriftboost--;
|
||||
|
||||
if (player->gateBoost)
|
||||
player->gateBoost--;
|
||||
|
||||
if (player->startboost > 0 && onground == true)
|
||||
{
|
||||
player->startboost--;
|
||||
|
|
@ -8949,7 +9089,7 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
player->strongdriftboost = 85;
|
||||
|
||||
K_SpawnDriftBoostExplosion(player, 3);
|
||||
K_SpawnDriftElectricSparks(player);
|
||||
K_SpawnDriftElectricSparks(player, K_DriftSparkColor(player, player->driftcharge), false);
|
||||
}
|
||||
else if (player->driftcharge >= dsfour)
|
||||
{
|
||||
|
|
@ -8963,7 +9103,7 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
player->strongdriftboost = 125;
|
||||
|
||||
K_SpawnDriftBoostExplosion(player, 4);
|
||||
K_SpawnDriftElectricSparks(player);
|
||||
K_SpawnDriftElectricSparks(player, K_DriftSparkColor(player, player->driftcharge), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -9320,7 +9460,7 @@ static INT32 K_FlameShieldMax(player_t *player)
|
|||
}
|
||||
|
||||
disttofinish = player->distancetofinish - disttofinish;
|
||||
distv = FixedMul(distv * FRACUNIT, mapobjectscale) / FRACUNIT;
|
||||
distv = FixedMul(distv, mapobjectscale);
|
||||
return min(16, 1 + (disttofinish / distv));
|
||||
}
|
||||
|
||||
|
|
@ -10628,9 +10768,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->pflags &= ~PF_RINGLOCK; // reset ring lock
|
||||
|
||||
if (player->itemtype == KITEM_SPB
|
||||
|| player->itemtype == KITEM_SHRINK
|
||||
|| player->growshrinktimer < 0)
|
||||
indirectitemcooldown = 20*TICRATE;
|
||||
|| player->itemtype == KITEM_SHRINK)
|
||||
{
|
||||
K_SetItemCooldown(player->itemtype, 20*TICRATE);
|
||||
}
|
||||
|
||||
if (player->hyudorotimer > 0)
|
||||
{
|
||||
|
|
|
|||
16
src/k_kart.h
16
src/k_kart.h
|
|
@ -44,12 +44,18 @@ 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);
|
||||
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);
|
||||
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper);
|
||||
fixed_t K_ItemOddsScale(UINT8 numPlayers);
|
||||
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers);
|
||||
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean bot, boolean rival);
|
||||
INT32 K_GetRollingRouletteItem(player_t *player);
|
||||
boolean K_ForcedSPB(player_t *player);
|
||||
INT32 K_GetShieldFromItem(INT32 item);
|
||||
SINT8 K_ItemResultToType(SINT8 getitem);
|
||||
UINT8 K_ItemResultToAmount(SINT8 getitem);
|
||||
tic_t K_GetItemCooldown(SINT8 itemResult);
|
||||
void K_SetItemCooldown(SINT8 itemResult, tic_t time);
|
||||
void K_RunItemCooldowns(void);
|
||||
fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against);
|
||||
boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2);
|
||||
boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj);
|
||||
|
|
@ -119,7 +125,7 @@ INT32 K_GetKartDriftSparkValue(player_t *player);
|
|||
INT32 K_StairJankFlip(INT32 value);
|
||||
INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage);
|
||||
void K_SpawnDriftBoostExplosion(player_t *player, int stage);
|
||||
void K_SpawnDriftElectricSparks(player_t *player);
|
||||
void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave);
|
||||
void K_KartUpdatePosition(player_t *player);
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount);
|
||||
void K_DropItems(player_t *player);
|
||||
|
|
|
|||
|
|
@ -3366,34 +3366,14 @@ void M_DrawItemToggles(void)
|
|||
cv = KartItemCVars[currentMenu->menuitems[thisitem].mvar1-1];
|
||||
translucent = (cv->value ? 0 : V_TRANSLUCENT);
|
||||
|
||||
switch (currentMenu->menuitems[thisitem].mvar1)
|
||||
{
|
||||
case KRITEM_DUALSNEAKER:
|
||||
case KRITEM_DUALJAWZ:
|
||||
drawnum = 2;
|
||||
break;
|
||||
case KRITEM_TRIPLESNEAKER:
|
||||
case KRITEM_TRIPLEBANANA:
|
||||
case KRITEM_TRIPLEORBINAUT:
|
||||
drawnum = 3;
|
||||
break;
|
||||
case KRITEM_QUADORBINAUT:
|
||||
drawnum = 4;
|
||||
break;
|
||||
case KRITEM_TENFOLDBANANA:
|
||||
drawnum = 10;
|
||||
break;
|
||||
default:
|
||||
drawnum = 0;
|
||||
break;
|
||||
}
|
||||
drawnum = K_ItemResultToAmount(currentMenu->menuitems[thisitem].mvar1);
|
||||
|
||||
if (cv->value)
|
||||
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE));
|
||||
else
|
||||
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBGD", PU_CACHE));
|
||||
|
||||
if (drawnum != 0)
|
||||
if (drawnum > 1)
|
||||
{
|
||||
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISMUL", PU_CACHE));
|
||||
V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].mvar1, true), PU_CACHE));
|
||||
|
|
@ -3433,30 +3413,14 @@ void M_DrawItemToggles(void)
|
|||
cv = KartItemCVars[currentMenu->menuitems[itemOn].mvar1-1];
|
||||
translucent = (cv->value ? 0 : V_TRANSLUCENT);
|
||||
|
||||
switch (currentMenu->menuitems[itemOn].mvar1)
|
||||
{
|
||||
case KRITEM_DUALSNEAKER:
|
||||
case KRITEM_DUALJAWZ:
|
||||
drawnum = 2;
|
||||
break;
|
||||
case KRITEM_TRIPLESNEAKER:
|
||||
case KRITEM_TRIPLEBANANA:
|
||||
drawnum = 3;
|
||||
break;
|
||||
case KRITEM_TENFOLDBANANA:
|
||||
drawnum = 10;
|
||||
break;
|
||||
default:
|
||||
drawnum = 0;
|
||||
break;
|
||||
}
|
||||
drawnum = K_ItemResultToAmount(currentMenu->menuitems[itemOn].mvar1);
|
||||
|
||||
if (cv->value)
|
||||
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE));
|
||||
else
|
||||
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBGD", PU_CACHE));
|
||||
|
||||
if (drawnum != 0)
|
||||
if (drawnum > 1)
|
||||
{
|
||||
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITMUL", PU_CACHE));
|
||||
V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].mvar1, false), PU_CACHE));
|
||||
|
|
|
|||
|
|
@ -20,4 +20,13 @@ void Obj_SpawnItemDebrisEffects(mobj_t *collectible, mobj_t *collector);
|
|||
void Obj_ItemDebrisThink(mobj_t *debris);
|
||||
fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz);
|
||||
|
||||
/* SPB */
|
||||
void Obj_SPBThink(mobj_t *spb);
|
||||
void Obj_SPBExplode(mobj_t *spb);
|
||||
void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher);
|
||||
|
||||
/* SPB Juicebox Rings */
|
||||
void Obj_MantaRingThink(mobj_t *manta);
|
||||
mobj_t *Obj_MantaRingCreate(mobj_t *spb, mobj_t *owner, mobj_t *chase);
|
||||
|
||||
#endif/*k_objects_H*/
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ void K_DoIngameRespawn(player_t *player)
|
|||
|
||||
player->ringboost = 0;
|
||||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
|
||||
K_TumbleInterrupt(player);
|
||||
P_ResetPlayer(player);
|
||||
|
|
|
|||
|
|
@ -252,6 +252,10 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->driftboost);
|
||||
else if (fastcmp(field,"strongdriftboost"))
|
||||
lua_pushinteger(L, plr->strongdriftboost);
|
||||
else if (fastcmp(field,"gateBoost"))
|
||||
lua_pushinteger(L, plr->gateBoost);
|
||||
else if (fastcmp(field,"gateSound"))
|
||||
lua_pushinteger(L, plr->gateSound);
|
||||
else if (fastcmp(field,"aizdriftstraft"))
|
||||
lua_pushinteger(L, plr->aizdriftstrat);
|
||||
else if (fastcmp(field,"aizdrifttilt"))
|
||||
|
|
@ -616,6 +620,12 @@ static int player_set(lua_State *L)
|
|||
plr->driftcharge = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"driftboost"))
|
||||
plr->driftboost = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"strongdriftboost"))
|
||||
plr->strongdriftboost = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"gateBoost"))
|
||||
plr->gateBoost = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"gateSound"))
|
||||
plr->gateSound = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"aizdriftstraft"))
|
||||
plr->aizdriftstrat = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"aizdrifttilt"))
|
||||
|
|
|
|||
|
|
@ -375,9 +375,6 @@ int LUA_PushGlobals(lua_State *L, const char *word)
|
|||
} else if (fastcmp(word,"wantedcalcdelay")) {
|
||||
lua_pushinteger(L, wantedcalcdelay);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"indirectitemcooldown")) {
|
||||
lua_pushinteger(L, indirectitemcooldown);
|
||||
return 1;
|
||||
} else if (fastcmp(word,"thwompsactive")) {
|
||||
lua_pushboolean(L, thwompsactive);
|
||||
return 1;
|
||||
|
|
@ -463,8 +460,6 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
|
|||
racecountdown = (tic_t)luaL_checkinteger(L, 2);
|
||||
else if (fastcmp(word,"exitcountdown"))
|
||||
exitcountdown = (tic_t)luaL_checkinteger(L, 2);
|
||||
else if (fastcmp(word,"indirectitemcooldown"))
|
||||
indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2);
|
||||
else
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
hyudoro.c
|
||||
shrink.c
|
||||
item-debris.c
|
||||
spb.c
|
||||
manta-ring.c
|
||||
|
|
|
|||
307
src/objects/manta-ring.c
Normal file
307
src/objects/manta-ring.c
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 2022 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file manta-ring.c
|
||||
/// \brief SPB Juicebox rings. See spb.c for their spawning.
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_main.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../g_game.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../k_waypoint.h"
|
||||
#include "../k_respawn.h"
|
||||
|
||||
#define MANTA_RACETIME (90)
|
||||
#define MANTA_MINTIME (15)
|
||||
#define MANTA_SPRINTTIME (60)
|
||||
|
||||
#define MANTA_ALIVEGATE (0)
|
||||
#define MANTA_DEADGATE (FF_TRANS80)
|
||||
|
||||
#define MANTA_SIZE (2 * FRACUNIT)
|
||||
#define MANTA_SIZEUP (10)
|
||||
#define MANTA_SIZESTRENGTH (1500)
|
||||
#define MANTA_MAXRAMP (80)
|
||||
|
||||
#define MANTA_COLLIDE (80 * FRACUNIT)
|
||||
|
||||
#define MANTA_TURBO (40)
|
||||
#define MANTA_FASTRAMP (17)
|
||||
#define MANTA_MINPWR (10)
|
||||
|
||||
#define manta_delay(o) ((o)->fuse)
|
||||
#define manta_timealive(o) ((o)->movecount)
|
||||
#define manta_boostval(o) ((o)->extravalue1)
|
||||
#define manta_laps(o) ((o)->extravalue2)
|
||||
#define manta_touched(o) ((o)->cusval)
|
||||
|
||||
#define manta_owner(o) ((o)->target)
|
||||
#define manta_chase(o) ((o)->tracer)
|
||||
|
||||
static boolean MantaAlreadyTouched(mobj_t *manta, player_t *player)
|
||||
{
|
||||
INT32 touchFlag = 0;
|
||||
|
||||
if (manta_chase(manta) != NULL && P_MobjWasRemoved(manta_chase(manta)) == false
|
||||
&& player->mo == manta_chase(manta))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (manta_laps(manta) < player->laps)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
touchFlag = 1 << (player - players);
|
||||
return (manta_touched(manta) & touchFlag);
|
||||
}
|
||||
|
||||
static void Obj_MantaCollide(mobj_t *manta, mobj_t *other)
|
||||
{
|
||||
// Could hook this into actual mobj collide if desired.
|
||||
fixed_t distance = INT32_MAX;
|
||||
fixed_t size = INT32_MAX;
|
||||
|
||||
INT32 addBoost = 0;
|
||||
INT32 touchFlag = 0;
|
||||
|
||||
size_t i;
|
||||
|
||||
distance = P_AproxDistance(P_AproxDistance(
|
||||
other->x - manta->x,
|
||||
other->y - manta->y),
|
||||
other->z - manta->z) - other->radius - manta->radius;
|
||||
|
||||
size = FixedMul(MANTA_COLLIDE, mapobjectscale);
|
||||
|
||||
if (distance > size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (other->player != NULL) // Just in case other objects should be added?
|
||||
{
|
||||
if (MantaAlreadyTouched(manta, other->player))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
touchFlag = 1 << (other->player - players);
|
||||
}
|
||||
|
||||
addBoost = manta_boostval(manta);
|
||||
|
||||
if (manta_timealive(manta) < MANTA_FASTRAMP)
|
||||
{
|
||||
// Ramp up to max power.
|
||||
addBoost = FixedMul(addBoost * FRACUNIT, (manta_timealive(manta) * FRACUNIT) / MANTA_FASTRAMP);
|
||||
|
||||
// Convert to integer
|
||||
addBoost = (addBoost + (FRACUNIT/2)) / FRACUNIT;
|
||||
|
||||
// Cap it
|
||||
addBoost = max(MANTA_MINPWR, addBoost);
|
||||
}
|
||||
|
||||
if (other->player != NULL)
|
||||
{
|
||||
UINT8 snd = 0;
|
||||
|
||||
if (other->player->speedboost > FRACUNIT/4)
|
||||
{
|
||||
snd = other->player->gateSound;
|
||||
other->player->gateSound++;
|
||||
|
||||
if (other->player->gateSound > 4)
|
||||
{
|
||||
other->player->gateSound = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other->player->gateSound = 0;
|
||||
}
|
||||
|
||||
K_SpawnDriftBoostExplosion(other->player, 3);
|
||||
K_SpawnDriftElectricSparks(other->player, SKINCOLOR_CRIMSON, true);
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
S_StopSoundByID(other, sfx_gate01 + i);
|
||||
}
|
||||
|
||||
S_StartSound(other, sfx_gate01 + snd);
|
||||
other->player->gateBoost += addBoost/2;
|
||||
|
||||
if (P_IsDisplayPlayer(other->player) == true)
|
||||
{
|
||||
P_StartQuake(12 << FRACBITS, 6);
|
||||
}
|
||||
}
|
||||
|
||||
if (touchFlag > 0)
|
||||
{
|
||||
manta_touched(manta) |= touchFlag;
|
||||
}
|
||||
}
|
||||
|
||||
static void RunMantaCollide(mobj_t *manta)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
// Invalid
|
||||
continue;
|
||||
}
|
||||
|
||||
player = &players[i];
|
||||
if (player->spectator == true)
|
||||
{
|
||||
// Not playing.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
// Invalid object
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->mo == manta_chase(manta))
|
||||
{
|
||||
// Don't allow the person being chased to touch this.
|
||||
continue;
|
||||
}
|
||||
|
||||
Obj_MantaCollide(manta, player->mo);
|
||||
}
|
||||
}
|
||||
|
||||
static void RunMantaVisual(mobj_t *manta)
|
||||
{
|
||||
INT32 i;
|
||||
|
||||
if (manta->fuse < 5*TICRATE)
|
||||
{
|
||||
if (leveltime & 1)
|
||||
{
|
||||
manta->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
manta->renderflags &= ~RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= r_splitscreen; i++)
|
||||
{
|
||||
const UINT8 pID = displayplayers[i];
|
||||
player_t *player = &players[pID];
|
||||
|
||||
if (MantaAlreadyTouched(manta, player) == false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > r_splitscreen)
|
||||
{
|
||||
manta->frame = (manta->frame & ~FF_TRANSMASK) | MANTA_DEADGATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
manta->frame = (manta->frame & ~FF_TRANSMASK) | MANTA_ALIVEGATE;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_MantaRingThink(mobj_t *manta)
|
||||
{
|
||||
RunMantaVisual(manta);
|
||||
|
||||
if (manta_delay(manta) % MANTA_SIZEUP == 0)
|
||||
{
|
||||
manta->destscale += FixedMul(MANTA_SIZESTRENGTH, mapobjectscale);
|
||||
manta_boostval(manta) = min(MANTA_MAXRAMP, manta_boostval(manta) + 1);
|
||||
}
|
||||
|
||||
manta_timealive(manta)++;
|
||||
|
||||
RunMantaCollide(manta);
|
||||
}
|
||||
|
||||
mobj_t *Obj_MantaRingCreate(mobj_t *spb, mobj_t *owner, mobj_t *chase)
|
||||
{
|
||||
mobj_t *manta = NULL;
|
||||
INT32 delay = 0;
|
||||
|
||||
manta = P_SpawnMobjFromMobj(spb, 0, 0, 0, MT_MANTARING);
|
||||
|
||||
manta->color = SKINCOLOR_KETCHUP;
|
||||
|
||||
manta->destscale = FixedMul(MANTA_SIZE, spb->scale);
|
||||
P_SetScale(manta, manta->destscale);
|
||||
|
||||
manta->angle = R_PointToAngle2(0, 0, spb->momx, spb->momy) + ANGLE_90;
|
||||
|
||||
// Set boost value
|
||||
manta_boostval(manta) = MANTA_TURBO;
|
||||
|
||||
// Set despawn delay
|
||||
delay = max(MANTA_MINTIME, MANTA_RACETIME / mapheaderinfo[gamemap - 1]->numlaps);
|
||||
|
||||
if (mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
|
||||
{
|
||||
delay = MANTA_SPRINTTIME;
|
||||
}
|
||||
|
||||
manta_delay(manta) = delay * TICRATE;
|
||||
|
||||
// Default if neither object exists
|
||||
manta_laps(manta) = INT32_MAX;
|
||||
|
||||
// Set owner
|
||||
if (owner != NULL && P_MobjWasRemoved(owner) == false)
|
||||
{
|
||||
P_SetTarget(&manta_owner(manta), owner);
|
||||
|
||||
if (owner->player != NULL)
|
||||
{
|
||||
// Default if chaser doesn't exist
|
||||
manta_laps(manta) = owner->player->laps;
|
||||
}
|
||||
}
|
||||
|
||||
// Set chaser
|
||||
if (chase != NULL && P_MobjWasRemoved(chase) == false)
|
||||
{
|
||||
P_SetTarget(&manta_chase(manta), chase);
|
||||
|
||||
if (chase->player != NULL)
|
||||
{
|
||||
manta_laps(manta) = chase->player->laps;
|
||||
}
|
||||
}
|
||||
|
||||
return manta;
|
||||
}
|
||||
|
|
@ -439,6 +439,8 @@ void Obj_PohbeeThinker(mobj_t *pohbee)
|
|||
{
|
||||
mobj_t *gun = NULL;
|
||||
|
||||
K_SetItemCooldown(KITEM_SHRINK, 20*TICRATE);
|
||||
|
||||
pohbee->momx = pohbee->momy = pohbee->momz = 0;
|
||||
pohbee->spritexscale = pohbee->spriteyscale = 2*FRACUNIT;
|
||||
|
||||
|
|
@ -482,6 +484,8 @@ void Obj_PohbeeRemoved(mobj_t *pohbee)
|
|||
P_RemoveMobj(gun);
|
||||
gun = nextGun;
|
||||
}
|
||||
|
||||
P_SetTarget(&pohbee_guns(pohbee), NULL);
|
||||
}
|
||||
|
||||
void Obj_ShrinkGunRemoved(mobj_t *gun)
|
||||
|
|
@ -493,6 +497,8 @@ void Obj_ShrinkGunRemoved(mobj_t *gun)
|
|||
P_RemoveMobj(gun_laser(gun));
|
||||
}
|
||||
|
||||
P_SetTarget(&gun_laser(gun), NULL);
|
||||
|
||||
chain = gun_chains(gun);
|
||||
while (chain != NULL && P_MobjWasRemoved(chain) == false)
|
||||
{
|
||||
|
|
@ -500,6 +506,8 @@ void Obj_ShrinkGunRemoved(mobj_t *gun)
|
|||
P_RemoveMobj(chain);
|
||||
chain = nextChain;
|
||||
}
|
||||
|
||||
P_SetTarget(&gun_chains(gun), NULL);
|
||||
}
|
||||
|
||||
boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim)
|
||||
|
|
|
|||
1024
src/objects/spb.c
Normal file
1024
src/objects/spb.c
Normal file
File diff suppressed because it is too large
Load diff
511
src/p_enemy.c
511
src/p_enemy.c
|
|
@ -312,7 +312,6 @@ void A_ChangeHeight(mobj_t *actor);
|
|||
void A_ItemPop(mobj_t *actor);
|
||||
void A_JawzChase(mobj_t *actor);
|
||||
void A_JawzExplode(mobj_t *actor);
|
||||
void A_SPBChase(mobj_t *actor);
|
||||
void A_SSMineSearch(mobj_t *actor);
|
||||
void A_SSMineExplode(mobj_t *actor);
|
||||
void A_LandMineExplode(mobj_t *actor);
|
||||
|
|
@ -13370,516 +13369,6 @@ void A_JawzExplode(mobj_t *actor)
|
|||
return;
|
||||
}
|
||||
|
||||
static void SpawnSPBTrailRings(mobj_t *actor)
|
||||
{
|
||||
I_Assert(actor != NULL);
|
||||
|
||||
if (leveltime % 6 == 0)
|
||||
{
|
||||
if (leveltime % (actor->extravalue1 == 2 ? 6 : 3) == 0) // Extravalue1 == 2 is seeking mode. Because the SPB is about twice as fast as normal in that mode, also spawn the rings twice as often to make up for it!
|
||||
{
|
||||
mobj_t *ring = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy,
|
||||
actor->z - actor->momz + (24*mapobjectscale), MT_RING);
|
||||
ring->threshold = 10;
|
||||
ring->fuse = 35*TICRATE;
|
||||
ring->colorized = true;
|
||||
ring->color = SKINCOLOR_RED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spawns the V shaped dust. To be used when the SPB is going mostly forward.
|
||||
static void SpawnSPBDust(mobj_t *mo)
|
||||
{
|
||||
// The easiest way to spawn a V shaped cone of dust from the SPB is simply to spawn 2 particles, and to both move them to the sides in opposite direction.
|
||||
mobj_t *dust;
|
||||
fixed_t sx;
|
||||
fixed_t sy;
|
||||
fixed_t sz = mo->floorz;
|
||||
angle_t sa = mo->angle - ANG1*60;
|
||||
INT32 i;
|
||||
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
sz = mo->ceilingz;
|
||||
|
||||
if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64) // Only ever other frame. Also don't spawn it if we're way above the ground.
|
||||
{
|
||||
// Determine spawning position next to the SPB:
|
||||
for (i=0; i < 2; i++)
|
||||
{
|
||||
sx = mo->x + FixedMul((mo->scale*96), FINECOSINE((sa)>>ANGLETOFINESHIFT));
|
||||
sy = mo->y + FixedMul((mo->scale*96), FINESINE((sa)>>ANGLETOFINESHIFT));
|
||||
|
||||
dust = P_SpawnMobj(sx, sy, sz, MT_SPBDUST);
|
||||
dust->momx = mo->momx/2;
|
||||
dust->momy = mo->momy/2;
|
||||
dust->momz = mo->momz/2; // Give some of the momentum to the dust
|
||||
P_SetScale(dust, mo->scale*2);
|
||||
dust->colorized = true;
|
||||
dust->color = SKINCOLOR_RED;
|
||||
P_InitAngle(dust, mo->angle - FixedAngle(FRACUNIT*90 - FRACUNIT*180*i)); // The first one will spawn to the right of the spb, the second one to the left.
|
||||
P_Thrust(dust, dust->angle, 6*dust->scale);
|
||||
|
||||
K_MatchGenericExtraFlags(dust, mo);
|
||||
|
||||
sa += ANG1*120; // Add 120 degrees to get to mo->angle + ANG1*60
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spawns SPB slip tide. To be used when the SPB is turning.
|
||||
// Modified version of K_SpawnAIZDust. Maybe we could merge those to be cleaner?
|
||||
|
||||
// dir should be either 1 or -1 to determine where to spawn the dust.
|
||||
|
||||
static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir)
|
||||
{
|
||||
fixed_t newx;
|
||||
fixed_t newy;
|
||||
mobj_t *spark;
|
||||
angle_t travelangle;
|
||||
fixed_t sz = mo->floorz;
|
||||
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
sz = mo->ceilingz;
|
||||
|
||||
travelangle = K_MomentumAngle(mo);
|
||||
if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64)
|
||||
{
|
||||
newx = mo->x + P_ReturnThrustX(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale));
|
||||
newy = mo->y + P_ReturnThrustY(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale));
|
||||
spark = P_SpawnMobj(newx, newy, sz, MT_AIZDRIFTSTRAT);
|
||||
spark->colorized = true;
|
||||
spark->color = SKINCOLOR_RED;
|
||||
spark->flags = MF_NOGRAVITY|MF_PAIN;
|
||||
P_SetTarget(&spark->target, mo);
|
||||
|
||||
P_InitAngle(spark, travelangle+(dir*ANGLE_90));
|
||||
P_SetScale(spark, (spark->destscale = mo->scale*3/2));
|
||||
|
||||
spark->momx = (6*mo->momx)/5;
|
||||
spark->momy = (6*mo->momy)/5;
|
||||
|
||||
K_MatchGenericExtraFlags(spark, mo);
|
||||
}
|
||||
}
|
||||
|
||||
// Used for seeking and when SPB is trailing its target from way too close!
|
||||
static void SpawnSPBSpeedLines(mobj_t *actor)
|
||||
{
|
||||
mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale),
|
||||
actor->y + (P_RandomRange(-24,24) * actor->scale),
|
||||
actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale),
|
||||
MT_FASTLINE);
|
||||
|
||||
P_SetTarget(&fast->target, actor);
|
||||
P_InitAngle(fast, K_MomentumAngle(actor));
|
||||
fast->color = SKINCOLOR_RED;
|
||||
fast->colorized = true;
|
||||
K_MatchGenericExtraFlags(fast, actor);
|
||||
}
|
||||
|
||||
|
||||
void A_SPBChase(mobj_t *actor)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
player_t *scplayer = NULL; // secondary target for seeking
|
||||
UINT8 i;
|
||||
UINT8 bestrank = UINT8_MAX;
|
||||
fixed_t dist;
|
||||
angle_t hang, vang;
|
||||
fixed_t wspeed, xyspeed, zspeed;
|
||||
fixed_t pdist = 1536<<FRACBITS; // best player distance when seeking
|
||||
angle_t pangle; // angle between us and the player
|
||||
|
||||
if (LUA_CallAction(A_SPBCHASE, actor))
|
||||
return;
|
||||
|
||||
// Default speed
|
||||
wspeed = FixedMul(mapobjectscale, K_GetKartSpeedFromStat(5)*2); // Go at twice the average speed a player would be going at!
|
||||
|
||||
if (actor->threshold) // Just fired, go straight.
|
||||
{
|
||||
actor->lastlook = -1;
|
||||
actor->cusval = -1;
|
||||
spbplace = -1;
|
||||
P_InstaThrust(actor, actor->angle, wspeed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the player with the best rank
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator || players[i].exiting)
|
||||
continue; // not in-game
|
||||
|
||||
/*if (!players[i].mo)
|
||||
continue; // no mobj
|
||||
|
||||
if (players[i].mo->health <= 0)
|
||||
continue; // dead
|
||||
|
||||
if (players[i].respawn.state != RESPAWNST_NONE)
|
||||
continue;*/ // respawning
|
||||
|
||||
if (players[i].position < bestrank)
|
||||
{
|
||||
bestrank = players[i].position;
|
||||
player = &players[i];
|
||||
}
|
||||
}
|
||||
|
||||
// lastlook = last player num targetted
|
||||
// cvmem = stored speed
|
||||
// cusval = next waypoint heap index
|
||||
// extravalue1 = SPB movement mode
|
||||
// extravalue2 = mode misc option
|
||||
|
||||
if (actor->extravalue1 == 1) // MODE: TARGETING
|
||||
{
|
||||
actor->cusval = -1; // Reset waypoint
|
||||
|
||||
if (actor->tracer && actor->tracer->health)
|
||||
{
|
||||
fixed_t defspeed = wspeed;
|
||||
fixed_t range = (160*actor->tracer->scale);
|
||||
fixed_t cx = 0, cy =0;
|
||||
|
||||
// Play the intimidating gurgle
|
||||
if (!S_SoundPlaying(actor, actor->info->activesound))
|
||||
S_StartSound(actor, actor->info->activesound);
|
||||
|
||||
// Maybe we want SPB to target an object later? IDK lol
|
||||
if (actor->tracer->player)
|
||||
{
|
||||
UINT8 fracmax = 32;
|
||||
UINT8 spark = ((10-actor->tracer->player->kartspeed) + actor->tracer->player->kartweight) / 2;
|
||||
fixed_t easiness = ((actor->tracer->player->kartspeed + (10-spark)) << FRACBITS) / 2;
|
||||
|
||||
actor->lastlook = actor->tracer->player-players; // Save the player num for death scumming...
|
||||
actor->tracer->player->pflags |= PF_RINGLOCK; // set ring lock
|
||||
|
||||
if (actor->tracer->hitlag)
|
||||
{
|
||||
// If the player is frozen through no fault of their own, the SPB should be too.
|
||||
actor->hitlag = actor->tracer->hitlag;
|
||||
}
|
||||
|
||||
if (!P_IsObjectOnGround(actor->tracer))
|
||||
{
|
||||
// In the air you have no control; basically don't hit unless you make a near complete stop
|
||||
defspeed = (7 * actor->tracer->player->speed) / 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 7/8ths max speed for Knuckles, 3/4ths max speed for min accel, exactly max speed for max accel
|
||||
defspeed = FixedMul(((fracmax+1)<<FRACBITS) - easiness, K_GetKartSpeed(actor->tracer->player, false, false)) / fracmax;
|
||||
}
|
||||
|
||||
// Be fairer on conveyors
|
||||
cx = actor->tracer->player->cmomx;
|
||||
cy = actor->tracer->player->cmomy;
|
||||
|
||||
// Switch targets if you're no longer 1st for long enough
|
||||
if (actor->tracer->player->position <= bestrank)
|
||||
actor->extravalue2 = 7*TICRATE;
|
||||
else if (actor->extravalue2-- <= 0)
|
||||
actor->extravalue1 = 0; // back to SEEKING
|
||||
|
||||
spbplace = actor->tracer->player->position;
|
||||
}
|
||||
|
||||
dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z);
|
||||
|
||||
wspeed = FixedMul(defspeed, FRACUNIT + FixedDiv(dist-range, range));
|
||||
if (wspeed < defspeed)
|
||||
wspeed = defspeed;
|
||||
if (wspeed > (3*defspeed)/2)
|
||||
wspeed = (3*defspeed)/2;
|
||||
if (wspeed < 20*actor->tracer->scale)
|
||||
wspeed = 20*actor->tracer->scale;
|
||||
if (actor->tracer->player->carry == CR_SLIDING)
|
||||
wspeed = actor->tracer->player->speed/2;
|
||||
// ^^^^ current section: These are annoying, and grand metropolis in particular needs this.
|
||||
|
||||
hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
|
||||
vang = R_PointToAngle2(0, actor->z, dist, actor->tracer->z);
|
||||
|
||||
// Modify stored speed
|
||||
if (wspeed > actor->cvmem)
|
||||
actor->cvmem += (wspeed - actor->cvmem) / TICRATE;
|
||||
else
|
||||
actor->cvmem = wspeed;
|
||||
|
||||
{
|
||||
// Smoothly rotate horz angle
|
||||
angle_t input = hang - actor->angle;
|
||||
boolean invert = (input > ANGLE_180);
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
// Slow down when turning; it looks better and makes U-turns not unfair
|
||||
xyspeed = FixedMul(actor->cvmem, max(0, (((180<<FRACBITS) - AngleFixed(input)) / 90) - FRACUNIT));
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/4);
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
actor->angle += input;
|
||||
|
||||
// Smoothly rotate vert angle
|
||||
input = vang - actor->movedir;
|
||||
invert = (input > ANGLE_180);
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
// Slow down when turning; might as well do it for momz, since we do it above too
|
||||
zspeed = FixedMul(actor->cvmem, max(0, (((180<<FRACBITS) - AngleFixed(input)) / 90) - FRACUNIT));
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/4);
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
actor->movedir += input;
|
||||
}
|
||||
|
||||
actor->momx = cx + FixedMul(FixedMul(xyspeed, FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
actor->momy = cy + FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
|
||||
// Spawn a trail of rings behind the SPB!
|
||||
SpawnSPBTrailRings(actor);
|
||||
|
||||
// Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed!
|
||||
if (R_PointToDist2(0, 0, actor->momx, actor->momy) > (actor->tracer->player ? (16*actor->tracer->player->speed)/15
|
||||
: (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target
|
||||
&& xyspeed > K_GetKartSpeed(actor->tracer->player, false, false) / 4) // Don't display speedup lines at pitifully low speeds
|
||||
SpawnSPBSpeedLines(actor);
|
||||
|
||||
return;
|
||||
}
|
||||
else // Target's gone, return to SEEKING
|
||||
{
|
||||
P_SetTarget(&actor->tracer, NULL);
|
||||
actor->extravalue1 = 2; // WAIT...
|
||||
actor->extravalue2 = 52; // Slightly over the respawn timer length
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (actor->extravalue1 == 2) // MODE: WAIT...
|
||||
{
|
||||
actor->momx = actor->momy = actor->momz = 0; // Stoooop
|
||||
actor->cusval = -1; // Reset waypoint
|
||||
|
||||
if (actor->lastlook != -1
|
||||
&& playeringame[actor->lastlook]
|
||||
&& !players[actor->lastlook].spectator
|
||||
&& !players[actor->lastlook].exiting)
|
||||
{
|
||||
spbplace = players[actor->lastlook].position;
|
||||
players[actor->lastlook].pflags |= PF_RINGLOCK;
|
||||
if (actor->extravalue2-- <= 0 && players[actor->lastlook].mo)
|
||||
{
|
||||
P_SetTarget(&actor->tracer, players[actor->lastlook].mo);
|
||||
actor->extravalue1 = 1; // TARGET ACQUIRED
|
||||
actor->extravalue2 = 7*TICRATE;
|
||||
actor->cvmem = wspeed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->extravalue1 = 0; // SEEKING
|
||||
actor->extravalue2 = 0;
|
||||
spbplace = -1;
|
||||
}
|
||||
}
|
||||
else // MODE: SEEKING
|
||||
{
|
||||
waypoint_t *lastwaypoint = NULL;
|
||||
waypoint_t *bestwaypoint = NULL;
|
||||
waypoint_t *nextwaypoint = NULL;
|
||||
waypoint_t *tempwaypoint = NULL;
|
||||
|
||||
actor->lastlook = -1; // Just make sure this is reset
|
||||
|
||||
if (!player || !player->mo || player->mo->health <= 0 || (player->respawn.state != RESPAWNST_NONE))
|
||||
{
|
||||
// No one there? Completely STOP.
|
||||
actor->momx = actor->momy = actor->momz = 0;
|
||||
if (!player)
|
||||
spbplace = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Found someone, now get close enough to initiate the slaughter...
|
||||
P_SetTarget(&actor->tracer, player->mo);
|
||||
spbplace = bestrank;
|
||||
dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z);
|
||||
|
||||
/*
|
||||
K_GetBestWaypointForMobj returns the waypoint closest to the object that isn't its current waypoint. While this is usually good enough,
|
||||
in cases where the track overlaps, this means that the SPB will sometimes target a waypoint on an earlier/later portion of the track instead of following along.
|
||||
For this reason, we're going to try and make sure to avoid these situations.
|
||||
*/
|
||||
|
||||
// Move along the waypoints until you get close enough
|
||||
if (actor->cusval > -1 && actor->extravalue2 > 0)
|
||||
{
|
||||
// Previously set nextwaypoint
|
||||
lastwaypoint = K_GetWaypointFromIndex((size_t)actor->cusval);
|
||||
tempwaypoint = K_GetBestWaypointForMobj(actor);
|
||||
// check if the tempwaypoint corresponds to lastwaypoint's next ID at least;
|
||||
// This is to avoid situations where the SPB decides to suicide jump down a bridge because it found a COMPLETELY unrelated waypoint down there.
|
||||
|
||||
if (K_GetWaypointID(tempwaypoint) == K_GetWaypointNextID(lastwaypoint) || K_GetWaypointID(tempwaypoint) == K_GetWaypointID(lastwaypoint))
|
||||
// either our previous or curr waypoint ID, sure, take it
|
||||
bestwaypoint = tempwaypoint;
|
||||
else
|
||||
bestwaypoint = K_GetWaypointFromIndex((size_t)actor->extravalue2); // keep going from the PREVIOUS wp.
|
||||
}
|
||||
else
|
||||
bestwaypoint = K_GetBestWaypointForMobj(actor);
|
||||
|
||||
if (bestwaypoint == NULL && lastwaypoint == NULL)
|
||||
{
|
||||
// We have invalid waypoints all around, so use closest to try and make it non-NULL.
|
||||
bestwaypoint = K_GetClosestWaypointToMobj(actor);
|
||||
}
|
||||
|
||||
if (bestwaypoint != NULL)
|
||||
{
|
||||
const boolean huntbackwards = false;
|
||||
boolean useshortcuts = false;
|
||||
|
||||
// If the player is on a shortcut, use shortcuts. No escape.
|
||||
if (K_GetWaypointIsShortcut(player->nextwaypoint))
|
||||
{
|
||||
useshortcuts = true;
|
||||
}
|
||||
|
||||
nextwaypoint = K_GetNextWaypointToDestination(
|
||||
bestwaypoint, player->nextwaypoint, useshortcuts, huntbackwards);
|
||||
}
|
||||
|
||||
if (nextwaypoint == NULL && lastwaypoint != NULL)
|
||||
{
|
||||
// Restore to the last nextwaypoint
|
||||
nextwaypoint = lastwaypoint;
|
||||
}
|
||||
|
||||
if (nextwaypoint != NULL)
|
||||
{
|
||||
const fixed_t xywaypointdist = P_AproxDistance(
|
||||
actor->x - nextwaypoint->mobj->x, actor->y - nextwaypoint->mobj->y);
|
||||
|
||||
hang = R_PointToAngle2(actor->x, actor->y, nextwaypoint->mobj->x, nextwaypoint->mobj->y);
|
||||
vang = R_PointToAngle2(0, actor->z, xywaypointdist, nextwaypoint->mobj->z);
|
||||
|
||||
actor->cusval = (INT32)K_GetWaypointHeapIndex(nextwaypoint);
|
||||
actor->extravalue2 = (INT32)K_GetWaypointHeapIndex(bestwaypoint); // save our last best, used above.
|
||||
}
|
||||
else
|
||||
{
|
||||
// continue straight ahead... Shouldn't happen.
|
||||
hang = actor->angle;
|
||||
vang = 0U;
|
||||
}
|
||||
|
||||
{
|
||||
// Smoothly rotate horz angle
|
||||
angle_t input = hang - actor->angle;
|
||||
boolean invert = (input > ANGLE_180);
|
||||
INT32 turnangle;
|
||||
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/8);
|
||||
|
||||
// Slow down when turning; it looks better and makes U-turns not unfair
|
||||
xyspeed = FixedMul(wspeed, max(0, (((180<<FRACBITS) - AngleFixed(input)) / 90) - FRACUNIT));
|
||||
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
actor->angle += input;
|
||||
|
||||
// If input is small enough, spawn dust. Otherwise, spawn a slip tide!
|
||||
turnangle = AngleFixed(input)/FRACUNIT;
|
||||
|
||||
// The SPB is really turning if that value is >= 3 and <= 357. This looks pretty bad check-wise so feel free to change it for something that isn't as terrible.
|
||||
if (turnangle >= 3 && turnangle <= 357)
|
||||
SpawnSPBAIZDust(actor, turnangle < 180 ? 1 : -1); // 1 if turning left, -1 if turning right. Angles work counterclockwise, remember!
|
||||
else
|
||||
SpawnSPBDust(actor); // if we're mostly going straight, then spawn the V dust cone!
|
||||
|
||||
SpawnSPBSpeedLines(actor); // Always spawn speed lines while seeking
|
||||
|
||||
// Smoothly rotate vert angle
|
||||
input = vang - actor->movedir;
|
||||
invert = (input > ANGLE_180);
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/8);
|
||||
|
||||
// Slow down when turning; might as well do it for momz, since we do it above too
|
||||
zspeed = FixedMul(wspeed, max(0, (((180<<FRACBITS) - AngleFixed(input)) / 90) - FRACUNIT));
|
||||
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
actor->movedir += input;
|
||||
}
|
||||
|
||||
actor->momx = FixedMul(FixedMul(xyspeed, FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
actor->momy = FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
|
||||
// see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh!
|
||||
for (i=0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator || players[i].exiting)
|
||||
continue; // not in-game
|
||||
|
||||
if (R_PointToDist2(actor->x, actor->y, players[i].mo->x, players[i].mo->y) < pdist)
|
||||
{
|
||||
pdist = R_PointToDist2(actor->x, actor->y, players[i].mo->x, players[i].mo->y);
|
||||
scplayer = &players[i]; // it doesn't matter if we override this guy now.
|
||||
}
|
||||
}
|
||||
|
||||
// different player from our main target, try and ram into em~!
|
||||
if (scplayer && scplayer != player)
|
||||
{
|
||||
pangle = actor->angle - R_PointToAngle2(actor->x, actor->y,scplayer->mo->x, scplayer->mo->y);
|
||||
// check if the angle wouldn't make us LOSE speed...
|
||||
if ((INT32)pangle/ANG1 >= -80 && (INT32)pangle/ANG1 <= 80) // allow for around 80 degrees
|
||||
{
|
||||
// Thrust us towards the guy, try to screw em up!
|
||||
P_Thrust(actor, R_PointToAngle2(actor->x, actor->y, scplayer->mo->x, scplayer->mo->y), actor->movefactor/4); // not too fast though.
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn a trail of rings behind the SPB!
|
||||
SpawnSPBTrailRings(actor);
|
||||
|
||||
if (dist <= (1024*actor->tracer->scale) && !(actor->flags2 & MF2_AMBUSH)) // Close enough to target? Use Ambush flag to disable targetting so I can have an easier time testing stuff...
|
||||
{
|
||||
S_StartSound(actor, actor->info->attacksound);
|
||||
actor->extravalue1 = 1; // TARGET ACQUIRED
|
||||
actor->extravalue2 = 7*TICRATE;
|
||||
actor->cvmem = wspeed;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, no matter what, the spb should not be able to be under the ground, or above the ceiling;
|
||||
if (actor->z < actor->floorz)
|
||||
actor->z = actor->floorz;
|
||||
else if (actor->z > actor->ceilingz - actor->height)
|
||||
actor->z = actor->ceilingz - actor->height;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void A_SSMineSearch(mobj_t *actor)
|
||||
{
|
||||
fixed_t dis = INT32_MAX;
|
||||
|
|
|
|||
|
|
@ -352,41 +352,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
}
|
||||
return;
|
||||
case MT_SPB:
|
||||
if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0))
|
||||
return;
|
||||
|
||||
if (special->health <= 0 || toucher->health <= 0)
|
||||
return;
|
||||
|
||||
if (player->spectator)
|
||||
return;
|
||||
|
||||
if (special->tracer && !P_MobjWasRemoved(special->tracer) && toucher == special->tracer)
|
||||
{
|
||||
mobj_t *spbexplode;
|
||||
|
||||
if (player->bubbleblowup > 0)
|
||||
{
|
||||
K_DropHnextList(player, false);
|
||||
special->extravalue1 = 2; // WAIT...
|
||||
special->extravalue2 = 52; // Slightly over the respawn timer length
|
||||
return;
|
||||
}
|
||||
|
||||
S_StopSound(special); // Don't continue playing the gurgle or the siren
|
||||
|
||||
spbexplode = P_SpawnMobj(toucher->x, toucher->y, toucher->z, MT_SPBEXPLOSION);
|
||||
spbexplode->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback
|
||||
if (special->target && !P_MobjWasRemoved(special->target))
|
||||
P_SetTarget(&spbexplode->target, special->target);
|
||||
|
||||
P_RemoveMobj(special);
|
||||
Obj_SPBTouch(special, toucher);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_DamageMobj(player->mo, special, special->target, 1, DMG_NORMAL);
|
||||
}
|
||||
return;
|
||||
case MT_EMERALD:
|
||||
if (!P_CanPickupItem(player, 0))
|
||||
return;
|
||||
|
|
@ -2060,6 +2029,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
player->sneakertimer = player->numsneakers = 0;
|
||||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
player->ringboost = 0;
|
||||
player->glanceDir = 0;
|
||||
player->pflags &= ~PF_GAINAX;
|
||||
|
|
|
|||
22
src/p_mobj.c
22
src/p_mobj.c
|
|
@ -6661,7 +6661,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
break;
|
||||
case KITEM_SPB:
|
||||
case KITEM_SHRINK:
|
||||
indirectitemcooldown = 20*TICRATE;
|
||||
K_SetItemCooldown(mobj->threshold, 20*TICRATE);
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
mobj->sprite = SPR_ITEM;
|
||||
|
|
@ -6911,8 +6911,15 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
mobj->threshold--;
|
||||
break;
|
||||
case MT_SPB:
|
||||
indirectitemcooldown = 20*TICRATE;
|
||||
/* FALLTHRU */
|
||||
{
|
||||
Obj_SPBThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_MANTARING:
|
||||
{
|
||||
Obj_MantaRingThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BALLHOG:
|
||||
{
|
||||
mobj_t *ghost = P_SpawnGhostMobj(mobj);
|
||||
|
|
@ -9274,6 +9281,11 @@ static boolean P_FuseThink(mobj_t *mobj)
|
|||
P_RemoveMobj(mobj);
|
||||
return false;
|
||||
}
|
||||
case MT_SPB:
|
||||
{
|
||||
Obj_SPBExplode(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_PLAYER:
|
||||
break; // don't remove
|
||||
default:
|
||||
|
|
@ -9310,6 +9322,8 @@ void P_MobjThinker(mobj_t *mobj)
|
|||
P_SetTarget(&mobj->hnext, NULL);
|
||||
if (mobj->hprev && P_MobjWasRemoved(mobj->hprev))
|
||||
P_SetTarget(&mobj->hprev, NULL);
|
||||
if (mobj->itnext && P_MobjWasRemoved(mobj->itnext))
|
||||
P_SetTarget(&mobj->itnext, NULL);
|
||||
|
||||
if (mobj->flags & MF_NOTHINK)
|
||||
return;
|
||||
|
|
@ -10710,6 +10724,8 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
|
||||
P_SetTarget(&mobj->itnext, NULL);
|
||||
|
||||
// DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error.
|
||||
#ifdef SCRAMBLE_REMOVED
|
||||
// Invalidate mobj_t data to cause crashes if accessed!
|
||||
|
|
|
|||
|
|
@ -269,6 +269,9 @@ static void P_NetArchivePlayers(void)
|
|||
WRITEUINT8(save_p, players[i].driftboost);
|
||||
WRITEUINT8(save_p, players[i].strongdriftboost);
|
||||
|
||||
WRITEUINT16(save_p, players[i].gateBoost);
|
||||
WRITEUINT8(save_p, players[i].gateSound);
|
||||
|
||||
WRITESINT8(save_p, players[i].aizdriftstrat);
|
||||
WRITEINT32(save_p, players[i].aizdrifttilt);
|
||||
WRITEINT32(save_p, players[i].aizdriftturn);
|
||||
|
|
@ -563,6 +566,9 @@ static void P_NetUnArchivePlayers(void)
|
|||
players[i].driftboost = READUINT8(save_p);
|
||||
players[i].strongdriftboost = READUINT8(save_p);
|
||||
|
||||
players[i].gateBoost = READUINT16(save_p);
|
||||
players[i].gateSound = READUINT8(save_p);
|
||||
|
||||
players[i].aizdriftstrat = READSINT8(save_p);
|
||||
players[i].aizdrifttilt = READINT32(save_p);
|
||||
players[i].aizdriftturn = READINT32(save_p);
|
||||
|
|
@ -4558,7 +4564,8 @@ static void P_NetArchiveMisc(boolean resending)
|
|||
WRITEFIXED(save_p, battleovertime.z);
|
||||
|
||||
WRITEUINT32(save_p, wantedcalcdelay);
|
||||
WRITEUINT32(save_p, indirectitemcooldown);
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
WRITEUINT32(save_p, itemCooldowns[i]);
|
||||
WRITEUINT32(save_p, mapreset);
|
||||
|
||||
WRITEUINT8(save_p, spectateGriefed);
|
||||
|
|
@ -4721,7 +4728,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
|
|||
battleovertime.z = READFIXED(save_p);
|
||||
|
||||
wantedcalcdelay = READUINT32(save_p);
|
||||
indirectitemcooldown = READUINT32(save_p);
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
itemCooldowns[i] = READUINT32(save_p);
|
||||
mapreset = READUINT32(save_p);
|
||||
|
||||
spectateGriefed = READUINT8(save_p);
|
||||
|
|
|
|||
|
|
@ -4022,6 +4022,8 @@ static void P_InitPlayers(void)
|
|||
|
||||
static void P_InitGametype(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
spectateGriefed = 0;
|
||||
K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped
|
||||
|
||||
|
|
@ -4046,7 +4048,10 @@ static void P_InitGametype(void)
|
|||
}
|
||||
|
||||
wantedcalcdelay = wantedfrequency*2;
|
||||
indirectitemcooldown = 0;
|
||||
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
itemCooldowns[i] = 0;
|
||||
|
||||
mapreset = 0;
|
||||
|
||||
thwompsactive = false;
|
||||
|
|
|
|||
|
|
@ -1925,7 +1925,7 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
player->startboost = 125;
|
||||
|
||||
K_SpawnDriftBoostExplosion(player, 4);
|
||||
K_SpawnDriftElectricSparks(player);
|
||||
K_SpawnDriftElectricSparks(player, SKINCOLOR_SILVER, false);
|
||||
|
||||
rainbowstartavailable = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -683,8 +683,7 @@ void P_Ticker(boolean run)
|
|||
if (exitcountdown > 1)
|
||||
exitcountdown--;
|
||||
|
||||
if (indirectitemcooldown > 0)
|
||||
indirectitemcooldown--;
|
||||
K_RunItemCooldowns();
|
||||
|
||||
K_BossInfoTicker();
|
||||
|
||||
|
|
|
|||
|
|
@ -2592,7 +2592,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
|
|||
if (mo->type == MT_SPB) // If you destroy a SPB, you don't get the luxury of a cooldown.
|
||||
{
|
||||
spbplace = -1;
|
||||
indirectitemcooldown = 0;
|
||||
itemCooldowns[KITEM_SPB - 1] = 0;
|
||||
}
|
||||
|
||||
if (mo->flags & MF_BOSS) //don't OHKO bosses nor players!
|
||||
|
|
|
|||
12
src/sounds.c
12
src/sounds.c
|
|
@ -1118,6 +1118,18 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
// Shrink laser beam
|
||||
{"beam01", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// SPB seeking
|
||||
{"spbska", false, 32, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"spbskb", false, 32, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"spbskc", false, 32, 16, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// Juicebox for SPB
|
||||
{"gate01", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gate02", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gate03", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gate04", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gate05", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// SRB2Kart - Engine sounds
|
||||
// Engine class A
|
||||
{"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
12
src/sounds.h
12
src/sounds.h
|
|
@ -1183,6 +1183,18 @@ typedef enum
|
|||
// Shrink laser
|
||||
sfx_beam01,
|
||||
|
||||
// SPB seeking
|
||||
sfx_spbska,
|
||||
sfx_spbskb,
|
||||
sfx_spbskc,
|
||||
|
||||
// Juicebox for SPB
|
||||
sfx_gate01,
|
||||
sfx_gate02,
|
||||
sfx_gate03,
|
||||
sfx_gate04,
|
||||
sfx_gate05,
|
||||
|
||||
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
|
||||
// Engine class A - Low Speed, Low Weight
|
||||
sfx_krta00,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue