Merge branch 'master' into cheats-streamline

This commit is contained in:
Sally Coolatta 2022-09-24 14:32:15 -04:00
commit a60d48202f
40 changed files with 2293 additions and 1264 deletions

View file

@ -49,15 +49,15 @@ jobs:
paths: paths:
- /var/cache/apt/archives - /var/cache/apt/archives
- checkout - checkout
- run: #- run:
name: Compile without network support # name: Compile without network support
command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1 # command: make -C src LINUX=1 ERRORMODE=1 -k NONET=1
- run: #- run:
name: wipe build # name: wipe build
command: make -C src LINUX=1 cleandep # command: make -C src LINUX=1 cleandep
- run: #- run:
name: rebuild depend # name: rebuild depend
command: make -C src LINUX=1 clean # command: make -C src LINUX=1 clean
- restore_cache: - restore_cache:
keys: keys:
- v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }} - v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}

View file

@ -1036,15 +1036,17 @@ static void COM_Help_f(void)
/** Toggles a console variable. Useful for on/off values. /** Toggles a console variable. Useful for on/off values.
* *
* This works on on/off, yes/no values only * This works on on/off, yes/no values by default. Given
* a list of values, cycles between them.
*/ */
static void COM_Toggle_f(void) static void COM_Toggle_f(void)
{ {
consvar_t *cvar; consvar_t *cvar;
if (COM_Argc() != 2) if (COM_Argc() == 1 || COM_Argc() == 3)
{ {
CONS_Printf(M_GetText("Toggle <cvar_name>: Toggle the value of a cvar\n")); CONS_Printf(M_GetText("Toggle <cvar_name>: Toggle the value of a cvar\n"));
CONS_Printf("Toggle <cvar_name> <value1> <value2>...: Cycle along a set of values\n");
return; return;
} }
cvar = CV_FindVar(COM_Argv(1)); cvar = CV_FindVar(COM_Argv(1));
@ -1054,16 +1056,45 @@ static void COM_Toggle_f(void)
return; return;
} }
if (COM_Argc() == 2)
{
if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff)) if (!(cvar->PossibleValue == CV_YesNo || cvar->PossibleValue == CV_OnOff))
{ {
CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1)); CONS_Alert(CONS_NOTICE, M_GetText("%s is not a boolean value\n"), COM_Argv(1));
return; return;
} }
}
// netcvar don't change imediately // netcvar don't change imediately
cvar->flags |= CV_SHOWMODIFONETIME; cvar->flags |= CV_SHOWMODIFONETIME;
if (COM_Argc() == 2)
{
CV_AddValue(cvar, +1); CV_AddValue(cvar, +1);
} }
else
{
size_t i;
for (i = 2; i < COM_Argc() - 1; ++i)
{
const char *str = COM_Argv(i);
INT32 val;
if (CV_CompleteValue(cvar, &str, &val))
{
if (str ? !stricmp(cvar->string, str)
: cvar->value == val)
{
CV_Set(cvar, COM_Argv(i + 1));
return;
}
}
}
CV_Set(cvar, COM_Argv(2));
}
}
/** Command variant of CV_AddValue /** Command variant of CV_AddValue
*/ */
@ -1436,25 +1467,27 @@ const char *CV_CompleteVar(char *partial, INT32 skips)
return NULL; return NULL;
} }
/** Sets a value to a variable with less checking. Only for internal use. boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval)
*
* \param var Variable to set.
* \param valstr String value for the variable.
*/
static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
{ {
boolean override = false; const char *valstr = *valstrp;
INT32 overrideval = 0; INT32 overrideval = 0;
if ((var->flags & CV_CHEAT) && CV_CheatsEnabled() == false) INT32 v;
if (var == &cv_forceskin)
{ {
// Enforce to default value without cheats. v = R_SkinAvailable(valstr);
valstr = var->defaultvalue;
if (!R_SkinUsable(-1, v))
v = -1;
goto finish;
} }
if (var->PossibleValue) if (var->PossibleValue)
{ {
INT32 v; INT32 i;
if (var->flags & CV_FLOAT) if (var->flags & CV_FLOAT)
{ {
@ -1475,7 +1508,6 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
{ {
#define MINVAL 0 #define MINVAL 0
#define MAXVAL 1 #define MAXVAL 1
INT32 i;
#ifdef PARANOIA #ifdef PARANOIA
if (!var->PossibleValue[MAXVAL].strvalue) if (!var->PossibleValue[MAXVAL].strvalue)
I_Error("Bounded cvar \"%s\" without maximum!\n", var->name); I_Error("Bounded cvar \"%s\" without maximum!\n", var->name);
@ -1484,52 +1516,26 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
// search for other // search for other
for (i = MAXVAL+1; var->PossibleValue[i].strvalue; i++) for (i = MAXVAL+1; var->PossibleValue[i].strvalue; i++)
if (v == var->PossibleValue[i].value || !stricmp(var->PossibleValue[i].strvalue, valstr)) if (v == var->PossibleValue[i].value || !stricmp(var->PossibleValue[i].strvalue, valstr))
{ goto found;
if (client && execversion_enabled)
{
if (var->revert.allocated)
{
Z_Free(var->revert.v.string);
var->revert.allocated = false; // the below value is not allocated in zone memory, don't try to free it!
}
var->revert.v.const_munge = var->PossibleValue[i].strvalue;
return;
}
// free the old value string
Z_Free(var->zstring);
var->zstring = NULL;
var->value = var->PossibleValue[i].value;
var->string = var->PossibleValue[i].strvalue;
goto finish;
}
if ((v != INT32_MIN && v < var->PossibleValue[MINVAL].value) || !stricmp(valstr, "MIN")) if ((v != INT32_MIN && v < var->PossibleValue[MINVAL].value) || !stricmp(valstr, "MIN"))
{ {
v = var->PossibleValue[MINVAL].value; i = MINVAL;
valstr = var->PossibleValue[MINVAL].strvalue; goto found;
override = true;
overrideval = v;
} }
else if ((v != INT32_MIN && v > var->PossibleValue[MAXVAL].value) || !stricmp(valstr, "MAX")) else if ((v != INT32_MIN && v > var->PossibleValue[MAXVAL].value) || !stricmp(valstr, "MAX"))
{ {
v = var->PossibleValue[MAXVAL].value; i = MAXVAL;
valstr = var->PossibleValue[MAXVAL].strvalue; goto found;
override = true;
overrideval = v;
} }
if (v == INT32_MIN) if (v == INT32_MIN)
goto badinput; goto badinput;
valstr = NULL; // not a preset value
#undef MINVAL #undef MINVAL
#undef MAXVAL #undef MAXVAL
} }
else else
{ {
INT32 i;
// check first strings // check first strings
for (i = 0; var->PossibleValue[i].strvalue; i++) for (i = 0; var->PossibleValue[i].strvalue; i++)
if (!stricmp(var->PossibleValue[i].strvalue, valstr)) if (!stricmp(var->PossibleValue[i].strvalue, valstr))
@ -1561,26 +1567,65 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
// ...or not. // ...or not.
goto badinput; goto badinput;
found: found:
if (client && execversion_enabled) v = var->PossibleValue[i].value;
{ valstr = var->PossibleValue[i].strvalue;
var->revert.v.const_munge = var->PossibleValue[i].strvalue;
return;
} }
var->value = var->PossibleValue[i].value; finish:
var->string = var->PossibleValue[i].strvalue; if (intval)
goto finish; *intval = v;
*valstrp = valstr;
return true;
}
// landing point for possiblevalue failures
badinput:
return false;
}
/** Sets a value to a variable with less checking. Only for internal use.
*
* \param var Variable to set.
* \param valstr String value for the variable.
*/
static void Setvalue(consvar_t *var, const char *valstr, boolean stealth)
{
boolean override = false;
INT32 overrideval = 0;
const char *overridestr = valstr;
if ((var->flags & CV_CHEAT) && CV_CheatsEnabled() == false)
{
// Enforce to default value without cheats.
overridestr = var->defaultvalue;
}
else if (CV_CompleteValue(var, &overridestr, &overrideval))
{
if (overridestr)
{
valstr = overridestr;
override = true;
} }
} }
else if (var->PossibleValue)
goto badinput;
if (client && execversion_enabled) if (client && execversion_enabled)
{ {
if (var->revert.allocated) if (var->revert.allocated)
{ {
Z_Free(var->revert.v.string); Z_Free(var->revert.v.string);
// Z_StrDup creates a new zone memory block, so we can keep the allocated flag on // Z_StrDup creates a new zone memory block, so we can keep the allocated flag on
if (override)
var->revert.allocated = false; // the below value is not allocated in zone memory, don't try to free it!
} }
if (override)
var->revert.v.const_munge = valstr;
else
var->revert.v.string = Z_StrDup(valstr); var->revert.v.string = Z_StrDup(valstr);
return; return;
@ -1589,22 +1634,20 @@ found:
// free the old value string // free the old value string
Z_Free(var->zstring); Z_Free(var->zstring);
var->string = var->zstring = Z_StrDup(valstr);
if (override) if (override)
var->value = overrideval;
else if (var->flags & CV_FLOAT)
{ {
double d = atof(var->string); var->zstring = NULL;
var->value = (INT32)(d * FRACUNIT); var->value = overrideval;
var->string = valstr;
} }
else else
{ {
if (var == &cv_forceskin) var->string = var->zstring = Z_StrDup(valstr);
if (var->flags & CV_FLOAT)
{ {
var->value = R_SkinAvailable(var->string); double d = atof(var->string);
if (!R_SkinUsable(-1, var->value)) var->value = (INT32)(d * FRACUNIT);
var->value = -1;
} }
else else
var->value = atoi(var->string); var->value = atoi(var->string);

View file

@ -194,6 +194,12 @@ void CV_ClearChangedFlags(void);
// returns the name of the nearest console variable name found // returns the name of the nearest console variable name found
const char *CV_CompleteVar(char *partial, INT32 skips); const char *CV_CompleteVar(char *partial, INT32 skips);
// Returns true if valstrp is within the PossibleValues of
// var. If an exact string value exists, it is returned in
// valstrp. An integer value is returned in intval if it
// is not NULL.
boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval);
// equivalent to "<varname> <value>" typed at the console // equivalent to "<varname> <value>" typed at the console
void CV_Set(consvar_t *var, const char *value); void CV_Set(consvar_t *var, const char *value);

View file

@ -58,11 +58,11 @@ typedef enum
// //
typedef enum typedef enum
{ {
// True if button down last tic. // free: 1<<0 to 1<<2
PF_ATTACKDOWN = 1,
PF_ACCELDOWN = 1<<1, // Look back VFX has been spawned
PF_BRAKEDOWN = 1<<2, // TODO: Is there a better way to track this?
PF_LOOKDOWN = 1<<3, PF_GAINAX = 1<<3,
// Accessibility and cheats // Accessibility and cheats
PF_KICKSTARTACCEL = 1<<4, // Is accelerate in kickstart mode? PF_KICKSTARTACCEL = 1<<4, // Is accelerate in kickstart mode?
@ -337,6 +337,7 @@ typedef struct player_s
// Caveat: ticcmd_t is ATTRPACK! Be careful what precedes it. // Caveat: ticcmd_t is ATTRPACK! Be careful what precedes it.
ticcmd_t cmd; ticcmd_t cmd;
ticcmd_t oldcmd; // from the previous tic
playerstate_t playerstate; playerstate_t playerstate;
@ -435,6 +436,9 @@ typedef struct player_s
UINT8 driftboost; // (0 to 125) - Boost you get from drifting 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 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 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 aizdrifttilt;
INT32 aizdriftturn; INT32 aizdriftturn;

View file

@ -322,7 +322,6 @@ actionpointer_t actionpointers[] =
{{A_ItemPop}, "A_ITEMPOP"}, {{A_ItemPop}, "A_ITEMPOP"},
{{A_JawzChase}, "A_JAWZCHASE"}, {{A_JawzChase}, "A_JAWZCHASE"},
{{A_JawzExplode}, "A_JAWZEXPLODE"}, {{A_JawzExplode}, "A_JAWZEXPLODE"},
{{A_SPBChase}, "A_SPBCHASE"},
{{A_SSMineSearch}, "A_SSMINESEARCH"}, {{A_SSMineSearch}, "A_SSMINESEARCH"},
{{A_SSMineExplode}, "A_SSMINEEXPLODE"}, {{A_SSMineExplode}, "A_SSMINEEXPLODE"},
{{A_LandMineExplode}, "A_LANDMINEEXPLODE"}, {{A_LandMineExplode}, "A_LANDMINEEXPLODE"},
@ -3652,6 +3651,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_SPB20", "S_SPB20",
"S_SPB_DEAD", "S_SPB_DEAD",
// Juicebox for SPB
"S_MANTA1",
"S_MANTA2",
// Lightning Shield // Lightning Shield
"S_LIGHTNINGSHIELD1", "S_LIGHTNINGSHIELD1",
"S_LIGHTNINGSHIELD2", "S_LIGHTNINGSHIELD2",
@ -5356,6 +5359,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_SPB", // Self-Propelled Bomb "MT_SPB", // Self-Propelled Bomb
"MT_SPBEXPLOSION", "MT_SPBEXPLOSION",
"MT_MANTARING", // Juicebox for SPB
"MT_LIGHTNINGSHIELD", // Shields "MT_LIGHTNINGSHIELD", // Shields
"MT_BUBBLESHIELD", "MT_BUBBLESHIELD",
@ -5725,11 +5729,14 @@ const char *const MAPTHINGFLAG_LIST[4] = {
}; };
const char *const PLAYERFLAG_LIST[] = { const char *const PLAYERFLAG_LIST[] = {
// True if button down last tic. // free: 1<<0 to 1<<2 (name un-matchable)
"ATTACKDOWN", "\x01",
"ACCELDOWN", "\x01",
"BRAKEDOWN", "\x01",
"LOOKDOWN",
// Look back VFX has been spawned
// TODO: Is there a better way to track this?
"GAINAX",
// Accessibility and cheats // Accessibility and cheats
"KICKSTARTACCEL", // Is accelerate in kickstart mode? "KICKSTARTACCEL", // Is accelerate in kickstart mode?

View file

@ -706,7 +706,7 @@ extern boolean comeback;
extern SINT8 battlewanted[4]; extern SINT8 battlewanted[4];
extern tic_t wantedcalcdelay; extern tic_t wantedcalcdelay;
extern tic_t indirectitemcooldown; extern tic_t itemCooldowns[NUMKARTITEMS - 1];
extern tic_t mapreset; extern tic_t mapreset;
extern boolean thwompsactive; extern boolean thwompsactive;
extern UINT8 lastLowestLap; extern UINT8 lastLowestLap;

View file

@ -316,7 +316,7 @@ SINT8 pickedvote; // What vote the host rolls
// Server-sided, synched variables // Server-sided, synched variables
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
tic_t wantedcalcdelay; // Time before it recalculates WANTED 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 tic_t mapreset; // Map reset delay when enough players have joined an empty game
boolean thwompsactive; // Thwomps activate on lap 2 boolean thwompsactive; // Thwomps activate on lap 2
UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors
@ -2428,11 +2428,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
// ^ Not necessary anyway since it will be respawned regardless considering it doesn't exist anymore. // ^ Not necessary anyway since it will be respawned regardless considering it doesn't exist anymore.
// Don't do anything immediately
p->pflags |= PF_BRAKEDOWN;
p->pflags |= PF_ATTACKDOWN;
p->pflags |= PF_ACCELDOWN;
p->playerstate = PST_LIVE; p->playerstate = PST_LIVE;
p->panim = PA_STILL; // standing animation p->panim = PA_STILL; // standing animation

View file

@ -31,6 +31,7 @@
#include "../p_local.h" // stplyr #include "../p_local.h" // stplyr
#include "../g_game.h" // players #include "../g_game.h" // players
#include "../k_hud.h" #include "../k_hud.h"
#include "../r_plane.h" // R_FlatDimensionsFromLumpSize
#include <fcntl.h> #include <fcntl.h>
#include "../i_video.h" // for rendermode != render_glide #include "../i_video.h" // for rendermode != render_glide
@ -482,42 +483,17 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum) void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum)
{ {
FOutVector v[4];
double dflatsize;
INT32 flatflag;
const size_t len = W_LumpLength(flatlumpnum); const size_t len = W_LumpLength(flatlumpnum);
switch (len) size_t sflatsize;
{ double dflatsize;
case 4194304: // 2048x2048 lump INT32 flatflag;
dflatsize = 2048.0f;
flatflag = 2047; FOutVector v[4];
break;
case 1048576: // 1024x1024 lump sflatsize = R_FlatDimensionsFromLumpSize(len);
dflatsize = 1024.0f; dflatsize = (double)sflatsize;
flatflag = 1023; flatflag = sflatsize - 1;
break;
case 262144:// 512x512 lump
dflatsize = 512.0f;
flatflag = 511;
break;
case 65536: // 256x256 lump
dflatsize = 256.0f;
flatflag = 255;
break;
case 16384: // 128x128 lump
dflatsize = 128.0f;
flatflag = 127;
break;
case 1024: // 32x32 lump
dflatsize = 32.0f;
flatflag = 31;
break;
default: // 64x64 lump
dflatsize = 64.0f;
flatflag = 63;
break;
}
// 3--2 // 3--2
// | /| // | /|

View file

@ -46,6 +46,7 @@
// SRB2Kart // SRB2Kart
#include "../k_kart.h" // HITLAGJITTERS #include "../k_kart.h" // HITLAGJITTERS
#include "../r_fps.h" #include "../r_fps.h"
#include "../r_plane.h" // R_FlatDimensionsFromLumpSize
#ifdef NEWCLIP #ifdef NEWCLIP
#include "hw_clip.h" #include "hw_clip.h"
@ -393,31 +394,9 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
if (levelflat->type == LEVELFLAT_FLAT) if (levelflat->type == LEVELFLAT_FLAT)
{ {
size_t len = W_LumpLength(levelflat->u.flat.lumpnum); size_t len = W_LumpLength(levelflat->u.flat.lumpnum);
switch (len) size_t sflatsize = R_FlatDimensionsFromLumpSize(len);
{ fflatwidth = fflatheight = (double)sflatsize;
case 4194304: // 2048x2048 lump flatflag = sflatsize-1;
fflatwidth = fflatheight = 2048.0f;
break;
case 1048576: // 1024x1024 lump
fflatwidth = fflatheight = 1024.0f;
break;
case 262144:// 512x512 lump
fflatwidth = fflatheight = 512.0f;
break;
case 65536: // 256x256 lump
fflatwidth = fflatheight = 256.0f;
break;
case 16384: // 128x128 lump
fflatwidth = fflatheight = 128.0f;
break;
case 1024: // 32x32 lump
fflatwidth = fflatheight = 32.0f;
break;
default: // 64x64 lump
fflatwidth = fflatheight = 64.0f;
break;
}
flatflag = ((INT32)fflatwidth)-1;
} }
else else
{ {
@ -2756,31 +2735,9 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
if (levelflat->type == LEVELFLAT_FLAT) if (levelflat->type == LEVELFLAT_FLAT)
{ {
size_t len = W_LumpLength(levelflat->u.flat.lumpnum); size_t len = W_LumpLength(levelflat->u.flat.lumpnum);
switch (len) size_t sflatsize = R_FlatDimensionsFromLumpSize(len);
{ fflatwidth = fflatheight = (double)sflatsize;
case 4194304: // 2048x2048 lump flatflag = sflatsize-1;
fflatwidth = fflatheight = 2048.0f;
break;
case 1048576: // 1024x1024 lump
fflatwidth = fflatheight = 1024.0f;
break;
case 262144:// 512x512 lump
fflatwidth = fflatheight = 512.0f;
break;
case 65536: // 256x256 lump
fflatwidth = fflatheight = 256.0f;
break;
case 16384: // 128x128 lump
fflatwidth = fflatheight = 128.0f;
break;
case 1024: // 32x32 lump
fflatwidth = fflatheight = 32.0f;
break;
default: // 64x64 lump
fflatwidth = fflatheight = 64.0f;
break;
}
flatflag = ((INT32)fflatwidth)-1;
} }
else else
{ {

View file

@ -565,6 +565,8 @@ char sprnames[NUMSPRITES + 1][5] =
"BHOG", // Ballhog "BHOG", // Ballhog
"BHBM", // Ballhog BOOM "BHBM", // Ballhog BOOM
"SPBM", // Self-Propelled Bomb "SPBM", // Self-Propelled Bomb
"TRIS", // SPB Manta Ring start
"TRNQ", // SPB Manta Ring loop
"THNS", // Lightning Shield "THNS", // Lightning Shield
"BUBS", // Bubble Shield (not Bubs) "BUBS", // Bubble Shield (not Bubs)
"BWVE", // Bubble Shield waves "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|14, 1, {NULL}, 0, 0, S_BALLHOGBOOM16}, // S_BALLHOGBOOM15
{SPR_BHBM, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_NULL}, // S_BALLHOGBOOM16 {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, 0, 1, {NULL}, 0, 0, S_SPB2}, // S_SPB1
{SPR_SPBM, 1, 1, {A_SPBChase}, 0, 0, S_SPB3}, // S_SPB2 {SPR_SPBM, 1, 1, {NULL}, 0, 0, S_SPB3}, // S_SPB2
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB4}, // S_SPB3 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB4}, // S_SPB3
{SPR_SPBM, 2, 1, {A_SPBChase}, 0, 0, S_SPB5}, // S_SPB4 {SPR_SPBM, 2, 1, {NULL}, 0, 0, S_SPB5}, // S_SPB4
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB6}, // S_SPB5 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB6}, // S_SPB5
{SPR_SPBM, 3, 1, {A_SPBChase}, 0, 0, S_SPB7}, // S_SPB6 {SPR_SPBM, 3, 1, {NULL}, 0, 0, S_SPB7}, // S_SPB6
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB8}, // S_SPB7 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB8}, // S_SPB7
{SPR_SPBM, 4, 1, {A_SPBChase}, 0, 0, S_SPB9}, // S_SPB8 {SPR_SPBM, 4, 1, {NULL}, 0, 0, S_SPB9}, // S_SPB8
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB10}, // S_SPB9 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB10}, // S_SPB9
{SPR_SPBM, 5, 1, {A_SPBChase}, 0, 0, S_SPB11}, // S_SPB10 {SPR_SPBM, 5, 1, {NULL}, 0, 0, S_SPB11}, // S_SPB10
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB12}, // S_SPB11 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB12}, // S_SPB11
{SPR_SPBM, 6, 1, {A_SPBChase}, 0, 0, S_SPB13}, // S_SPB12 {SPR_SPBM, 6, 1, {NULL}, 0, 0, S_SPB13}, // S_SPB12
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB14}, // S_SPB13 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB14}, // S_SPB13
{SPR_SPBM, 7, 1, {A_SPBChase}, 0, 0, S_SPB15}, // S_SPB14 {SPR_SPBM, 7, 1, {NULL}, 0, 0, S_SPB15}, // S_SPB14
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB16}, // S_SPB15 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB16}, // S_SPB15
{SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB17}, // S_SPB16 {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB17}, // S_SPB16
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB18}, // S_SPB17 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB18}, // S_SPB17
{SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB19}, // S_SPB18 {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB19}, // S_SPB18
{SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB20}, // S_SPB19 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB20}, // S_SPB19
{SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB1}, // S_SPB20 {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_SPB1}, // S_SPB20
{SPR_SPBM, 8, 175, {NULL}, 0, 0, S_NULL}, // S_SPB_DEAD {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|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|10, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD3}, // S_LIGHTNINGSHIELD2
{SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD4}, // S_LIGHTNINGSHIELD3 {SPR_THNS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_LIGHTNINGSHIELD4}, // S_LIGHTNINGSHIELD3
@ -23906,6 +23911,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate 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 { // MT_LIGHTNINGSHIELD
-1, // doomednum -1, // doomednum
S_LIGHTNINGSHIELD1, // spawnstate S_LIGHTNINGSHIELD1, // spawnstate
@ -28707,10 +28739,10 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
16<<FRACBITS, // radius 16<<FRACBITS, // radius
32<<FRACBITS, // height 32<<FRACBITS, // height
1, // display offset 1, // display offset
100, // mass DMG_NORMAL, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
MF_DONTENCOREMAP|MF_NOGRAVITY|MF_PAIN, // flags MF_NOGRAVITY|MF_PAIN|MF_NOHITLAGFORME|MF_DONTENCOREMAP, // flags
S_NULL // raisestate S_NULL // raisestate
}, },

View file

@ -275,7 +275,6 @@ enum actionnum
A_ITEMPOP, A_ITEMPOP,
A_JAWZCHASE, A_JAWZCHASE,
A_JAWZEXPLODE, A_JAWZEXPLODE,
A_SPBCHASE,
A_SSMINESEARCH, A_SSMINESEARCH,
A_SSMINEEXPLODE, A_SSMINEEXPLODE,
A_LANDMINEEXPLODE, A_LANDMINEEXPLODE,
@ -548,7 +547,6 @@ void A_ChangeHeight();
void A_ItemPop(); void A_ItemPop();
void A_JawzChase(); void A_JawzChase();
void A_JawzExplode(); void A_JawzExplode();
void A_SPBChase();
void A_SSMineSearch(); void A_SSMineSearch();
void A_SSMineExplode(); void A_SSMineExplode();
void A_LandMineExplode(); void A_LandMineExplode();
@ -1113,6 +1111,8 @@ typedef enum sprite
SPR_BHOG, // Ballhog SPR_BHOG, // Ballhog
SPR_BHBM, // Ballhog BOOM SPR_BHBM, // Ballhog BOOM
SPR_SPBM, // Self-Propelled Bomb SPR_SPBM, // Self-Propelled Bomb
SPR_TRIS, // SPB Manta Ring start
SPR_TRNQ, // SPB Manta Ring loop
SPR_THNS, // Thunder Shield SPR_THNS, // Thunder Shield
SPR_BUBS, // Bubble Shield (not Bubs) SPR_BUBS, // Bubble Shield (not Bubs)
SPR_BWVE, // Bubble Shield waves SPR_BWVE, // Bubble Shield waves
@ -4650,6 +4650,10 @@ typedef enum state
S_SPB20, S_SPB20,
S_SPB_DEAD, S_SPB_DEAD,
// Juicebox for SPB
S_MANTA1,
S_MANTA2,
// Thunder Shield // Thunder Shield
S_LIGHTNINGSHIELD1, S_LIGHTNINGSHIELD1,
S_LIGHTNINGSHIELD2, S_LIGHTNINGSHIELD2,
@ -6390,6 +6394,7 @@ typedef enum mobj_type
MT_SPB, // SPB stuff MT_SPB, // SPB stuff
MT_SPBEXPLOSION, MT_SPBEXPLOSION,
MT_MANTARING, // Juicebox for SPB
MT_LIGHTNINGSHIELD, // Shields MT_LIGHTNINGSHIELD, // Shields
MT_BUBBLESHIELD, MT_BUBBLESHIELD,

View file

@ -27,6 +27,23 @@
#include "m_random.h" #include "m_random.h"
#include "r_things.h" // numskins #include "r_things.h" // numskins
/*--------------------------------------------------
static inline boolean K_ItemButtonWasDown(player_t *player)
Looks for players around the bot, and presses the item button
if there is one in range.
Input Arguments:-
player - Bot to check.
Return:-
true if the item button was pressed last tic, otherwise false.
--------------------------------------------------*/
static inline boolean K_ItemButtonWasDown(player_t *player)
{
return (player->oldcmd.buttons & BT_ATTACK);
}
/*-------------------------------------------------- /*--------------------------------------------------
static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius) static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius)
@ -45,7 +62,7 @@ static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t r
{ {
UINT8 i; UINT8 i;
if (player->pflags & PF_ATTACKDOWN) if (K_ItemButtonWasDown(player) == true)
{ {
return false; return false;
} }
@ -327,7 +344,7 @@ static void K_ItemConfirmForTarget(player_t *bot, player_t *target, UINT16 amoun
--------------------------------------------------*/ --------------------------------------------------*/
static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir) static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
{ {
if (player->pflags & PF_ATTACKDOWN) if (K_ItemButtonWasDown(player) == true)
{ {
return false; return false;
} }
@ -352,7 +369,7 @@ static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir)
--------------------------------------------------*/ --------------------------------------------------*/
static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd) static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd)
{ {
if (!(player->pflags & PF_ATTACKDOWN)) if (K_ItemButtonWasDown(player) == false)
{ {
cmd->buttons |= BT_ATTACK; cmd->buttons |= BT_ATTACK;
player->botvars.itemconfirm = 0; player->botvars.itemconfirm = 0;
@ -475,7 +492,7 @@ static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd)
|| player->speedboost > (FRACUNIT/8) // Have another type of boost (tethering) || player->speedboost > (FRACUNIT/8) // Have another type of boost (tethering)
|| player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long || player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long
{ {
if (!player->sneakertimer && !(player->pflags & PF_ATTACKDOWN)) if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false)
{ {
cmd->buttons |= BT_ATTACK; cmd->buttons |= BT_ATTACK;
player->botvars.itemconfirm = 2*TICRATE; player->botvars.itemconfirm = 2*TICRATE;
@ -503,7 +520,7 @@ static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd)
{ {
if (player->botvars.itemconfirm > TICRATE) if (player->botvars.itemconfirm > TICRATE)
{ {
if (!player->sneakertimer && !(player->pflags & PF_ATTACKDOWN)) if (player->sneakertimer == 0 && K_ItemButtonWasDown(player) == false)
{ {
cmd->buttons |= BT_ATTACK; cmd->buttons |= BT_ATTACK;
player->botvars.itemconfirm = 0; player->botvars.itemconfirm = 0;
@ -1193,7 +1210,7 @@ static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd)
{ {
boolean mash = false; boolean mash = false;
if (player->pflags & PF_ATTACKDOWN) if (K_ItemButtonWasDown(player) == true)
{ {
return; return;
} }

View file

@ -695,7 +695,7 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
} }
} }
static patch_t **K_GetItemPatchTable(INT32 item) static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset)
{ {
patch_t **kp[1 + NUMKARTITEMS] = { patch_t **kp[1 + NUMKARTITEMS] = {
kp_sadface, kp_sadface,
@ -723,8 +723,8 @@ static patch_t **K_GetItemPatchTable(INT32 item)
kp_droptarget, kp_droptarget,
}; };
if (item >= KITEM_SAD && item < NUMKARTITEMS) if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS))
return kp[item - KITEM_SAD]; return kp[item - KITEM_SAD][offset];
else else
return NULL; return NULL;
} }
@ -1146,7 +1146,7 @@ static void K_drawKartItem(void)
break; break;
default: default:
localpatch = K_GetItemPatchTable(item)[offset]; localpatch = K_GetCachedItemPatch(item, offset);
} }
} }
else else
@ -1224,7 +1224,7 @@ static void K_drawKartItem(void)
/*FALLTHRU*/ /*FALLTHRU*/
default: default:
localpatch = K_GetItemPatchTable(stplyr->itemtype)[offset]; localpatch = K_GetCachedItemPatch(stplyr->itemtype, offset);
if (localpatch == NULL) if (localpatch == NULL)
localpatch = kp_nodraw; // diagnose underflows localpatch = kp_nodraw; // diagnose underflows
@ -4445,7 +4445,6 @@ static void K_drawDistributionDebugger(void)
kp_jawz[1], kp_jawz[1],
kp_mine[1], kp_mine[1],
kp_landmine[1], kp_landmine[1],
kp_droptarget[1],
kp_ballhog[1], kp_ballhog[1],
kp_selfpropelledbomb[1], kp_selfpropelledbomb[1],
kp_grow[1], kp_grow[1],
@ -4457,6 +4456,7 @@ static void K_drawDistributionDebugger(void)
kp_pogospring[1], kp_pogospring[1],
kp_superring[1], kp_superring[1],
kp_kitchensink[1], kp_kitchensink[1],
kp_droptarget[1],
kp_sneaker[1], kp_sneaker[1],
kp_sneaker[1], kp_sneaker[1],
@ -4471,11 +4471,17 @@ static void K_drawDistributionDebugger(void)
UINT32 pdis = 0; UINT32 pdis = 0;
INT32 i; INT32 i;
INT32 x = -9, y = -9; INT32 x = -9, y = -9;
boolean spbrush = false;
if (stplyr != &players[displayplayers[0]]) // only for p1 if (stplyr != &players[displayplayers[0]]) // only for p1
return; 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 // The only code duplication from the Kart, just to avoid the actual item function from calculating pingame twice
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
@ -4498,14 +4504,7 @@ static void K_drawDistributionDebugger(void)
} }
} }
if (spbplace != -1 && stplyr->position == spbplace+1) pdis = K_ScaleItemDistance(pdis, pingame);
{
// SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell
pdis = (3 * pdis) / 2;
spbrush = true;
}
pdis = K_ScaleItemDistance(pdis, pingame, spbrush);
if (stplyr->bot && stplyr->botvars.rival) if (stplyr->bot && stplyr->botvars.rival)
{ {
@ -4513,7 +4512,7 @@ static void K_drawDistributionDebugger(void)
pdis = (15 * pdis) / 14; 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++) for (i = 1; i < NUMKARTRESULTS; i++)
{ {
@ -4521,38 +4520,21 @@ static void K_drawDistributionDebugger(void)
useodds, i, useodds, i,
stplyr->distancetofinish, stplyr->distancetofinish,
0, 0,
spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival) stplyr->bot, (stplyr->bot && stplyr->botvars.rival)
); );
INT32 amount = 1;
if (itemodds <= 0) if (itemodds <= 0)
continue; continue;
V_DrawScaledPatch(x, y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, items[i]); V_DrawScaledPatch(x, y, V_SNAPTOTOP, items[i]);
V_DrawThinString(x+11, y+31, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, va("%d", itemodds)); V_DrawThinString(x+11, y+31, V_SNAPTOTOP, va("%d", itemodds));
// Display amount for multi-items // Display amount for multi-items
if (i >= NUMKARTITEMS) amount = K_ItemResultToAmount(i);
if (amount > 1)
{ {
INT32 amount; V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("x%d", 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));
} }
x += 32; 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) static void K_drawCheckpointDebugger(void)

File diff suppressed because it is too large Load diff

View file

@ -44,12 +44,18 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value);
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1]; extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
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);
fixed_t K_ItemOddsScale(UINT8 numPlayers, boolean spbrush); fixed_t K_ItemOddsScale(UINT8 numPlayers);
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush); UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival); INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean bot, boolean rival);
INT32 K_GetRollingRouletteItem(player_t *player); INT32 K_GetRollingRouletteItem(player_t *player);
boolean K_ForcedSPB(player_t *player);
INT32 K_GetShieldFromItem(INT32 item); 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); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against);
boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2);
boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); 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_StairJankFlip(INT32 value);
INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage); INT32 K_GetKartDriftSparkValueForStage(player_t *player, UINT8 stage);
void K_SpawnDriftBoostExplosion(player_t *player, int 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); 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); 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); void K_DropItems(player_t *player);

View file

@ -536,7 +536,7 @@ extern struct menutransition_s {
extern boolean menuwipe; extern boolean menuwipe;
extern consvar_t cv_showfocuslost; extern consvar_t cv_showfocuslost;
extern consvar_t cv_chooseskin, cv_serversort; extern consvar_t cv_chooseskin, cv_serversort, cv_menujam_update;
void M_SetMenuDelay(UINT8 i); void M_SetMenuDelay(UINT8 i);

View file

@ -3366,34 +3366,14 @@ void M_DrawItemToggles(void)
cv = KartItemCVars[currentMenu->menuitems[thisitem].mvar1-1]; cv = KartItemCVars[currentMenu->menuitems[thisitem].mvar1-1];
translucent = (cv->value ? 0 : V_TRANSLUCENT); translucent = (cv->value ? 0 : V_TRANSLUCENT);
switch (currentMenu->menuitems[thisitem].mvar1) drawnum = K_ItemResultToAmount(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;
}
if (cv->value) if (cv->value)
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE)); V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE));
else else
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBGD", PU_CACHE)); 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, 0, W_CachePatchName("K_ISMUL", PU_CACHE));
V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].mvar1, true), 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]; cv = KartItemCVars[currentMenu->menuitems[itemOn].mvar1-1];
translucent = (cv->value ? 0 : V_TRANSLUCENT); translucent = (cv->value ? 0 : V_TRANSLUCENT);
switch (currentMenu->menuitems[itemOn].mvar1) drawnum = K_ItemResultToAmount(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;
}
if (cv->value) if (cv->value)
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE)); V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE));
else else
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBGD", PU_CACHE)); 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, 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)); V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].mvar1, false), PU_CACHE));

View file

@ -143,6 +143,10 @@ consvar_t cv_showfocuslost = CVAR_INIT ("showfocuslost", "Yes", CV_SAVE, CV_YesN
static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}}; static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}};
consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDDEN, skins_cons_t, NULL); consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDDEN, skins_cons_t, NULL);
consvar_t cv_menujam_update = CVAR_INIT ("menujam_update", "Off", CV_SAVE, CV_OnOff, NULL);
static CV_PossibleValue_t menujam_cons_t[] = {{0, "menu"}, {1, "menu2"}, {2, "menu3"}, {0, NULL}};
static consvar_t cv_menujam = CVAR_INIT ("menujam", "0", CV_SAVE, menujam_cons_t, NULL);
// This gametype list is integral for many different reasons. // This gametype list is integral for many different reasons.
// When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h! // When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h!
CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1]; CV_PossibleValue_t gametype_cons_t[NUMGAMETYPES+1];
@ -945,7 +949,13 @@ void M_StartControlPanel(void)
paused = false; paused = false;
CON_ToggleOff(); CON_ToggleOff();
S_ChangeMusicInternal("menu", true); if (cv_menujam_update.value)
{
CV_AddValue(&cv_menujam, 1);
CV_SetValue(&cv_menujam_update, 0);
}
S_ChangeMusicInternal(cv_menujam.string, true);
} }
menuactive = true; menuactive = true;
@ -1686,6 +1696,14 @@ void M_Init(void)
CV_RegisterVar(&cv_chooseskin); CV_RegisterVar(&cv_chooseskin);
CV_RegisterVar(&cv_autorecord); CV_RegisterVar(&cv_autorecord);
// don't lose your position in the jam cycle
CV_RegisterVar(&cv_menujam_update);
CV_RegisterVar(&cv_menujam);
#ifndef NONET
CV_RegisterVar(&cv_serversort);
#endif
if (dedicated) if (dedicated)
return; return;
@ -1712,20 +1730,6 @@ void M_Init(void)
CV_RegisterVar(&cv_dummyaddonsearch); CV_RegisterVar(&cv_dummyaddonsearch);
M_UpdateMenuBGImage(true); M_UpdateMenuBGImage(true);
#if 0
#ifdef HWRENDER
// Permanently hide some options based on render mode
if (rendermode == render_soft)
OP_VideoOptionsMenu[op_video_ogl].status =
OP_VideoOptionsMenu[op_video_kartman].status =
OP_VideoOptionsMenu[op_video_md2] .status = IT_DISABLED;
#endif
#endif
#ifndef NONET
CV_RegisterVar(&cv_serversort);
#endif
} }
// ================================================== // ==================================================

View file

@ -20,4 +20,13 @@ void Obj_SpawnItemDebrisEffects(mobj_t *collectible, mobj_t *collector);
void Obj_ItemDebrisThink(mobj_t *debris); void Obj_ItemDebrisThink(mobj_t *debris);
fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz); 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*/ #endif/*k_objects_H*/

View file

@ -151,6 +151,7 @@ void K_DoIngameRespawn(player_t *player)
player->ringboost = 0; player->ringboost = 0;
player->driftboost = player->strongdriftboost = 0; player->driftboost = player->strongdriftboost = 0;
player->gateBoost = 0;
K_TumbleInterrupt(player); K_TumbleInterrupt(player);
P_ResetPlayer(player); P_ResetPlayer(player);

View file

@ -192,6 +192,8 @@ static int player_get(lua_State *L)
LUA_PushUserdata(L, plr->mo, META_MOBJ); LUA_PushUserdata(L, plr->mo, META_MOBJ);
else if (fastcmp(field,"cmd")) else if (fastcmp(field,"cmd"))
LUA_PushUserdata(L, &plr->cmd, META_TICCMD); LUA_PushUserdata(L, &plr->cmd, META_TICCMD);
else if (fastcmp(field,"oldcmd"))
LUA_PushUserdata(L, &plr->oldcmd, META_TICCMD);
else if (fastcmp(field,"respawn")) else if (fastcmp(field,"respawn"))
LUA_PushUserdata(L, &plr->respawn, META_RESPAWN); LUA_PushUserdata(L, &plr->respawn, META_RESPAWN);
else if (fastcmp(field,"playerstate")) else if (fastcmp(field,"playerstate"))
@ -250,6 +252,10 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->driftboost); lua_pushinteger(L, plr->driftboost);
else if (fastcmp(field,"strongdriftboost")) else if (fastcmp(field,"strongdriftboost"))
lua_pushinteger(L, plr->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")) else if (fastcmp(field,"aizdriftstraft"))
lua_pushinteger(L, plr->aizdriftstrat); lua_pushinteger(L, plr->aizdriftstrat);
else if (fastcmp(field,"aizdrifttilt")) else if (fastcmp(field,"aizdrifttilt"))
@ -526,6 +532,8 @@ static int player_set(lua_State *L)
} }
else if (fastcmp(field,"cmd")) else if (fastcmp(field,"cmd"))
return NOSET; return NOSET;
else if (fastcmp(field,"oldcmd"))
return NOSET;
else if (fastcmp(field,"respawn")) else if (fastcmp(field,"respawn"))
return NOSET; return NOSET;
else if (fastcmp(field,"playerstate")) else if (fastcmp(field,"playerstate"))
@ -612,6 +620,12 @@ static int player_set(lua_State *L)
plr->driftcharge = luaL_checkinteger(L, 3); plr->driftcharge = luaL_checkinteger(L, 3);
else if (fastcmp(field,"driftboost")) else if (fastcmp(field,"driftboost"))
plr->driftboost = luaL_checkinteger(L, 3); 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")) else if (fastcmp(field,"aizdriftstraft"))
plr->aizdriftstrat = luaL_checkinteger(L, 3); plr->aizdriftstrat = luaL_checkinteger(L, 3);
else if (fastcmp(field,"aizdrifttilt")) else if (fastcmp(field,"aizdrifttilt"))

View file

@ -375,9 +375,6 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"wantedcalcdelay")) { } else if (fastcmp(word,"wantedcalcdelay")) {
lua_pushinteger(L, wantedcalcdelay); lua_pushinteger(L, wantedcalcdelay);
return 1; return 1;
} else if (fastcmp(word,"indirectitemcooldown")) {
lua_pushinteger(L, indirectitemcooldown);
return 1;
} else if (fastcmp(word,"thwompsactive")) { } else if (fastcmp(word,"thwompsactive")) {
lua_pushboolean(L, thwompsactive); lua_pushboolean(L, thwompsactive);
return 1; return 1;
@ -463,8 +460,6 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
racecountdown = (tic_t)luaL_checkinteger(L, 2); racecountdown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"exitcountdown")) else if (fastcmp(word,"exitcountdown"))
exitcountdown = (tic_t)luaL_checkinteger(L, 2); exitcountdown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"indirectitemcooldown"))
indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2);
else else
return 0; return 0;

View file

@ -1043,11 +1043,11 @@ void OP_ObjectplaceMovement(player_t *player)
} }
if (player->pflags & PF_ATTACKDOWN) if (player->pflags & PF_STASIS)
{ {
// Are ANY objectplace buttons pressed? If no, remove flag. // Are ANY objectplace buttons pressed? If no, remove flag.
if (!(cmd->buttons & (BT_ATTACK|BT_DRIFT))) if (!(cmd->buttons & (BT_ATTACK|BT_DRIFT)))
player->pflags &= ~PF_ATTACKDOWN; player->pflags &= ~PF_STASIS;
// Do nothing. // Do nothing.
return; return;
@ -1056,12 +1056,12 @@ void OP_ObjectplaceMovement(player_t *player)
/*if (cmd->buttons & BT_FORWARD) /*if (cmd->buttons & BT_FORWARD)
{ {
OP_CycleThings(-1); OP_CycleThings(-1);
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_STASIS;
} }
else*/ if (cmd->buttons & BT_DRIFT) else*/ if (cmd->buttons & BT_DRIFT)
{ {
OP_CycleThings(1); OP_CycleThings(1);
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_STASIS;
} }
// Place an object and add it to the maplist // Place an object and add it to the maplist
@ -1072,7 +1072,7 @@ void OP_ObjectplaceMovement(player_t *player)
mobjtype_t spawnthing = op_currentdoomednum; mobjtype_t spawnthing = op_currentdoomednum;
boolean ceiling; boolean ceiling;
player->pflags |= PF_ATTACKDOWN; player->pflags |= PF_STASIS;
if (cv_mapthingnum.value > 0 && cv_mapthingnum.value < 4096) if (cv_mapthingnum.value > 0 && cv_mapthingnum.value < 4096)
{ {

View file

@ -1,3 +1,5 @@
hyudoro.c hyudoro.c
shrink.c shrink.c
item-debris.c item-debris.c
spb.c
manta-ring.c

307
src/objects/manta-ring.c Normal file
View 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;
}

View file

@ -439,6 +439,8 @@ void Obj_PohbeeThinker(mobj_t *pohbee)
{ {
mobj_t *gun = NULL; mobj_t *gun = NULL;
K_SetItemCooldown(KITEM_SHRINK, 20*TICRATE);
pohbee->momx = pohbee->momy = pohbee->momz = 0; pohbee->momx = pohbee->momy = pohbee->momz = 0;
pohbee->spritexscale = pohbee->spriteyscale = 2*FRACUNIT; pohbee->spritexscale = pohbee->spriteyscale = 2*FRACUNIT;
@ -482,6 +484,8 @@ void Obj_PohbeeRemoved(mobj_t *pohbee)
P_RemoveMobj(gun); P_RemoveMobj(gun);
gun = nextGun; gun = nextGun;
} }
P_SetTarget(&pohbee_guns(pohbee), NULL);
} }
void Obj_ShrinkGunRemoved(mobj_t *gun) void Obj_ShrinkGunRemoved(mobj_t *gun)
@ -493,6 +497,8 @@ void Obj_ShrinkGunRemoved(mobj_t *gun)
P_RemoveMobj(gun_laser(gun)); P_RemoveMobj(gun_laser(gun));
} }
P_SetTarget(&gun_laser(gun), NULL);
chain = gun_chains(gun); chain = gun_chains(gun);
while (chain != NULL && P_MobjWasRemoved(chain) == false) while (chain != NULL && P_MobjWasRemoved(chain) == false)
{ {
@ -500,6 +506,8 @@ void Obj_ShrinkGunRemoved(mobj_t *gun)
P_RemoveMobj(chain); P_RemoveMobj(chain);
chain = nextChain; chain = nextChain;
} }
P_SetTarget(&gun_chains(gun), NULL);
} }
boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim) boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim)

1024
src/objects/spb.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -312,7 +312,6 @@ void A_ChangeHeight(mobj_t *actor);
void A_ItemPop(mobj_t *actor); void A_ItemPop(mobj_t *actor);
void A_JawzChase(mobj_t *actor); void A_JawzChase(mobj_t *actor);
void A_JawzExplode(mobj_t *actor); void A_JawzExplode(mobj_t *actor);
void A_SPBChase(mobj_t *actor);
void A_SSMineSearch(mobj_t *actor); void A_SSMineSearch(mobj_t *actor);
void A_SSMineExplode(mobj_t *actor); void A_SSMineExplode(mobj_t *actor);
void A_LandMineExplode(mobj_t *actor); void A_LandMineExplode(mobj_t *actor);
@ -13210,7 +13209,6 @@ void A_ItemPop(mobj_t *actor)
void A_JawzChase(mobj_t *actor) void A_JawzChase(mobj_t *actor)
{ {
const fixed_t currentspeed = R_PointToDist2(0, 0, actor->momx, actor->momy);
player_t *player; player_t *player;
fixed_t thrustamount = 0; fixed_t thrustamount = 0;
fixed_t frictionsafety = (actor->friction == 0) ? 1 : actor->friction; fixed_t frictionsafety = (actor->friction == 0) ? 1 : actor->friction;
@ -13295,12 +13293,15 @@ void A_JawzChase(mobj_t *actor)
P_SetTarget(&actor->tracer, NULL); P_SetTarget(&actor->tracer, NULL);
} }
if (!P_IsObjectOnGround(actor)) if (!actor->tracer)
{ {
// No friction in the air actor->angle = K_MomentumAngle(actor);
frictionsafety = FRACUNIT;
} }
if (P_IsObjectOnGround(actor))
{
const fixed_t currentspeed = R_PointToDist2(0, 0, actor->momx, actor->momy);
if (currentspeed >= topspeed) if (currentspeed >= topspeed)
{ {
// Thrust as if you were at top speed, slow down naturally // Thrust as if you were at top speed, slow down naturally
@ -13313,12 +13314,8 @@ void A_JawzChase(mobj_t *actor)
thrustamount = beatfriction + FixedDiv(topspeed - currentspeed, frictionsafety); thrustamount = beatfriction + FixedDiv(topspeed - currentspeed, frictionsafety);
} }
if (!actor->tracer)
{
actor->angle = K_MomentumAngle(actor);
}
P_Thrust(actor, actor->angle, thrustamount); P_Thrust(actor, actor->angle, thrustamount);
}
if ((actor->tracer != NULL) && (actor->tracer->health > 0)) if ((actor->tracer != NULL) && (actor->tracer->health > 0))
return; return;
@ -13372,516 +13369,6 @@ void A_JawzExplode(mobj_t *actor)
return; 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) void A_SSMineSearch(mobj_t *actor)
{ {
fixed_t dis = INT32_MAX; fixed_t dis = INT32_MAX;

View file

@ -352,41 +352,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
return; return;
case MT_SPB: 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; Obj_SPBTouch(special, toucher);
if (player->bubbleblowup > 0)
{
K_DropHnextList(player, false);
special->extravalue1 = 2; // WAIT...
special->extravalue2 = 52; // Slightly over the respawn timer length
return; 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);
}
else
{
P_DamageMobj(player->mo, special, special->target, 1, DMG_NORMAL);
}
return;
case MT_EMERALD: case MT_EMERALD:
if (!P_CanPickupItem(player, 0)) if (!P_CanPickupItem(player, 0))
return; return;
@ -2060,9 +2029,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player->sneakertimer = player->numsneakers = 0; player->sneakertimer = player->numsneakers = 0;
player->driftboost = player->strongdriftboost = 0; player->driftboost = player->strongdriftboost = 0;
player->gateBoost = 0;
player->ringboost = 0; player->ringboost = 0;
player->glanceDir = 0; player->glanceDir = 0;
player->pflags &= ~PF_LOOKDOWN; player->pflags &= ~PF_GAINAX;
switch (type) switch (type)
{ {

View file

@ -1594,21 +1594,7 @@ void P_XYMovement(mobj_t *mo)
else if (P_MobjWasRemoved(mo)) else if (P_MobjWasRemoved(mo))
return; return;
//{ SRB2kart - Jawz if (mo->flags & MF_MISSILE)
if (mo->type == MT_JAWZ || mo->type == MT_JAWZ_DUD)
{
if (mo->health == 1)
{
// This Item Damage
S_StartSound(mo, mo->info->deathsound);
P_KillMobj(mo, NULL, NULL, DMG_NORMAL);
P_SetObjectMomZ(mo, 8*FRACUNIT, false);
P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT);
}
}
//}
else if (mo->flags & MF_MISSILE)
{ {
// explode a missile // explode a missile
if (P_CheckSkyHit(mo)) if (P_CheckSkyHit(mo))
@ -1671,7 +1657,7 @@ void P_XYMovement(mobj_t *mo)
{ {
boolean walltransferred = false; boolean walltransferred = false;
if (player || mo->flags & MF_SLIDEME) //if (player || mo->flags & MF_SLIDEME)
{ // try to slide along it { // try to slide along it
// Wall transfer part 1. // Wall transfer part 1.
pslope_t *transferslope = NULL; pslope_t *transferslope = NULL;
@ -1745,15 +1731,20 @@ void P_XYMovement(mobj_t *mo)
fx->scale = mo->scale; fx->scale = mo->scale;
} }
if (mo->type == MT_ORBINAUT) // Orbinaut speed decreasing switch (mo->type)
{ {
case MT_ORBINAUT: // Orbinaut speed decreasing
if (mo->health > 1) if (mo->health > 1)
{ {
S_StartSound(mo, mo->info->attacksound); S_StartSound(mo, mo->info->attacksound);
mo->health--; mo->health--;
mo->threshold = 0; mo->threshold = 0;
} }
else if (mo->health == 1) /*FALLTHRU*/
case MT_JAWZ:
case MT_JAWZ_DUD:
if (mo->health == 1)
{ {
// This Item Damage // This Item Damage
S_StartSound(mo, mo->info->deathsound); S_StartSound(mo, mo->info->deathsound);
@ -1762,6 +1753,10 @@ void P_XYMovement(mobj_t *mo)
P_SetObjectMomZ(mo, 8*FRACUNIT, false); P_SetObjectMomZ(mo, 8*FRACUNIT, false);
P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT); P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT);
} }
break;
default:
break;
} }
// Bubble bounce // Bubble bounce
@ -6666,7 +6661,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
break; break;
case KITEM_SPB: case KITEM_SPB:
case KITEM_SHRINK: case KITEM_SHRINK:
indirectitemcooldown = 20*TICRATE; K_SetItemCooldown(mobj->threshold, 20*TICRATE);
/* FALLTHRU */ /* FALLTHRU */
default: default:
mobj->sprite = SPR_ITEM; mobj->sprite = SPR_ITEM;
@ -6738,13 +6733,18 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
} }
} }
else else
{
mobj_t *ghost = P_SpawnGhostMobj(mobj);
ghost->colorized = true; // already has color!
mobj->angle = K_MomentumAngle(mobj);
if (P_IsObjectOnGround(mobj))
{ {
fixed_t finalspeed = mobj->movefactor; fixed_t finalspeed = mobj->movefactor;
const fixed_t currentspeed = R_PointToDist2(0, 0, mobj->momx, mobj->momy); const fixed_t currentspeed = R_PointToDist2(0, 0, mobj->momx, mobj->momy);
fixed_t thrustamount = 0; fixed_t thrustamount = 0;
fixed_t frictionsafety = (mobj->friction == 0) ? 1 : mobj->friction; fixed_t frictionsafety = (mobj->friction == 0) ? 1 : mobj->friction;
mobj_t *ghost = P_SpawnGhostMobj(mobj);
ghost->colorized = true; // already has color!
if (!grounded) if (!grounded)
{ {
@ -6752,7 +6752,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
frictionsafety = FRACUNIT; frictionsafety = FRACUNIT;
} }
mobj->angle = K_MomentumAngle(mobj);
if (mobj->health <= 5) if (mobj->health <= 5)
{ {
INT32 i; INT32 i;
@ -6773,6 +6772,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
} }
P_Thrust(mobj, mobj->angle, thrustamount); P_Thrust(mobj, mobj->angle, thrustamount);
}
if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true)) if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true))
K_DoPogoSpring(mobj, 0, 1); K_DoPogoSpring(mobj, 0, 1);
@ -6911,8 +6911,15 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->threshold--; mobj->threshold--;
break; break;
case MT_SPB: case MT_SPB:
indirectitemcooldown = 20*TICRATE; {
/* FALLTHRU */ Obj_SPBThink(mobj);
break;
}
case MT_MANTARING:
{
Obj_MantaRingThink(mobj);
break;
}
case MT_BALLHOG: case MT_BALLHOG:
{ {
mobj_t *ghost = P_SpawnGhostMobj(mobj); mobj_t *ghost = P_SpawnGhostMobj(mobj);
@ -9274,6 +9281,11 @@ static boolean P_FuseThink(mobj_t *mobj)
P_RemoveMobj(mobj); P_RemoveMobj(mobj);
return false; return false;
} }
case MT_SPB:
{
Obj_SPBExplode(mobj);
break;
}
case MT_PLAYER: case MT_PLAYER:
break; // don't remove break; // don't remove
default: default:
@ -9310,6 +9322,8 @@ void P_MobjThinker(mobj_t *mobj)
P_SetTarget(&mobj->hnext, NULL); P_SetTarget(&mobj->hnext, NULL);
if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) if (mobj->hprev && P_MobjWasRemoved(mobj->hprev))
P_SetTarget(&mobj->hprev, NULL); P_SetTarget(&mobj->hprev, NULL);
if (mobj->itnext && P_MobjWasRemoved(mobj->itnext))
P_SetTarget(&mobj->itnext, NULL);
if (mobj->flags & MF_NOTHINK) if (mobj->flags & MF_NOTHINK)
return; 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. // DBG: set everything in mobj_t to 0xFF instead of leaving it. debug memory error.
#ifdef SCRAMBLE_REMOVED #ifdef SCRAMBLE_REMOVED
// Invalidate mobj_t data to cause crashes if accessed! // Invalidate mobj_t data to cause crashes if accessed!

View file

@ -269,6 +269,9 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].driftboost); WRITEUINT8(save_p, players[i].driftboost);
WRITEUINT8(save_p, players[i].strongdriftboost); WRITEUINT8(save_p, players[i].strongdriftboost);
WRITEUINT16(save_p, players[i].gateBoost);
WRITEUINT8(save_p, players[i].gateSound);
WRITESINT8(save_p, players[i].aizdriftstrat); WRITESINT8(save_p, players[i].aizdriftstrat);
WRITEINT32(save_p, players[i].aizdrifttilt); WRITEINT32(save_p, players[i].aizdrifttilt);
WRITEINT32(save_p, players[i].aizdriftturn); WRITEINT32(save_p, players[i].aizdriftturn);
@ -563,6 +566,9 @@ static void P_NetUnArchivePlayers(void)
players[i].driftboost = READUINT8(save_p); players[i].driftboost = READUINT8(save_p);
players[i].strongdriftboost = 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].aizdriftstrat = READSINT8(save_p);
players[i].aizdrifttilt = READINT32(save_p); players[i].aizdrifttilt = READINT32(save_p);
players[i].aizdriftturn = READINT32(save_p); players[i].aizdriftturn = READINT32(save_p);
@ -4558,7 +4564,8 @@ static void P_NetArchiveMisc(boolean resending)
WRITEFIXED(save_p, battleovertime.z); WRITEFIXED(save_p, battleovertime.z);
WRITEUINT32(save_p, wantedcalcdelay); WRITEUINT32(save_p, wantedcalcdelay);
WRITEUINT32(save_p, indirectitemcooldown); for (i = 0; i < NUMKARTITEMS-1; i++)
WRITEUINT32(save_p, itemCooldowns[i]);
WRITEUINT32(save_p, mapreset); WRITEUINT32(save_p, mapreset);
WRITEUINT8(save_p, spectateGriefed); WRITEUINT8(save_p, spectateGriefed);
@ -4721,7 +4728,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
battleovertime.z = READFIXED(save_p); battleovertime.z = READFIXED(save_p);
wantedcalcdelay = READUINT32(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); mapreset = READUINT32(save_p);
spectateGriefed = READUINT8(save_p); spectateGriefed = READUINT8(save_p);

View file

@ -4022,6 +4022,8 @@ static void P_InitPlayers(void)
static void P_InitGametype(void) static void P_InitGametype(void)
{ {
size_t i;
spectateGriefed = 0; spectateGriefed = 0;
K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped
@ -4046,7 +4048,10 @@ static void P_InitGametype(void)
} }
wantedcalcdelay = wantedfrequency*2; wantedcalcdelay = wantedfrequency*2;
indirectitemcooldown = 0;
for (i = 0; i < NUMKARTITEMS-1; i++)
itemCooldowns[i] = 0;
mapreset = 0; mapreset = 0;
thwompsactive = false; thwompsactive = false;
@ -4074,6 +4079,9 @@ static void P_InitGametype(void)
G_RecordDemo(buf); G_RecordDemo(buf);
} }
// Started a game? Move on to the next jam when you go back to the title screen
CV_SetValue(&cv_menujam_update, 1);
} }
/** Loads a level from a lump or external wad. /** Loads a level from a lump or external wad.

View file

@ -1925,7 +1925,7 @@ static void K_HandleLapIncrement(player_t *player)
player->startboost = 125; player->startboost = 125;
K_SpawnDriftBoostExplosion(player, 4); K_SpawnDriftBoostExplosion(player, 4);
K_SpawnDriftElectricSparks(player); K_SpawnDriftElectricSparks(player, SKINCOLOR_SILVER, false);
rainbowstartavailable = false; rainbowstartavailable = false;
} }

View file

@ -683,8 +683,7 @@ void P_Ticker(boolean run)
if (exitcountdown > 1) if (exitcountdown > 1)
exitcountdown--; exitcountdown--;
if (indirectitemcooldown > 0) K_RunItemCooldowns();
indirectitemcooldown--;
K_BossInfoTicker(); K_BossInfoTicker();
@ -768,6 +767,11 @@ void P_Ticker(boolean run)
K_TimerInit(); K_TimerInit();
} }
for (i = 0; i < MAXPLAYERS; i++)
{
G_CopyTiccmd(&players[i].oldcmd, &players[i].cmd, 1);
}
// Z_CheckMemCleanup(); // Z_CheckMemCleanup();
} }

View file

@ -2218,7 +2218,7 @@ void P_MovePlayer(player_t *player)
player->drawangle -= ANGLE_22h; player->drawangle -= ANGLE_22h;
player->mo->rollangle = 0; player->mo->rollangle = 0;
player->glanceDir = 0; player->glanceDir = 0;
player->pflags &= ~PF_LOOKDOWN; player->pflags &= ~PF_GAINAX;
} }
else if ((player->pflags & PF_FAULT) || (player->spinouttimer > 0)) else if ((player->pflags & PF_FAULT) || (player->spinouttimer > 0))
{ {
@ -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. if (mo->type == MT_SPB) // If you destroy a SPB, you don't get the luxury of a cooldown.
{ {
spbplace = -1; spbplace = -1;
indirectitemcooldown = 0; itemCooldowns[KITEM_SPB - 1] = 0;
} }
if (mo->flags & MF_BOSS) //don't OHKO bosses nor players! if (mo->flags & MF_BOSS) //don't OHKO bosses nor players!
@ -4186,7 +4186,7 @@ void P_PlayerThink(player_t *player)
} }
else if (cmd->buttons & BT_ACCELERATE) else if (cmd->buttons & BT_ACCELERATE)
{ {
if (!player->exiting && !(player->pflags & PF_ACCELDOWN)) if (!player->exiting && !(player->oldcmd.buttons & BT_ACCELERATE))
{ {
player->kickstartaccel = 0; player->kickstartaccel = 0;
} }
@ -4394,19 +4394,6 @@ void P_PlayerThink(player_t *player)
P_DoBubbleBreath(player); // Spawn Sonic's bubbles P_DoBubbleBreath(player); // Spawn Sonic's bubbles
P_CheckInvincibilityTimer(player); // Spawn Invincibility Sparkles P_CheckInvincibilityTimer(player); // Spawn Invincibility Sparkles
// check for buttons
if (cmd->buttons & BT_ACCELERATE)
player->pflags |= PF_ACCELDOWN;
else
player->pflags &= ~PF_ACCELDOWN;
if (cmd->buttons & BT_BRAKE)
player->pflags |= PF_BRAKEDOWN;
else
player->pflags &= ~PF_BRAKEDOWN;
// PF_LOOKDOWN handled in K_KartMoveAnimation
// Counters, time dependent power ups. // Counters, time dependent power ups.
// Time Bonus & Ring Bonus count settings // Time Bonus & Ring Bonus count settings

View file

@ -89,6 +89,7 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop);
void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop);
void R_PlaneBounds(visplane_t *plane); void R_PlaneBounds(visplane_t *plane);
size_t R_FlatDimensionsFromLumpSize(size_t size);
void R_CheckFlatLength(size_t size); void R_CheckFlatLength(size_t size);
boolean R_CheckPowersOfTwo(void); boolean R_CheckPowersOfTwo(void);

View file

@ -656,6 +656,44 @@ boolean R_CheckPowersOfTwo(void)
return ds_powersoftwo; return ds_powersoftwo;
} }
//
// R_FlatDimensionsFromLumpSize
//
// Returns the flat's square size from its lump length.
//
size_t R_FlatDimensionsFromLumpSize(size_t size)
{
switch (size)
{
case 4194304: // 2048x2048 lump
return 2048;
case 1048576: // 1024x1024 lump
return 1024;
case 262144:// 512x512 lump
return 512;
case 65536: // 256x256 lump
return 256;
case 16384: // 128x128 lump
return 128;
case 1024: // 32x32 lump
return 32;
case 256: // 16x16 lump
return 16;
case 64: // 8x8 lump
return 8;
default: // 64x64 lump
return 64;
}
}
// //
// R_CheckFlatLength // R_CheckFlatLength
// //
@ -707,6 +745,20 @@ void R_CheckFlatLength(size_t size)
nflatshiftup = 11; nflatshiftup = 11;
ds_flatwidth = ds_flatheight = 32; ds_flatwidth = ds_flatheight = 32;
break; break;
case 256: // 16x16 lump
nflatmask = 0xF0;
nflatxshift = 28;
nflatyshift = 24;
nflatshiftup = 12;
ds_flatwidth = ds_flatheight = 16;
break;
case 64: // 8x8 lump
nflatmask = 0x38;
nflatxshift = 29;
nflatyshift = 26;
nflatshiftup = 13;
ds_flatwidth = ds_flatheight = 8;
break;
default: // 64x64 lump default: // 64x64 lump
nflatmask = 0xFC0; nflatmask = 0xFC0;
nflatxshift = 26; nflatxshift = 26;
@ -774,30 +826,7 @@ Rloadflats (INT32 i, INT32 w)
W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0); W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0);
lumplength = W_LumpLengthPwad(wadnum, lumpnum); lumplength = W_LumpLengthPwad(wadnum, lumpnum);
switch (lumplength) flatsize = R_FlatDimensionsFromLumpSize(lumplength);
{
case 4194304: // 2048x2048 lump
flatsize = 2048;
break;
case 1048576: // 1024x1024 lump
flatsize = 1024;
break;
case 262144:// 512x512 lump
flatsize = 512;
break;
case 65536: // 256x256 lump
flatsize = 256;
break;
case 16384: // 128x128 lump
flatsize = 128;
break;
case 1024: // 32x32 lump
flatsize = 32;
break;
default: // 64x64 lump
flatsize = 64;
break;
}
//CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize); //CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize);
texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);

View file

@ -1118,6 +1118,18 @@ sfxinfo_t S_sfx[NUMSFX] =
// Shrink laser beam // Shrink laser beam
{"beam01", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"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 // SRB2Kart - Engine sounds
// Engine class A // Engine class A
{"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""},

View file

@ -1183,6 +1183,18 @@ typedef enum
// Shrink laser // Shrink laser
sfx_beam01, 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... // Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
// Engine class A - Low Speed, Low Weight // Engine class A - Low Speed, Low Weight
sfx_krta00, sfx_krta00,

View file

@ -1236,19 +1236,19 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum)
{ {
case 4194304: // 2048x2048 lump case 4194304: // 2048x2048 lump
lflatsize = 2048; lflatsize = 2048;
flatshift = 10; flatshift = 11;
break; break;
case 1048576: // 1024x1024 lump case 1048576: // 1024x1024 lump
lflatsize = 1024; lflatsize = 1024;
flatshift = 9; flatshift = 10;
break; break;
case 262144:// 512x512 lump case 262144:// 512x512 lump
lflatsize = 512; lflatsize = 512;
flatshift = 8; flatshift = 9;
break; break;
case 65536: // 256x256 lump case 65536: // 256x256 lump
lflatsize = 256; lflatsize = 256;
flatshift = 7; flatshift = 8;
break; break;
case 16384: // 128x128 lump case 16384: // 128x128 lump
lflatsize = 128; lflatsize = 128;
@ -1258,6 +1258,14 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum)
lflatsize = 32; lflatsize = 32;
flatshift = 5; flatshift = 5;
break; break;
case 256: // 16x16 lump
lflatsize = 16;
flatshift = 4;
break;
case 64: // 8x8 lump
lflatsize = 8;
flatshift = 3;
break;
default: // 64x64 lump default: // 64x64 lump
lflatsize = 64; lflatsize = 64;
flatshift = 6; flatshift = 6;