Merge branch 'master' into waypoints-disable

This commit is contained in:
Sally Coolatta 2021-02-12 20:28:16 -05:00
commit 1849f70359
37 changed files with 2189 additions and 278 deletions

View file

@ -170,6 +170,7 @@ set(SRB2_CORE_GAME_SOURCES
p_telept.c
p_tick.c
p_user.c
k_race.c
k_battle.c
k_bheap.c
k_collide.c
@ -195,6 +196,7 @@ set(SRB2_CORE_GAME_SOURCES
p_slopes.h
p_spec.h
p_tick.h
k_race.h
k_battle.h
k_bheap.h
k_collide.h

View file

@ -558,6 +558,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/k_respawn.o\
$(OBJDIR)/k_collide.o\
$(OBJDIR)/k_color.o \
$(OBJDIR)/k_race.o \
$(OBJDIR)/k_battle.o \
$(OBJDIR)/k_pwrlv.o \
$(OBJDIR)/k_waypoint.o\

View file

@ -616,6 +616,9 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->kartstuff[j] = LONG(players[i].kartstuff[j]);
rsp->airtime = (tic_t)LONG(players[i].airtime);
rsp->driftInput = players[i].driftInput;
rsp->airFailsafe = players[i].airFailsafe;
rsp->trickpanel = (UINT8)players[i].trickpanel;
rsp->trickdelay = (boolean)players[i].trickdelay;
rsp->trickmomx = (fixed_t)LONG(players[i].trickmomx);
@ -631,6 +634,8 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->tumbleLastBounce = players[i].tumbleLastBounce;
rsp->tumbleSound = players[i].tumbleSound;
rsp->glanceDir = players[i].glanceDir;
// respawnvars_t
rsp->respawn_state = players[i].respawn.state;
rsp->respawn_pointx = (fixed_t)LONG(players[i].respawn.pointx);
@ -774,6 +779,9 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].kartstuff[j] = LONG(rsp->kartstuff[j]);
players[i].airtime = (tic_t)LONG(rsp->airtime);
players[i].driftInput = (boolean)rsp->driftInput;
players[i].airFailsafe = (boolean)rsp->airFailsafe;
players[i].trickpanel = (UINT8)rsp->trickpanel;
players[i].trickdelay = (boolean)rsp->trickdelay;
players[i].trickmomx = (fixed_t)LONG(rsp->trickmomx);
@ -789,6 +797,8 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].tumbleLastBounce = (boolean)rsp->tumbleLastBounce;
players[i].tumbleSound = (boolean)rsp->tumbleSound;
players[i].glanceDir = (SINT8)rsp->glanceDir;
// respawnvars_t
players[i].respawn.state = rsp->respawn_state;
players[i].respawn.pointx = (fixed_t)LONG(rsp->respawn_pointx);

View file

@ -280,6 +280,8 @@ typedef struct
// SRB2kart
INT32 kartstuff[NUMKARTSTUFF];
tic_t airtime;
boolean driftInput;
boolean airFailsafe;
UINT8 trickpanel;
boolean trickdelay;
fixed_t trickmomx;
@ -295,6 +297,8 @@ typedef struct
boolean tumbleLastBounce;
boolean tumbleSound;
SINT8 glanceDir;
// respawnvars_t
UINT8 respawn_state;
fixed_t respawn_pointx;

View file

@ -3555,12 +3555,16 @@ static void Command_Login_f(void)
boolean IsPlayerAdmin(INT32 playernum)
{
#ifdef DEVELOP
return playernum != serverplayer;
#else
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
if (playernum == adminplayers[i])
return true;
return false;
#endif
}
void SetAdminPlayer(INT32 playernum)

View file

@ -115,19 +115,11 @@ typedef enum
{
// Are animation frames playing?
PA_ETC=0,
PA_IDLE,
PA_EDGE,
PA_WALK,
PA_RUN,
PA_DASH,
PA_PAIN,
PA_ROLL,
PA_JUMP,
PA_SPRING,
PA_FALL,
PA_ABILITY,
PA_ABILITY2,
PA_RIDE
PA_STILL,
PA_SLOW,
PA_FAST,
PA_DRIFT,
PA_HURT
} panim_t;
//
@ -454,6 +446,8 @@ typedef enum
#define TRICKMOMZRAMP (30)
#define TRICKLAG (9)
#define TUMBLEBOUNCES 3
//}
// player_t struct for all respawn variables
@ -525,10 +519,13 @@ typedef struct player_s
// SRB2kart stuff
INT32 kartstuff[NUMKARTSTUFF];
INT32 karthud[NUMKARTHUD];
UINT32 distancetofinish;
waypoint_t *nextwaypoint;
respawnvars_t respawn; // Respawn info
tic_t airtime; // Keep track of how long you've been in the air
boolean driftInput; // Whenever or not try drifting.
boolean airFailsafe; // Whenever or not try the air boost
UINT8 trickpanel; // Trick panel state
boolean trickdelay; // Prevent tricks until control stick is neutral
@ -575,6 +572,8 @@ typedef struct player_s
boolean tumbleLastBounce;
boolean tumbleSound;
SINT8 glanceDir; // Direction the player is trying to look backwards in
//
UINT32 charflags; // Extra abilities/settings for skins (combinable stuff)

View file

@ -2031,6 +2031,13 @@ static void readlevelheader(MYFILE *f, INT32 num)
else
mapheaderinfo[num-1]->levelflags &= ~LF_SECTIONRACE;
}
else if (fastcmp(word, "SUBTRACTNUM"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_SUBTRACTNUM;
else
mapheaderinfo[num-1]->levelflags &= ~LF_SUBTRACTNUM;
}
// Individual triggers for menu flags
else if (fastcmp(word, "HIDDEN"))
@ -5204,12 +5211,24 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_KART_STILL",
"S_KART_STILL_L",
"S_KART_STILL_R",
"S_KART_STILL_GLANCE_L",
"S_KART_STILL_GLANCE_R",
"S_KART_STILL_LOOK_L",
"S_KART_STILL_LOOK_R",
"S_KART_SLOW",
"S_KART_SLOW_L",
"S_KART_SLOW_R",
"S_KART_SLOW_GLANCE_L",
"S_KART_SLOW_GLANCE_R",
"S_KART_SLOW_LOOK_L",
"S_KART_SLOW_LOOK_R",
"S_KART_FAST",
"S_KART_FAST_L",
"S_KART_FAST_R",
"S_KART_FAST_GLANCE_L",
"S_KART_FAST_GLANCE_R",
"S_KART_FAST_LOOK_L",
"S_KART_FAST_LOOK_R",
"S_KART_DRIFT_L",
"S_KART_DRIFT_L_OUT",
"S_KART_DRIFT_L_IN",
@ -5217,12 +5236,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_KART_DRIFT_R_OUT",
"S_KART_DRIFT_R_IN",
"S_KART_SPINOUT",
"S_KART_SQUISH",
"S_KART_DEAD",
"S_KART_SIGN",
// technically the player goes here but it's an infinite tic state
"S_OBJPLACE_DUMMY",
"S_KART_LEFTOVER",
"S_KART_LEFTOVER_NOTIRES",
"S_KART_TIRE1",
"S_KART_TIRE2",
// Blue Crawla
"S_POSS_STND",
"S_POSS_RUN1",
@ -9398,6 +9423,31 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_SPINDASHDUST",
"S_SPINDASHWIND",
// Finish line beam
"S_FINISHBEAM1",
"S_FINISHBEAM2",
"S_FINISHBEAM3",
"S_FINISHBEAM4",
"S_FINISHBEAM5",
"S_FINISHBEAMEND1",
"S_FINISHBEAMEND2",
// Funny Spike
"S_DEBTSPIKE1",
"S_DEBTSPIKE2",
"S_DEBTSPIKE3",
"S_DEBTSPIKE4",
"S_DEBTSPIKE5",
"S_DEBTSPIKE6",
"S_DEBTSPIKE7",
"S_DEBTSPIKE8",
"S_DEBTSPIKE9",
"S_DEBTSPIKEA",
"S_DEBTSPIKEB",
"S_DEBTSPIKEC",
"S_DEBTSPIKED",
"S_DEBTSPIKEE",
#ifdef SEENAMES
"S_NAMECHECK",
#endif
@ -9412,6 +9462,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_THOK", // Thok! mobj
"MT_PLAYER",
"MT_KART_LEFTOVER",
"MT_KART_TIRE",
// Enemies
"MT_BLUECRAWLA", // Crawla (Blue)
@ -9537,6 +9589,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
// Collectible Items
"MT_RING",
"MT_FLINGRING", // Lost ring
"MT_DEBTSPIKE", // Ring debt funny spike
"MT_BLUESPHERE", // Blue sphere for special stages
"MT_FLINGBLUESPHERE", // Lost blue sphere
"MT_BOMBSPHERE",
@ -10480,6 +10533,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_PAPERITEMSPOT",
"MT_BEAMPOINT",
#ifdef SEENAMES
"MT_NAMECHECK",
#endif
@ -11002,6 +11057,32 @@ static const char *const KARTSTUFF_LIST[] = {
"WRONGWAY"
};
static const char *const KARTHUD_LIST[] = {
"ITEMBLINK",
"ITEMBLINKMODE",
"RINGFRAME",
"RINGTICS",
"RINGDELAY",
"RINGSPBBLOCK",
"LAPANIMATION",
"LAPHAND",
"FAULT",
"BOOSTCAM",
"DESTBOOSTCAM",
"TIMEOVERCAM",
"ENGINESND",
"VOICES",
"TAUNTVOICES",
"CARDANIMATION",
"YOUGOTEM",
};
static const char *const HUDITEMS_LIST[] = {
"LIVES",
@ -11245,6 +11326,7 @@ struct {
{"LF_SCRIPTISFILE",LF_SCRIPTISFILE},
{"LF_NOZONE",LF_NOZONE},
{"LF_SECTIONRACE",LF_SECTIONRACE},
{"LF_SUBTRACTNUM",LF_SUBTRACTNUM},
// And map flags
{"LF2_HIDEINMENU",LF2_HIDEINMENU},
{"LF2_HIDEINSTATS",LF2_HIDEINSTATS},
@ -11405,19 +11487,11 @@ struct {
// Player animation (panim_t)
{"PA_ETC",PA_ETC},
{"PA_IDLE",PA_IDLE},
{"PA_EDGE",PA_EDGE},
{"PA_WALK",PA_WALK},
{"PA_RUN",PA_RUN},
{"PA_DASH",PA_DASH},
{"PA_PAIN",PA_PAIN},
{"PA_ROLL",PA_ROLL},
{"PA_JUMP",PA_JUMP},
{"PA_SPRING",PA_SPRING},
{"PA_FALL",PA_FALL},
{"PA_ABILITY",PA_ABILITY},
{"PA_ABILITY2",PA_ABILITY2},
{"PA_RIDE",PA_RIDE},
{"PA_STILL",PA_STILL},
{"PA_SLOW",PA_SLOW},
{"PA_FAST",PA_FAST},
{"PA_DRIFT",PA_DRIFT},
{"PA_HURT",PA_HURT},
// Value for infinite lives
{"INFLIVES",INFLIVES},
@ -11644,6 +11718,8 @@ struct {
{"V_70TRANS",V_70TRANS},
{"V_80TRANS",V_80TRANS},
{"V_90TRANS",V_90TRANS},
{"V_ADDTRANS",V_ADDTRANS},
{"V_SUBTRANS",V_SUBTRANS},
{"V_HUDTRANSHALF",V_HUDTRANSHALF},
{"V_HUDTRANS",V_HUDTRANS},
{"V_RETURN8",V_RETURN8},
@ -12244,6 +12320,7 @@ void DEH_Check(void)
const size_t dehmobjs = sizeof(MOBJTYPE_LIST)/sizeof(const char*);
const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*);
const size_t dehkartstuff = sizeof(KARTSTUFF_LIST)/sizeof(const char*);
const size_t dehkarthud = sizeof(KARTHUD_LIST)/sizeof(const char*);
const size_t dehcolors = sizeof(COLOR_ENUMS)/sizeof(const char*);
if (dehstates != S_FIRSTFREESLOT)
@ -12256,7 +12333,10 @@ void DEH_Check(void)
I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers));
if (dehkartstuff != NUMKARTSTUFF)
I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d kartstuff defined, versus %s in the Dehacked list)\n", NUMKARTSTUFF, sizeu1(dehkartstuff));
I_Error("You forgot to update the Dehacked kartstuff list, you dolt!\n(%d kartstuff defined, versus %s in the Dehacked list)\n", NUMKARTSTUFF, sizeu1(dehkartstuff));
if (dehkarthud != NUMKARTHUD)
I_Error("You forgot to update the Dehacked karthud list, you dolt!\n(%d karthud defined, versus %s in the Dehacked list)\n", NUMKARTSTUFF, sizeu1(dehkartstuff));
if (dehcolors != SKINCOLOR_FIRSTFREESLOT)
I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors));
@ -12718,6 +12798,15 @@ static inline int lib_getenum(lua_State *L)
}
return 0;
}
else if (!mathlib && fastncmp("khud_",word,5)) {
p = word+5;
for (i = 0; i < NUMKARTHUD; i++)
if (fasticmp(p, KARTHUD_LIST[i])) {
lua_pushinteger(L, i);
return 1;
}
return 0;
}
else if (mathlib && fastncmp("K_",word,2)) { // SOCs are ALL CAPS!
p = word+2;
for (i = 0; i < NUMKARTSTUFF; i++)
@ -12727,6 +12816,15 @@ static inline int lib_getenum(lua_State *L)
}
return luaL_error(L, "kartstuff '%s' could not be found.\n", word);
}
else if (mathlib && fastncmp("KHUD_",word,5)) { // SOCs are ALL CAPS!
p = word+5;
for (i = 0; i < NUMKARTHUD; i++)
if (fastcmp(p, KARTHUD_LIST[i])) {
lua_pushinteger(L, i);
return 1;
}
return luaL_error(L, "karthud '%s' could not be found.\n", word);
}
else if (fastncmp("HUD_",word,4)) {
p = word+4;
for (i = 0; i < NUMHUDITEMS; i++)

View file

@ -408,6 +408,7 @@ typedef struct
#define LF_SCRIPTISFILE (1<<0) ///< True if the script is a file, not a lump.
#define LF_NOZONE (1<<1) ///< Don't include "ZONE" on level title
#define LF_SECTIONRACE (1<<2) ///< Section race level
#define LF_SUBTRACTNUM (1<<3) ///< Use subtractive position number (for bright levels)
#define LF2_HIDEINMENU (1<<0) ///< Hide in the multiplayer menu
#define LF2_HIDEINSTATS (1<<1) ///< Hide in the statistics screen

View file

@ -1309,9 +1309,11 @@ void G_PreLevelTitleCard(void)
//
boolean G_IsTitleCardAvailable(void)
{
#if 0
// The current level has no name.
if (!mapheaderinfo[gamemap-1]->lvlttl[0])
return false;
#endif
// The title card is available.
return true;
@ -2261,7 +2263,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->pflags |= PF_JUMPDOWN;
p->playerstate = PST_LIVE;
p->panim = PA_IDLE; // standing animation
p->panim = PA_STILL; // standing animation
// Check to make sure their color didn't change somehow...
if (G_GametypeHasTeams())

View file

@ -141,7 +141,7 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t
// 0--1
float dupx, dupy, fscalew, fscaleh, fwidth, fheight;
if (alphalevel >= 10 && alphalevel < 13)
if (alphalevel >= 12 && alphalevel < 13)
return;
// make patch ready in hardware cache
@ -268,7 +268,9 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t
{
FSurfaceInfo Surf;
Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff;
if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency];
if (alphalevel == 10) { flags &= ~PF_Translucent; flags |= PF_Additive; }
else if (alphalevel == 11) { flags &= ~PF_Translucent; flags |= PF_Substractive; }
else if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency];
else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency];
else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency];
else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel];
@ -293,7 +295,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
// 0--1
float dupx, dupy, fscale, fwidth, fheight;
if (alphalevel >= 10 && alphalevel < 13)
if (alphalevel >= 12 && alphalevel < 13)
return;
// make patch ready in hardware cache
@ -426,7 +428,9 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
{
FSurfaceInfo Surf;
Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff;
if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency];
if (alphalevel == 10) { flags &= ~PF_Translucent; flags |= PF_Additive; }
else if (alphalevel == 11) { flags &= ~PF_Translucent; flags |= PF_Substractive; }
else if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency];
else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency];
else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency];
else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel];

View file

@ -150,8 +150,8 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
char str[4096] = "";
va_list arglist;
if (gllogstream)
{
if (gllogstream)
{
va_start(arglist, format);
vsnprintf(str, 4096, format, arglist);
va_end(arglist);
@ -698,7 +698,38 @@ static INT32 shader_leveltime = 0;
"float fd = fe - fs;\n" \
"darkness = clamp((darkness - fs) * (1.0 / fd), 0.0, 1.0);\n" \
"}\n" \
"final_color = mix(final_color, fade_color, darkness);\n"
"float colorBrightness = sqrt((final_color.r * final_color.r) + (final_color.g * final_color.g) + (final_color.b * final_color.b));\n" \
"float fogBrightness = sqrt((fade_color.r * fade_color.r) + (fade_color.g * fade_color.g) + (fade_color.b * fade_color.b));\n" \
"float colorIntensity = 0.0;\n" \
"if (fogBrightness > colorBrightness) {\n" \
"colorIntensity = 1.0 - min(final_color.r, min(final_color.g, final_color.b));\n" \
"colorIntensity = abs(colorIntensity - (1.0 - fogBrightness));\n" \
"} else {\n" \
"colorIntensity = max(final_color.r, max(final_color.g, final_color.b));\n" \
"colorIntensity = abs(colorIntensity - (fogBrightness));\n" \
"}\n" \
"colorIntensity *= darkness;\n" \
"if (abs(final_color.r - fade_color.r) <= colorIntensity) {\n" \
"final_color.r = fade_color.r;\n" \
"} else if (final_color.r < fade_color.r) {\n" \
"final_color.r += colorIntensity;\n" \
"} else {\n" \
"final_color.r -= colorIntensity;\n" \
"}\n" \
"if (abs(final_color.g - fade_color.g) <= colorIntensity) {\n" \
"final_color.g = fade_color.g;\n" \
"} else if (final_color.g < fade_color.g) {\n" \
"final_color.g += colorIntensity;\n" \
"} else {\n" \
"final_color.g -= colorIntensity;\n" \
"}\n" \
"if (abs(final_color.b - fade_color.b) <= colorIntensity) {\n" \
"final_color.b = fade_color.b;\n" \
"} else if (final_color.b < fade_color.b) {\n" \
"final_color.b += colorIntensity;\n" \
"} else {\n" \
"final_color.b -= colorIntensity;\n" \
"}\n" \
#define GLSL_SOFTWARE_FRAGMENT_SHADER \
"uniform sampler2D tex;\n" \

View file

@ -32,6 +32,8 @@ char sprnames[NUMSPRITES + 1][5] =
"THOK", // Thok! mobj
"PLAY",
"KART",
"TIRE",
// Enemies
"POSS", // Crawla (Blue)
@ -131,6 +133,7 @@ char sprnames[NUMSPRITES + 1][5] =
// Collectible Items
"RING",
"DEBT",
"TRNG", // Team Rings
"TOKE", // Special Stage Token
"RFLG", // Red CTF Flag
@ -732,26 +735,39 @@ char sprnames[NUMSPRITES + 1][5] =
"GCHA", // follower: generic chao
"CHEZ", // follower: cheese
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
"VIEW",
"DBCL", // Drift boost clip
"DBNC", // Drift boost clip's sparks
"DBST", // Drift boost plume
"SDDS", // Spindash dust
"SDWN", // Spindash wind
"FLBM",
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
"VIEW",
};
char spr2names[NUMPLAYERSPRITES][5] =
{
"STIN", "STIL", "STIR", // Still
"STGL", "STGR", // Still (glance back)
"STLL", "STLR", // Still (look back)
"SLWN", "SLWL", "SLWR", // Slow driving
"SLGL", "SLGR", // Slow (glance back)
"SLLL", "SLLR", // Slow (look back)
"FSTN", "FSTL", "FSTR", // Fast driving
"FSGL", "FSGR", // Fast (glance back)
"FSLL", "FSLR", // Fast (look back)
"DRLN", "DRLO", "DRLI", // Drifting left
"DRRN", "DRRO", "DRRI", // Drifting right
"SPIN", // Spinout
"SQSH", // Squish
"DEAD", // Dead
"SIGN", // Finish signpost
"XTRA", // Three Faces of Darkness
};
@ -761,14 +777,26 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
0, // SPR2_STIN
SPR2_STIN, // SPR2_STIL
SPR2_STIN, // SPR2_STIR
SPR2_STIN, // SPR2_STGL
SPR2_STIN, // SPR2_STGR
SPR2_STGL, // SPR2_STLL
SPR2_STGR, // SPR2_STLR
0, // SPR2_SLWN
SPR2_SLWN, // SPR2_SLWL
SPR2_SLWN, // SPR2_SLWR
SPR2_SLWN, // SPR2_SLGL
SPR2_SLWN, // SPR2_SLGR
SPR2_SLGL, // SPR2_SLLL
SPR2_SLGR, // SPR2_SLLR
0, // SPR2_FSTN
SPR2_FSTN, // SPR2_FSTL
SPR2_FSTN, // SPR2_FSTR
SPR2_FSTN, // SPR2_FSGL
SPR2_FSTN, // SPR2_FSGR
SPR2_FSGL, // SPR2_FSLL
SPR2_FSGR, // SPR2_FSLR
0, // SPR2_DRLN
SPR2_DRLN, // SPR2_DRLO
@ -779,9 +807,10 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
SPR2_DRRN, // SPR2_DRRI
0, // SPR2_SPIN
SPR2_SPIN, // SPR2_SQSH
0, // SPR2_DEAD
0, // SPR2_SIGN
0, // SPR2_XTRA
};
// Doesn't work with g++, needs actionf_p1 (don't modify this comment)
@ -812,12 +841,24 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_STIN, 1, {NULL}, 0, 0, S_KART_STILL}, // S_KART_STILL
{SPR_PLAY, SPR2_STIL, 1, {NULL}, 0, 0, S_KART_STILL_L}, // S_KART_STILL_L
{SPR_PLAY, SPR2_STIR, 1, {NULL}, 0, 0, S_KART_STILL_R}, // S_KART_STILL_R
{SPR_PLAY, SPR2_STGL, 1, {NULL}, 0, 0, S_KART_STILL_GLANCE_L}, // S_KART_STILL_GLANCE_L
{SPR_PLAY, SPR2_STGR, 1, {NULL}, 0, 0, S_KART_STILL_GLANCE_R}, // S_KART_STILL_GLANCE_R
{SPR_PLAY, SPR2_STLL, 1, {NULL}, 0, 0, S_KART_STILL_LOOK_L}, // S_KART_STILL_LOOK_L
{SPR_PLAY, SPR2_STLR, 1, {NULL}, 0, 0, S_KART_STILL_LOOK_R}, // S_KART_STILL_LOOK_R
{SPR_PLAY, SPR2_SLWN, 1, {NULL}, 0, 0, S_KART_SLOW}, // S_KART_SLOW
{SPR_PLAY, SPR2_SLWL, 1, {NULL}, 0, 0, S_KART_SLOW_L}, // S_KART_SLOW_L
{SPR_PLAY, SPR2_SLWR, 1, {NULL}, 0, 0, S_KART_SLOW_R}, // S_KART_SLOW_R
{SPR_PLAY, SPR2_SLGL, 1, {NULL}, 0, 0, S_KART_SLOW_GLANCE_L}, // S_KART_SLOW_GLANCE_L
{SPR_PLAY, SPR2_SLGR, 1, {NULL}, 0, 0, S_KART_SLOW_GLANCE_R}, // S_KART_SLOW_GLANCE_R
{SPR_PLAY, SPR2_SLLL, 1, {NULL}, 0, 0, S_KART_SLOW_LOOK_L}, // S_KART_SLOW_LOOK_L
{SPR_PLAY, SPR2_SLLR, 1, {NULL}, 0, 0, S_KART_SLOW_LOOK_R}, // S_KART_SLOW_LOOK_R
{SPR_PLAY, SPR2_FSTN, 1, {NULL}, 0, 0, S_KART_FAST}, // S_KART_FAST
{SPR_PLAY, SPR2_FSTL, 1, {NULL}, 0, 0, S_KART_FAST_L}, // S_KART_FAST_L
{SPR_PLAY, SPR2_FSTR, 1, {NULL}, 0, 0, S_KART_FAST_R}, // S_KART_FAST_R
{SPR_PLAY, SPR2_FSGL, 1, {NULL}, 0, 0, S_KART_FAST_GLANCE_L}, // S_KART_FAST_GLANCE_L
{SPR_PLAY, SPR2_FSGR, 1, {NULL}, 0, 0, S_KART_FAST_GLANCE_R}, // S_KART_FAST_GLANCE_R
{SPR_PLAY, SPR2_FSLL, 1, {NULL}, 0, 0, S_KART_FAST_LOOK_L}, // S_KART_FAST_LOOK_L
{SPR_PLAY, SPR2_FSLR, 1, {NULL}, 0, 0, S_KART_FAST_LOOK_R}, // S_KART_FAST_LOOK_R
{SPR_PLAY, SPR2_DRLN, 1, {NULL}, 0, 0, S_KART_DRIFT_L}, // S_KART_DRIFT_L
{SPR_PLAY, SPR2_DRLO, 1, {NULL}, 0, 0, S_KART_DRIFT_L_OUT}, // S_KART_DRIFT_L_OUT
{SPR_PLAY, SPR2_DRLI, 1, {NULL}, 0, 0, S_KART_DRIFT_L_IN}, // S_KART_DRIFT_L_IN
@ -825,11 +866,17 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_DRRO, 1, {NULL}, 0, 0, S_KART_DRIFT_R_OUT}, // S_KART_DRIFT_R_OUT
{SPR_PLAY, SPR2_DRRI, 1, {NULL}, 0, 0, S_KART_DRIFT_R_IN}, // S_KART_DRIFT_R_IN
{SPR_PLAY, SPR2_SPIN|FF_ANIMATE, 350, {NULL}, 0, 1, S_KART_STILL}, // S_KART_SPINOUT
{SPR_PLAY, SPR2_SQSH|FF_ANIMATE, 350, {NULL}, 0, 1, S_KART_STILL}, // S_KART_SQUISH
{SPR_PLAY, SPR2_DEAD, 3, {NULL}, 0, 0, S_KART_DEAD}, // S_KART_DEAD
{SPR_PLAY, SPR2_SIGN|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_KART_SIGN}, // S_KART_SIGN
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, // S_OBJPLACE_DUMMY
{SPR_KART, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER
{SPR_KART, 1, -1, {NULL}, 0, 0, S_NULL}, // S_KART_LEFTOVER_NOTIRES
{SPR_TIRE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE1
{SPR_TIRE, 1, -1, {NULL}, 0, 0, S_NULL}, // S_KART_TIRE2
// Blue Crawla
{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND
{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2}, // S_POSS_RUN1
@ -5115,6 +5162,31 @@ state_t states[NUMSTATES] =
{SPR_SDDS, FF_ANIMATE, 9, {NULL}, 9, 1, S_NULL}, // S_SPINDASHDUST
{SPR_SDWN, FF_ANIMATE|FF_PAPERSPRITE, 18, {NULL}, 9, 2, S_NULL}, // S_SPINDASHWIND
// Finish line beam
{SPR_FLBM, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_FINISHBEAM1
{SPR_FLBM, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_NULL}, // S_FINISHBEAM2
{SPR_FLBM, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_NULL}, // S_FINISHBEAM3
{SPR_FLBM, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_NULL}, // S_FINISHBEAM4
{SPR_FLBM, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_NULL}, // S_FINISHBEAM5
{SPR_FLBM, FF_PAPERSPRITE|5, 1, {NULL}, 0, 0, S_NULL}, // S_FINISHBEAMEND1
{SPR_FLBM, FF_PAPERSPRITE|6, 1, {NULL}, 0, 0, S_NULL}, // S_FINISHBEAMEND2
// Funny Spike
{SPR_DEBT, 0|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE2}, // S_DEBTSPIKE1
{SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE3}, // S_DEBTSPIKE2
{SPR_DEBT, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE4}, // S_DEBTSPIKE3
{SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE5}, // S_DEBTSPIKE4
{SPR_DEBT, 2|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE6}, // S_DEBTSPIKE5
{SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE7}, // S_DEBTSPIKE6
{SPR_DEBT, 3|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE8}, // S_DEBTSPIKE7
{SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE9}, // S_DEBTSPIKE8
{SPR_DEBT, 4|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKEA}, // S_DEBTSPIKE9
{SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKEB}, // S_DEBTSPIKEA
{SPR_DEBT, 5|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKEC}, // S_DEBTSPIKEB
{SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKED}, // S_DEBTSPIKEC
{SPR_DEBT, 6|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKEE}, // S_DEBTSPIKED
{SPR_DEBT, 7|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_DEBTSPIKE1}, // S_DEBTSPIKEE
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
#endif
@ -5216,7 +5288,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_KART_SPINOUT, // deathstate
S_KART_DEAD, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
1, // speed
@ -5230,6 +5302,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
(statenum_t)MT_THOK // raisestate
},
{ // MT_KART_LEFTOVER
4095, // doomednum
S_KART_LEFTOVER, // spawnstate
2, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // 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
1, // speed
16*FRACUNIT, // radius
48*FRACUNIT, // height
-1, // display offset
1000, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_KART_TIRE
-1, // doomednum
S_KART_TIRE1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // 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
1, // speed
6*FRACUNIT, // radius
12*FRACUNIT, // height
-1, // display offset
1000, // mass
0, // damage
sfx_None, // activesound
MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BLUECRAWLA
100, // doomednum
S_POSS_STND, // spawnstate
@ -8011,6 +8137,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_DEBTSPIKE
-1, // doomednum
S_DEBTSPIKE1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
MT_FLINGRING, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
MT_RING, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_itemup, // deathsound
38*FRACUNIT, // speed
24*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BLUESPHERE
-1, // doomednum
S_BLUESPHERE_SPAWN, // spawnstate
@ -28743,6 +28896,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_BEAMPOINT
2424, // doomednum
S_INVISIBLE, // 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
48*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
// ============================================================================================================================//
#ifdef SEENAMES

View file

@ -303,6 +303,8 @@ typedef enum sprite
SPR_THOK, // Thok! mobj
SPR_PLAY,
SPR_KART,
SPR_TIRE,
// Enemies
SPR_POSS, // Crawla (Blue)
@ -402,6 +404,7 @@ typedef enum sprite
// Collectible Items
SPR_RING,
SPR_DEBT,
SPR_TRNG, // Team Rings
SPR_TOKE, // Special Stage Token
SPR_RFLG, // Red CTF Flag
@ -1003,9 +1006,6 @@ typedef enum sprite
SPR_GCHA, // follower: generic chao
SPR_CHEZ, // follower: cheese
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
SPR_VIEW,
SPR_DBCL, // Drift boost clip
SPR_DBNC, // Drift boost clip's sparks
SPR_DBST, // Drift boost plume
@ -1013,6 +1013,11 @@ typedef enum sprite
SPR_SDDS, // Spindash dust
SPR_SDWN, // Spindash wind
SPR_FLBM, // Finish line beam
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
SPR_VIEW,
SPR_FIRSTFREESLOT,
SPR_LASTFREESLOT = SPR_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1,
NUMSPRITES
@ -1024,12 +1029,15 @@ typedef enum sprite
typedef enum playersprite
{
SPR2_STIN = 0, SPR2_STIL, SPR2_STIR,
SPR2_STGL, SPR2_STGR, SPR2_STLL, SPR2_STLR,
SPR2_SLWN, SPR2_SLWL, SPR2_SLWR,
SPR2_SLGL, SPR2_SLGR, SPR2_SLLL, SPR2_SLLR,
SPR2_FSTN, SPR2_FSTL, SPR2_FSTR,
SPR2_FSGL, SPR2_FSGR, SPR2_FSLL, SPR2_FSLR,
SPR2_DRLN, SPR2_DRLO, SPR2_DRLI,
SPR2_DRRN, SPR2_DRRO, SPR2_DRRI,
SPR2_SPIN,
SPR2_SQSH,
SPR2_DEAD,
SPR2_SIGN,
SPR2_XTRA,
SPR2_FIRSTFREESLOT,
@ -1057,12 +1065,24 @@ typedef enum state
S_KART_STILL,
S_KART_STILL_L,
S_KART_STILL_R,
S_KART_STILL_GLANCE_L,
S_KART_STILL_GLANCE_R,
S_KART_STILL_LOOK_L,
S_KART_STILL_LOOK_R,
S_KART_SLOW,
S_KART_SLOW_L,
S_KART_SLOW_R,
S_KART_SLOW_GLANCE_L,
S_KART_SLOW_GLANCE_R,
S_KART_SLOW_LOOK_L,
S_KART_SLOW_LOOK_R,
S_KART_FAST,
S_KART_FAST_L,
S_KART_FAST_R,
S_KART_FAST_GLANCE_L,
S_KART_FAST_GLANCE_R,
S_KART_FAST_LOOK_L,
S_KART_FAST_LOOK_R,
S_KART_DRIFT_L,
S_KART_DRIFT_L_OUT,
S_KART_DRIFT_L_IN,
@ -1070,12 +1090,18 @@ typedef enum state
S_KART_DRIFT_R_OUT,
S_KART_DRIFT_R_IN,
S_KART_SPINOUT,
S_KART_SQUISH,
S_KART_DEAD,
S_KART_SIGN,
// technically the player goes here but it's an infinite tic state
S_OBJPLACE_DUMMY,
S_KART_LEFTOVER,
S_KART_LEFTOVER_NOTIRES,
S_KART_TIRE1,
S_KART_TIRE2,
// Blue Crawla
S_POSS_STND,
S_POSS_RUN1,
@ -5271,6 +5297,29 @@ typedef enum state
S_SPINDASHDUST,
S_SPINDASHWIND,
S_FINISHBEAM1,
S_FINISHBEAM2,
S_FINISHBEAM3,
S_FINISHBEAM4,
S_FINISHBEAM5,
S_FINISHBEAMEND1,
S_FINISHBEAMEND2,
S_DEBTSPIKE1,
S_DEBTSPIKE2,
S_DEBTSPIKE3,
S_DEBTSPIKE4,
S_DEBTSPIKE5,
S_DEBTSPIKE6,
S_DEBTSPIKE7,
S_DEBTSPIKE8,
S_DEBTSPIKE9,
S_DEBTSPIKEA,
S_DEBTSPIKEB,
S_DEBTSPIKEC,
S_DEBTSPIKED,
S_DEBTSPIKEE,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -5305,6 +5354,8 @@ typedef enum mobj_type
MT_THOK, // Thok! mobj
MT_PLAYER,
MT_KART_LEFTOVER,
MT_KART_TIRE,
// Enemies
MT_BLUECRAWLA, // Crawla (Blue)
@ -5430,6 +5481,7 @@ typedef enum mobj_type
// Collectible Items
MT_RING,
MT_FLINGRING, // Lost ring
MT_DEBTSPIKE, // Ring debt funny spike
MT_BLUESPHERE, // Blue sphere for special stages
MT_FLINGBLUESPHERE, // Lost blue sphere
MT_BOMBSPHERE,
@ -6373,6 +6425,8 @@ typedef enum mobj_type
MT_PAPERITEMSPOT,
MT_BEAMPOINT,
#ifdef SEENAMES
MT_NAMECHECK,
#endif

View file

@ -26,6 +26,7 @@
#include "d_ticcmd.h"
#include "m_random.h"
#include "r_things.h" // numskins
#include "k_race.h" // finishBeamLine
/*--------------------------------------------------
@ -296,7 +297,7 @@ boolean K_BotCanTakeCut(player_t *player)
--------------------------------------------------*/
static UINT32 K_BotRubberbandDistance(player_t *player)
{
const UINT32 spacing = FixedDiv(512 * FRACUNIT, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT;
const UINT32 spacing = FixedDiv(640 * FRACUNIT, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT;
const UINT8 portpriority = player - players;
UINT8 pos = 0;
UINT8 i;
@ -429,8 +430,8 @@ fixed_t K_BotTopSpeedRubberband(player_t *player)
}
else
{
// Max at +25% for level 9 bots
rubberband = FRACUNIT + ((rubberband - FRACUNIT) / 4);
// Max at +10% for level 9 bots
rubberband = FRACUNIT + ((rubberband - FRACUNIT) / 10);
}
// Only allow you to go faster than your regular top speed if you're facing the right direction
@ -519,28 +520,35 @@ fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
See header file for description.
--------------------------------------------------*/
fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy)
fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t px, fixed_t py)
{
fixed_t v1toc[2] = {cx - v1x, cy - v1y};
fixed_t v1tov2[2] = {v2x - v1x, v2y - v1y};
fixed_t mag = FixedMul(v1tov2[0], v1tov2[0]) + FixedMul(v1tov2[1], v1tov2[1]);
fixed_t dot = FixedMul(v1toc[0], v1tov2[0]) + FixedMul(v1toc[1], v1tov2[1]);
// Copy+paste from P_ClosestPointOnLine :pensive:
fixed_t startx = v1x;
fixed_t starty = v1y;
fixed_t dx = v2x - v1x;
fixed_t dy = v2y - v1y;
fixed_t cx, cy;
fixed_t vx, vy;
fixed_t magnitude;
fixed_t t;
fixed_t px, py;
if (mag == 0)
{
return 0;
}
cx = px - startx;
cy = py - starty;
t = FixedDiv(dot, mag);
vx = dx;
vy = dy;
px = v1x + FixedMul(v1tov2[0], t);
py = v1y + FixedMul(v1tov2[1], t);
magnitude = R_PointToDist2(v2x, v2y, startx, starty);
vx = FixedDiv(vx, magnitude);
vy = FixedDiv(vy, magnitude);
return P_AproxDistance(cx - px, cy - py);
t = (FixedMul(vx, cx) + FixedMul(vy, cy));
vx = FixedMul(vx, t);
vy = FixedMul(vy, t);
return R_PointToDist2(px, py, startx + vx, starty + vy);
}
/*--------------------------------------------------
@ -690,6 +698,145 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
return predict;
}
/*--------------------------------------------------
static UINT8 K_TrySpindash(player_t *player)
Determines conditions where the bot should attempt to spindash.
Input Arguments:-
player - Bot player to check.
Return:-
0 to make the bot drive normally, 1 to e-brake, 2 to e-brake & charge spindash.
(TODO: make this an enum)
--------------------------------------------------*/
static UINT8 K_TrySpindash(player_t *player)
{
const tic_t difficultyModifier = (TICRATE/6);
if (player->kartstuff[k_spindashboost] || player->kartstuff[k_tiregrease])
{
// You just released a spindash, you don't need to try again yet, jeez.
return 0;
}
// Try "start boosts" first
if (leveltime == starttime)
{
// Forces them to release, even if they haven't fully charged.
// Don't want them to keep charging if they didn't have time to.
return 0;
}
if (leveltime < starttime)
{
INT32 boosthold = starttime - K_GetSpindashChargeTime(player);
boosthold -= (MAXBOTDIFFICULTY - player->botvars.difficulty) * difficultyModifier;
if (leveltime >= (unsigned)boosthold)
{
// Start charging...
return 2;
}
else
{
// Just hold your ground and e-brake.
return 1;
}
}
// Logic for normal racing.
if (player->powers[pw_flashing] > 0)
{
// Don't bother trying to spindash.
// Trying to spindash while flashing is fine during POSITION, but not during the actual race.
return 0;
}
if (player->speed < 10*mapobjectscale // Below the speed threshold
&& player->kartstuff[k_speedboost] < (FRACUNIT/8)) // If you have other boosts, you can probably trust it.
{
INT32 chargingPoint = (K_GetSpindashChargeTime(player) + difficultyModifier);
// Release quicker the higher the difficulty is.
// Sounds counter-productive, but that's actually the best strategy after the race has started.
chargingPoint -= player->botvars.difficulty * difficultyModifier;
if (player->kartstuff[k_spindash] > chargingPoint)
{
// Time to release.
return 0;
}
return 2;
}
// We're doing just fine, we don't need to spindash, thanks.
return 0;
}
/*--------------------------------------------------
static INT16 K_FindBotController(mobj_t *mo)
Finds if any bot controller linedefs are tagged to the bot's sector.
Input Arguments:-
mo - The bot player's mobj.
Return:-
Line number of the bot controller. -1 if it doesn't exist.
--------------------------------------------------*/
static INT16 K_FindBotController(mobj_t *mo)
{
msecnode_t *node;
ffloor_t *rover;
INT16 lineNum = -1;
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (!node->m_sector)
{
continue;
}
lineNum = P_FindSpecialLineFromTag(2004, node->m_sector->tag, -1);
if (lineNum != -1)
{
return lineNum;
}
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
sector_t *rs = NULL;
if (!(rover->flags & FF_EXISTS))
{
continue;
}
if (mo->z > *rover->topheight || mo->z + mo->height < *rover->bottomheight)
{
continue;
}
rs = &sectors[rover->secnum];
lineNum = P_FindSpecialLineFromTag(2004, rs->tag, -1);
if (lineNum != -1)
{
return lineNum;
}
}
}
return -1;
}
/*--------------------------------------------------
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
@ -698,7 +845,10 @@ static botprediction_t *K_CreateBotPrediction(player_t *player)
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
{
botprediction_t *predict = NULL;
boolean trySpindash = true;
UINT8 spindash = 0;
INT32 turnamt = 0;
INT16 botController = -1;
// Can't build a ticcmd if we aren't spawned...
if (!player->mo)
@ -709,53 +859,87 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
// Remove any existing controls
memset(cmd, 0, sizeof(ticcmd_t));
if (gamestate != GS_LEVEL
|| player->mo->scale <= 1) // funny post-finish death
if (
gamestate != GS_LEVEL
|| player->mo->scale <= 1
|| player->playerstate == PST_DEAD
)
{
// No need to do anything else.
return;
}
if (player->playerstate == PST_DEAD)
{
cmd->buttons |= BT_ACCELERATE;
return;
}
// Complete override of all ticcmd functionality
if (LUAh_BotTiccmd(player, cmd))
return;
// Start boost handler
if (leveltime <= starttime)
{
tic_t length = (TICRATE/6);
tic_t boosthold = starttime - K_GetSpindashChargeTime(player);
cmd->buttons |= BT_EBRAKEMASK;
boosthold -= (MAXBOTDIFFICULTY - player->botvars.difficulty) * length;
if (leveltime >= boosthold)
{
cmd->buttons |= BT_DRIFT;
}
return;
}
// Handle steering towards waypoints!
if (player->nextwaypoint != NULL && player->nextwaypoint->mobj != NULL && !P_MobjWasRemoved(player->nextwaypoint->mobj))
botController = K_FindBotController(player->mo);
if (player->trickpanel != 0)
{
// Trick panel state -- do nothing until a controller line is found, in which case do a trick.
if (player->trickpanel == 1 && botController != -1)
{
line_t *controllerLine = &lines[botController];
INT32 type = (sides[controllerLine->sidenum[0]].rowoffset / FRACUNIT);
// Y Offset: Trick type
switch (type)
{
case 1:
cmd->turning = KART_FULLTURN;
break;
case 2:
cmd->turning = -KART_FULLTURN;
break;
case 3:
cmd->buttons |= BT_FORWARD;
break;
case 4:
cmd->buttons |= BT_BACKWARD;
break;
}
}
// Don't do anything else.
return;
}
if ((player->nextwaypoint != NULL
&& player->nextwaypoint->mobj != NULL
&& !P_MobjWasRemoved(player->nextwaypoint->mobj))
|| (botController != -1))
{
// Handle steering towards waypoints!
SINT8 turnsign = 0;
angle_t destangle, moveangle, angle;
INT16 anglediff;
predict = K_CreateBotPrediction(player);
if (botController != -1)
{
const fixed_t dist = (player->mo->radius * 4);
line_t *controllerLine = &lines[botController];
// X Offset: Movement direction
destangle = FixedAngle(sides[controllerLine->sidenum[0]].textureoffset);
// Overwritten prediction
predict = Z_Calloc(sizeof(botprediction_t), PU_LEVEL, NULL);
predict->x = player->mo->x + FixedMul(dist, FINECOSINE(destangle >> ANGLETOFINESHIFT));
predict->y = player->mo->y + FixedMul(dist, FINESINE(destangle >> ANGLETOFINESHIFT));
predict->radius = (DEFAULT_WAYPOINT_RADIUS / 4) * mapobjectscale;
}
else
{
predict = K_CreateBotPrediction(player);
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
}
destangle = R_PointToAngle2(player->mo->x, player->mo->y, predict->x, predict->y);
moveangle = player->mo->angle;
angle = (moveangle - destangle);
if (angle < ANGLE_180)
@ -781,7 +965,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
else
{
const fixed_t playerwidth = (player->mo->radius * 2);
const fixed_t realrad = predict->radius - (playerwidth * 4); // Remove a "safe" distance away from the edges of the road
fixed_t realrad = predict->radius - (playerwidth * 4); // Remove a "safe" distance away from the edges of the road
fixed_t rad = realrad;
fixed_t dirdist = K_DistanceOfLineFromPoint(
player->mo->x, player->mo->y,
@ -857,8 +1041,77 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
}
}
// Handle item usage
K_BotItemUsage(player, cmd, turnamt);
if (leveltime <= starttime && finishBeamLine != NULL)
{
const fixed_t distBase = 384*mapobjectscale;
const fixed_t distAdjust = 64*mapobjectscale;
const fixed_t closeDist = distBase + (distAdjust * (9 - player->kartweight));
const fixed_t farDist = closeDist + (distAdjust * 2);
fixed_t distToFinish = K_DistanceOfLineFromPoint(
finishBeamLine->v1->x, finishBeamLine->v1->y,
finishBeamLine->v2->x, finishBeamLine->v2->y,
player->mo->x, player->mo->y
);
// Don't run the spindash code at all until we're in the right place
trySpindash = false;
// If you're too far, enable spindash & stay still.
// If you're too close, start backing up.
if (distToFinish < closeDist)
{
// Silly way of getting us to reverse, but it respects the above code
// where we figure out what the shape of the track looks like.
UINT16 oldButtons = cmd->buttons;
cmd->buttons &= ~(BT_ACCELERATE|BT_BRAKE);
if (oldButtons & BT_ACCELERATE)
{
cmd->buttons |= BT_BRAKE;
}
if (oldButtons & BT_BRAKE)
{
cmd->buttons |= BT_ACCELERATE;
}
cmd->forwardmove = -cmd->forwardmove;
}
else if (distToFinish < farDist)
{
// We're in about the right place, spindash now.
cmd->forwardmove = 0;
trySpindash = true;
}
}
if (trySpindash == true)
{
// Spindashing
spindash = K_TrySpindash(player);
if (spindash > 0)
{
cmd->buttons |= BT_EBRAKEMASK;
cmd->forwardmove = 0;
if (spindash == 2 && player->speed < 6*mapobjectscale)
{
cmd->buttons |= BT_DRIFT;
}
}
}
if (spindash == 0)
{
// Don't pointlessly try to use rings/sneakers while charging a spindash.
// TODO: Allowing projectile items like orbinaut while e-braking would be nice, maybe just pass in the spindash variable?
K_BotItemUsage(player, cmd, turnamt);
}
if (turnamt != 0)
{
@ -873,6 +1126,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
if (turnamt > 0)
{
// Count up
if (player->botvars.turnconfirm < BOTTURNCONFIRM)
{
player->botvars.turnconfirm++;
@ -880,11 +1134,24 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
}
else if (turnamt < 0)
{
// Count down
if (player->botvars.turnconfirm > -BOTTURNCONFIRM)
{
player->botvars.turnconfirm--;
}
}
else
{
// Back to neutral
if (player->botvars.turnconfirm < 0)
{
player->botvars.turnconfirm++;
}
else if (player->botvars.turnconfirm > 0)
{
player->botvars.turnconfirm--;
}
}
if (abs(player->botvars.turnconfirm) >= BOTTURNCONFIRM)
{

View file

@ -167,9 +167,9 @@ void K_InitGrandPrixBots(void)
difficultylevels[10] = max(1, startingdifficulty-5);
difficultylevels[11] = max(1, startingdifficulty-6);
difficultylevels[12] = max(1, startingdifficulty-6);
difficultylevels[13] = max(1, startingdifficulty-6);
difficultylevels[13] = max(1, startingdifficulty-7);
difficultylevels[14] = max(1, startingdifficulty-7);
difficultylevels[15] = max(1, startingdifficulty-7);
difficultylevels[15] = max(1, startingdifficulty-8);
}
for (i = 0; i < MAXPLAYERS; i++)

View file

@ -1415,17 +1415,26 @@ static void K_DrawKartPositionNum(INT32 num)
fixed_t scale = FRACUNIT;
patch_t *localpatch = kp_positionnum[0][0];
INT32 fx = 0, fy = 0, fflags = 0;
INT32 addOrSub = V_ADDTRANS;
boolean flipdraw = false; // flip the order we draw it in for MORE splitscreen bs. fun.
boolean flipvdraw = false; // used only for 2p splitscreen so overtaking doesn't make 1P's position fly off the screen.
boolean overtake = false;
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SUBTRACTNUM) == LF_SUBTRACTNUM)
{
addOrSub = V_SUBTRANS;
}
if (stplyr->kartstuff[k_positiondelay] || stplyr->exiting)
{
scale *= 2;
overtake = true; // this is used for splitscreen stuff in conjunction with flipdraw.
}
if (r_splitscreen)
{
scale /= 2;
}
W = FixedMul(W<<FRACBITS, scale)>>FRACBITS;
@ -1472,38 +1481,46 @@ static void K_DrawKartPositionNum(INT32 num)
}
// Special case for 0
if (!num)
if (num <= 0)
{
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, scale, V_HUDTRANSHALF|V_SLIDEIN|fflags, kp_positionnum[0][0], NULL);
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, scale, addOrSub|V_SLIDEIN|fflags, kp_positionnum[0][0], NULL);
return;
}
I_Assert(num >= 0); // This function does not draw negative numbers
// Draw the number
while (num)
{
if (win) // 1st place winner? You get rainbows!!
{
localpatch = kp_winnernum[(leveltime % (NUMWINFRAMES*3)) / 3];
}
else if (stplyr->laps >= cv_numlaps.value || stplyr->exiting) // Check for the final lap, or won
{
// Alternate frame every three frames
switch (leveltime % 9)
boolean useRedNums = K_IsPlayerLosing(stplyr);
if (addOrSub == V_SUBTRANS)
{
case 1: case 2: case 3:
if (K_IsPlayerLosing(stplyr))
// Subtracting RED will look BLUE, and vice versa.
useRedNums = !useRedNums;
}
// Alternate frame every three frames
switch ((leveltime % 9) / 3)
{
case 0:
if (useRedNums == true)
localpatch = kp_positionnum[num % 10][4];
else
localpatch = kp_positionnum[num % 10][1];
break;
case 4: case 5: case 6:
if (K_IsPlayerLosing(stplyr))
case 1:
if (useRedNums == true)
localpatch = kp_positionnum[num % 10][5];
else
localpatch = kp_positionnum[num % 10][2];
break;
case 7: case 8: case 9:
if (K_IsPlayerLosing(stplyr))
case 2:
if (useRedNums == true)
localpatch = kp_positionnum[num % 10][6];
else
localpatch = kp_positionnum[num % 10][3];
@ -1514,9 +1531,15 @@ static void K_DrawKartPositionNum(INT32 num)
}
}
else
{
localpatch = kp_positionnum[num % 10][0];
}
V_DrawFixedPatch((fx<<FRACBITS) + ((overtake && flipdraw) ? (SHORT(localpatch->width)*scale/2) : 0), (fy<<FRACBITS) + ((overtake && flipvdraw) ? (SHORT(localpatch->height)*scale/2) : 0), scale, V_HUDTRANSHALF|V_SLIDEIN|fflags, localpatch, NULL);
V_DrawFixedPatch(
(fx<<FRACBITS) + ((overtake && flipdraw) ? (SHORT(localpatch->width)*scale/2) : 0),
(fy<<FRACBITS) + ((overtake && flipvdraw) ? (SHORT(localpatch->height)*scale/2) : 0),
scale, addOrSub|V_SLIDEIN|fflags, localpatch, NULL
);
// ^ if we overtake as p1 or p3 in splitscren, we shift it so that it doesn't go off screen.
// ^ if we overtake as p1 in 2p splits, shift vertically so that this doesn't happen either.
@ -2043,7 +2066,7 @@ static void K_drawKartSpeedometer(void)
{
case 1: // Sonic Drift 2 style percentage
default:
convSpeed = (((25*stplyr->speed)/24) * 100) / K_GetKartSpeed(stplyr, false); // Based on top speed! (cheats with the numbers due to some weird discrepancy)
convSpeed = (stplyr->speed * 100) / K_GetKartSpeed(stplyr, false); // Based on top speed!
labeln = 0;
break;
case 2: // Kilometers
@ -2062,7 +2085,8 @@ static void K_drawKartSpeedometer(void)
}
// Don't overflow
if (convSpeed > 999)
// (negative speed IS really high speed :V)
if (convSpeed > 999 || convSpeed < 0)
convSpeed = 999;
numbers[0] = ((convSpeed / 100) % 10);
@ -2402,6 +2426,7 @@ static void K_drawKartPlayerCheck(void)
UINT8 cnum = 0;
UINT8 i;
INT32 splitflags = V_SNAPTOBOTTOM|V_SPLITSCREEN;
fixed_t y = CHEK_Y * FRACUNIT;
if (stplyr == NULL || stplyr->mo == NULL || P_MobjWasRemoved(stplyr->mo))
{
@ -2420,6 +2445,8 @@ static void K_drawKartPlayerCheck(void)
if (r_splitscreen)
{
y /= 2;
for (i = 1; i <= r_splitscreen; i++)
{
if (stplyr == &players[displayplayers[i]])
@ -2492,7 +2519,7 @@ static void K_drawKartPlayerCheck(void)
K_ObjectTracking(&x, NULL, &c, thiscam->angle + ANGLE_180, 0, &v, cnum);
colormap = R_GetTranslationColormap(TC_DEFAULT, checkplayer->mo->color, GTC_CACHE);
V_DrawFixedPatch(x, CHEK_Y * FRACUNIT, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN|splitflags, kp_check[pnum], colormap);
V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN|splitflags, kp_check[pnum], colormap);
}
}

View file

@ -1010,6 +1010,14 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against)
break;
weight = K_PlayerWeight(mobj, against);
break;
case MT_KART_LEFTOVER:
weight = 5*FRACUNIT/2;
if (mobj->extravalue1 > 0)
{
weight = mobj->extravalue1 * (FRACUNIT >> 1);
}
break;
case MT_BUBBLESHIELD:
weight = K_PlayerWeight(mobj->target, against);
break;
@ -1726,6 +1734,102 @@ void K_SpawnDriftBoostClipSpark(mobj_t *clip)
spark->momy = clip->momx/2;
}
static SINT8 K_GlanceAtPlayers(player_t *glancePlayer)
{
const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
const angle_t blindSpotSize = ANG10; // ANG5
UINT8 i;
SINT8 glanceDir = 0;
SINT8 lastValidGlance = 0;
// See if there's any players coming up behind us.
// If so, your character will glance at 'em.
for (i = 0; i < MAXPLAYERS; i++)
{
player_t *p;
angle_t back;
angle_t diff;
fixed_t distance;
SINT8 dir = -1;
if (!playeringame[i])
{
// Invalid player
continue;
}
p = &players[i];
if (p == glancePlayer)
{
// FOOL! Don't glance at yerself!
continue;
}
if (!p->mo || P_MobjWasRemoved(p->mo))
{
// Invalid mobj
continue;
}
if (p->spectator || p->kartstuff[k_hyudorotimer] > 0)
{
// Not playing / invisible
continue;
}
distance = R_PointToDist2(glancePlayer->mo->x, glancePlayer->mo->y, p->mo->x, p->mo->y);
if (distance > maxdistance)
{
continue;
}
back = glancePlayer->mo->angle + ANGLE_180;
diff = R_PointToAngle2(glancePlayer->mo->x, glancePlayer->mo->y, p->mo->x, p->mo->y) - back;
if (diff > ANGLE_180)
{
diff = InvAngle(diff);
dir = -dir;
}
if (diff > ANGLE_90)
{
// Not behind the player
continue;
}
if (diff < blindSpotSize)
{
// Small blindspot directly behind your back, gives the impression of smoothly turning.
continue;
}
if (P_CheckSight(glancePlayer->mo, p->mo) == true)
{
// Not blocked by a wall, we can glance at 'em!
// Adds, so that if there's more targets on one of your sides, it'll glance on that side.
glanceDir += dir;
// That poses a limitation if there's an equal number of targets on both sides...
// In that case, we'll pick the last chosen glance direction.
lastValidGlance = dir;
}
}
if (glanceDir > 0)
{
return 1;
}
else if (glanceDir < 0)
{
return -1;
}
return lastValidGlance;
}
/** \brief Handles the state changing for moving players, moved here to eliminate duplicate code
\param player player data
@ -1735,7 +1839,6 @@ void K_SpawnDriftBoostClipSpark(mobj_t *clip)
void K_KartMoveAnimation(player_t *player)
{
const INT16 minturn = KART_FULLTURN/8;
SINT8 turndir = 0;
const fixed_t fastspeed = (K_GetKartSpeed(player, false) * 17) / 20; // 85%
const fixed_t speedthreshold = player->mo->scale / 8;
@ -1743,7 +1846,12 @@ void K_KartMoveAnimation(player_t *player)
const boolean onground = P_IsObjectOnGround(player->mo);
ticcmd_t *cmd = &player->cmd;
const boolean spinningwheels = ((cmd->buttons & BT_ACCELERATE) || (onground && player->speed > 0));
const boolean spinningwheels = (((cmd->buttons & BT_ACCELERATE) == BT_ACCELERATE) || (onground && player->speed > 0));
const boolean lookback = ((cmd->buttons & BT_LOOKBACK) == BT_LOOKBACK);
SINT8 turndir = 0;
SINT8 destGlanceDir = 0;
SINT8 drift = player->kartstuff[k_drift];
if (cmd->turning < -minturn)
{
@ -1754,20 +1862,89 @@ void K_KartMoveAnimation(player_t *player)
turndir = 1;
}
if (lookback == true && drift == 0)
{
// Prioritize looking back frames over turning
turndir = 0;
}
if (turndir == 0 && drift == 0)
{
// Only try glancing if you're driving straight.
// This avoids all-players loops when we don't need it.
destGlanceDir = K_GlanceAtPlayers(player);
if (lookback == true)
{
if (destGlanceDir == 0)
{
if (player->glanceDir != 0)
{
// Keep to the side you were already on.
if (player->glanceDir < 0)
{
destGlanceDir = -1;
}
else
{
destGlanceDir = 1;
}
}
else
{
// Look to your right by default
destGlanceDir = -1;
}
}
else
{
// Looking back AND glancing? Amplify the look!
destGlanceDir *= 2;
}
}
else if (K_GetForwardMove(player) < 0 && destGlanceDir == 0)
{
// Reversing -- like looking back, but doesn't stack on the other glances.
if (player->glanceDir != 0)
{
// Keep to the side you were already on.
if (player->glanceDir < 0)
{
destGlanceDir = -1;
}
else
{
destGlanceDir = 1;
}
}
else
{
// Look to your right by default
destGlanceDir = -1;
}
}
}
else
{
// Not glancing
destGlanceDir = 0;
player->glanceDir = 0;
}
#define SetState(sn) \
if (player->mo->state != &states[sn]) \
P_SetPlayerMobjState(player->mo, sn)
if (!onground)
if (onground == false)
{
// Only use certain frames in the air, to make it look like your tires are spinning fruitlessly!
if (player->kartstuff[k_drift] > 0)
if (drift > 0)
{
// Neutral drift
SetState(S_KART_DRIFT_L);
}
else if (player->kartstuff[k_drift] > 0)
else if (drift < 0)
{
// Neutral drift
SetState(S_KART_DRIFT_R);
@ -1782,22 +1959,41 @@ void K_KartMoveAnimation(player_t *player)
{
SetState(S_KART_FAST_L);
}
else if (turndir == 0)
else
{
SetState(S_KART_FAST);
switch (player->glanceDir)
{
case -2:
SetState(S_KART_FAST_LOOK_R);
break;
case 2:
SetState(S_KART_FAST_LOOK_L);
break;
case -1:
SetState(S_KART_FAST_GLANCE_R);
break;
case 1:
SetState(S_KART_FAST_GLANCE_L);
break;
default:
SetState(S_KART_FAST);
break;
}
}
}
if (!spinningwheels)
{
// TODO: These should prooobably be different SPR2s
// Just a quick hack to prevent needing to do that :V
// TODO: The "tires still in the air" states should have it's own SPR2s.
// This was a quick hack to get the same functionality with less work,
// but it's really dunderheaded & isn't customizable at all.
player->mo->frame = (player->mo->frame & ~FF_FRAMEMASK);
player->mo->tics++; // Makes it properly use frame 0
}
}
else
{
if (player->kartstuff[k_drift] > 0)
if (drift > 0)
{
// Drifting LEFT!
@ -1817,7 +2013,7 @@ void K_KartMoveAnimation(player_t *player)
SetState(S_KART_DRIFT_L);
}
}
else if (player->kartstuff[k_drift] < 0)
else if (drift < 0)
{
// Drifting RIGHT!
@ -1853,7 +2049,24 @@ void K_KartMoveAnimation(player_t *player)
}
else
{
SetState(S_KART_FAST);
switch (player->glanceDir)
{
case -2:
SetState(S_KART_FAST_LOOK_R);
break;
case 2:
SetState(S_KART_FAST_LOOK_L);
break;
case -1:
SetState(S_KART_FAST_GLANCE_R);
break;
case 1:
SetState(S_KART_FAST_GLANCE_L);
break;
default:
SetState(S_KART_FAST);
break;
}
}
}
else
@ -1872,7 +2085,24 @@ void K_KartMoveAnimation(player_t *player)
}
else
{
SetState(S_KART_SLOW);
switch (player->glanceDir)
{
case -2:
SetState(S_KART_SLOW_LOOK_R);
break;
case 2:
SetState(S_KART_SLOW_LOOK_L);
break;
case -1:
SetState(S_KART_SLOW_GLANCE_R);
break;
case 1:
SetState(S_KART_SLOW_GLANCE_L);
break;
default:
SetState(S_KART_SLOW);
break;
}
}
}
else
@ -1889,7 +2119,24 @@ void K_KartMoveAnimation(player_t *player)
}
else
{
SetState(S_KART_STILL);
switch (player->glanceDir)
{
case -2:
SetState(S_KART_STILL_LOOK_R);
break;
case 2:
SetState(S_KART_STILL_LOOK_L);
break;
case -1:
SetState(S_KART_STILL_GLANCE_R);
break;
case 1:
SetState(S_KART_STILL_GLANCE_L);
break;
default:
SetState(S_KART_STILL);
break;
}
}
}
}
@ -1898,6 +2145,16 @@ void K_KartMoveAnimation(player_t *player)
#undef SetState
// Update your glance value to smooth it out.
if (player->glanceDir > destGlanceDir)
{
player->glanceDir--;
}
else if (player->glanceDir < destGlanceDir)
{
player->glanceDir++;
}
// Update lastspeed value -- we use to display slow driving frames instead of fast driving when slowing down.
player->lastspeed = player->speed;
}
@ -2030,6 +2287,13 @@ boolean K_ApplyOffroad(player_t *player)
return true;
}
boolean K_SlopeResistance(player_t *player)
{
if (player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_sneakertimer] || player->kartstuff[k_tiregrease])
return true;
return false;
}
static fixed_t K_FlameShieldDashVar(INT32 val)
{
// 1 second = 75% + 50% top speed
@ -2048,7 +2312,7 @@ fixed_t K_GetSpindashChargeSpeed(player_t *player)
// more speed for higher weight & speed
// Tails = +6.25%, Fang = +20.31%, Mighty = +20.31%, Metal = +25%
// (can be higher than this value when overcharged)
return (player->kartspeed + player->kartweight) * (FRACUNIT/64);
return (player->kartspeed + player->kartweight) * (FRACUNIT/32);
}
@ -2124,11 +2388,12 @@ static void K_GetKartBoostPower(player_t *player)
if (player->kartstuff[k_spindashboost]) // Spindash boost
{
const fixed_t MAXCHARGESPEED = K_GetSpindashChargeSpeed(player);
const fixed_t exponent = FixedMul(player->kartstuff[k_spindashspeed], player->kartstuff[k_spindashspeed]);
// character & charge dependent
ADDBOOST(
FixedMul(MAXCHARGESPEED, player->kartstuff[k_spindashspeed]), // + 0 to K_GetSpindashChargeSpeed()% top speed
(4*FRACUNIT) + (36*player->kartstuff[k_spindashspeed]), // + 400% to 4000% acceleration
FixedMul(MAXCHARGESPEED, exponent), // + 0 to K_GetSpindashChargeSpeed()% top speed
(40 * exponent), // + 0% to 4000% acceleration
0 // + 0% handling
);
}
@ -2205,10 +2470,17 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower)
finalspeed = FixedMul(finalspeed, FRACUNIT + (sphereAdd * player->spheres));
}
if (K_PlayerUsesBotMovement(player) && player->botvars.rival == true)
if (K_PlayerUsesBotMovement(player))
{
// +10% top speed for the rival
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
// Increase bot speed by 1-10% depending on difficulty
fixed_t add = (player->botvars.difficulty * (FRACUNIT/10)) / MAXBOTDIFFICULTY;
finalspeed = FixedMul(finalspeed, FRACUNIT + add);
if (player->botvars.rival == true)
{
// +10% top speed for the rival
finalspeed = FixedMul(finalspeed, 11*FRACUNIT/10);
}
}
if (player->mo && !P_MobjWasRemoved(player->mo))
@ -2546,7 +2818,7 @@ void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source)
static boolean K_LastTumbleBounceCondition(player_t *player)
{
return (player->tumbleBounces > 4 && player->tumbleHeight < 40);
return (player->tumbleBounces > TUMBLEBOUNCES && player->tumbleHeight < 40);
}
static void K_HandleTumbleBounce(player_t *player)
@ -2616,8 +2888,10 @@ static void K_HandleTumbleSound(player_t *player)
}
}
void K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer
{
INT32 ringburst = 10;
(void)source;
player->mo->momz = 18*mapobjectscale*P_MobjFlip(player->mo); // please stop forgetting mobjflip checks!!!!
@ -2632,6 +2906,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A b
{
player->kartstuff[k_spinouttimer] = ((5*player->kartstuff[k_spinouttimer])/2)+1;
player->mo->momz *= 2;
ringburst = 20;
}
}
@ -2642,6 +2917,8 @@ void K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A b
if (P_IsDisplayPlayer(player))
P_StartQuake(64<<FRACBITS, 5);
return ringburst;
}
// This kind of wipeout happens with no rings -- doesn't remove a bumper, has no invulnerability, and is much shorter.
@ -6135,9 +6412,18 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
if (cmd->buttons & BT_DRIFT)
player->kartstuff[k_jmp] = 1;
{
// Only allow drifting while NOT trying to do an spindash input.
if ((cmd->buttons & BT_EBRAKEMASK) != BT_EBRAKEMASK)
{
player->driftInput = true;
}
// else, keep the previous value, because it might be brake-drifting.
}
else
player->kartstuff[k_jmp] = 0;
{
player->driftInput = false;
}
// Roulette Code
K_KartItemRoulette(player, cmd);
@ -6569,7 +6855,15 @@ void K_UpdateDistanceFromFinishLine(player_t *const player)
INT32 K_GetKartRingPower(player_t *player)
{
return (((9 - player->kartspeed) + (9 - player->kartweight)) / 2);
INT32 ringPower = ((9 - player->kartspeed) + (9 - player->kartweight)) / 2;
if (K_PlayerUsesBotMovement(player))
{
// Double for Lv. 9
ringPower += (player->botvars.difficulty * ringPower) / MAXBOTDIFFICULTY;
}
return ringPower;
}
// Returns false if this player being placed here causes them to collide with any other player
@ -6715,6 +7009,7 @@ INT32 K_GetKartDriftSparkValue(player_t *player)
Stage 1: red sparks
Stage 2: blue sparks
Stage 3: big large rainbow sparks
Stage 0: air failsafe
*/
void K_SpawnDriftBoostExplosion(player_t *player, int stage)
{
@ -6745,6 +7040,11 @@ void K_SpawnDriftBoostExplosion(player_t *player, int stage)
S_StartSound(player->mo, sfx_kc5b);
S_StartSound(player->mo, sfx_s3kc4l);
break;
case 0:
overlay->color = SKINCOLOR_SILVER;
overlay->fuse = 16;
break;
}
overlay->extravalue1 = stage;
@ -6752,13 +7052,15 @@ void K_SpawnDriftBoostExplosion(player_t *player, int stage)
static void K_KartDrift(player_t *player, boolean onground)
{
fixed_t minspeed = (10 * player->mo->scale);
INT32 dsone = K_GetKartDriftSparkValue(player);
INT32 dstwo = dsone*2;
INT32 dsthree = dstwo*2;
const fixed_t minspeed = (10 * player->mo->scale);
const INT32 dsone = K_GetKartDriftSparkValue(player);
const INT32 dstwo = dsone*2;
const INT32 dsthree = dstwo*2;
// Drifting is actually straffing + automatic turning.
// Holding the Jump button will enable drifting.
// (This comment is extremely funny)
// Drift Release (Moved here so you can't "chain" drifts)
if (player->kartstuff[k_drift] != -5 && player->kartstuff[k_drift] != 5)
@ -6819,21 +7121,21 @@ static void K_KartDrift(player_t *player, boolean onground)
}
// Drifting: left or right?
if ((player->cmd.turning > 0) && player->speed > minspeed && player->kartstuff[k_jmp] == 1
if ((player->cmd.turning > 0) && player->speed > minspeed && player->driftInput == true
&& (player->kartstuff[k_drift] == 0 || player->kartstuff[k_driftend] == 1)) // && player->kartstuff[k_drift] != 1)
{
// Starting left drift
player->kartstuff[k_drift] = 1;
player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0;
}
else if ((player->cmd.turning < 0) && player->speed > minspeed && player->kartstuff[k_jmp] == 1
else if ((player->cmd.turning < 0) && player->speed > minspeed && player->driftInput == true
&& (player->kartstuff[k_drift] == 0 || player->kartstuff[k_driftend] == 1)) // && player->kartstuff[k_drift] != -1)
{
// Starting right drift
player->kartstuff[k_drift] = -1;
player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0;
}
else if (player->kartstuff[k_jmp] == 0) // || player->kartstuff[k_turndir] == 0)
else if (player->driftInput == false) // || player->kartstuff[k_turndir] == 0)
{
// drift is not being performed so if we're just finishing set driftend and decrement counters
if (player->kartstuff[k_drift] > 0)
@ -6857,7 +7159,7 @@ static void K_KartDrift(player_t *player, boolean onground)
player->kartstuff[k_aizdriftstrat] = player->kartstuff[k_brakedrift] = 0;
player->kartstuff[k_getsparks] = 0;
}
else if (player->kartstuff[k_jmp] == 1 && player->kartstuff[k_drift] != 0)
else if (player->driftInput == true && player->kartstuff[k_drift] != 0)
{
// Incease/decrease the drift value to continue drifting in that direction
fixed_t driftadditive = 24;
@ -7209,6 +7511,11 @@ static void K_KartSpindash(player_t *player)
ticcmd_t *cmd = &player->cmd;
boolean spawnWind = (leveltime % 2 == 0);
if (player->mo->hitlag > 0 || P_PlayerInPain(player))
{
player->kartstuff[k_spindash] = 0;
}
if (player->kartstuff[k_spindash] > 0 && (cmd->buttons & (BT_DRIFT|BT_BRAKE)) != (BT_DRIFT|BT_BRAKE))
{
player->kartstuff[k_spindashspeed] = (player->kartstuff[k_spindash] * FRACUNIT) / MAXCHARGETIME;
@ -7250,11 +7557,14 @@ static void K_KartSpindash(player_t *player)
return;
}
if (player->speed < 6*mapobjectscale && player->powers[pw_flashing] == 0)
if (player->speed == 0 && cmd->turning != 0 && leveltime % 8 == 0)
{
if (cmd->turning != 0 && leveltime % 8 == 0)
S_StartSound(player->mo, sfx_ruburn);
// Rubber burn turn sfx
S_StartSound(player->mo, sfx_ruburn);
}
if (player->speed < 6*player->mo->scale)
{
if ((cmd->buttons & (BT_DRIFT|BT_BRAKE)) == (BT_DRIFT|BT_BRAKE))
{
INT16 chargetime = MAXCHARGETIME - ++player->kartstuff[k_spindash];
@ -7271,6 +7581,15 @@ static void K_KartSpindash(player_t *player)
K_KartSpindashWind(player->mo);
}
if (player->powers[pw_flashing] > 0 && (leveltime & 1) && player->kartstuff[k_hyudorotimer] == 0)
{
// Every frame that you're invisible from flashing, spill a ring.
// Intentionally a lop-sided trade-off, so the game doesn't become
// Funky Kong's Ring Racers.
P_PlayerRingBurst(player, 1);
}
if (chargetime > 0)
{
UINT16 soundcharge = 0;
@ -7298,6 +7617,39 @@ static void K_KartSpindash(player_t *player)
}
}
static void K_AirFailsafe(player_t *player)
{
const fixed_t maxSpeed = 6*player->mo->scale;
const fixed_t thrustSpeed = 6*player->mo->scale; // 10*player->mo->scale
ticcmd_t *cmd = &player->cmd;
if (player->speed > maxSpeed // Above the max speed that you're allowed to use this technique.
|| player->respawn.state != RESPAWNST_NONE) // Respawning, you don't need this AND drop dash :V
{
player->airFailsafe = false;
return;
}
if ((cmd->buttons & BT_ACCELERATE) || K_GetForwardMove(player) != 0)
{
// Queue up later
player->airFailsafe = true;
return;
}
if (player->airFailsafe == true)
{
// Push the player forward
P_Thrust(player->mo, K_MomentumAngle(player->mo), thrustSpeed);
S_StartSound(player->mo, sfx_s23c);
K_SpawnDriftBoostExplosion(player, 0);
player->airFailsafe = false;
}
}
//
// K_AdjustPlayerFriction
//
@ -8171,9 +8523,18 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
}
}
K_KartDrift(player, P_IsObjectOnGround(player->mo)); // Not using onground, since we don't want this affected by spring pads
K_KartDrift(player, onground);
K_KartSpindash(player);
if (onground == false)
{
K_AirFailsafe(player);
}
else
{
player->airFailsafe = false;
}
// Play the starting countdown sounds
if (player == &players[g_localplayers[0]]) // Don't play louder in splitscreen
{

View file

@ -45,13 +45,14 @@ void K_DoInstashield(player_t *player);
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved);
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type);
void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_DebtStingPlayer(player_t *player, mobj_t *source);
void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers);
void K_DestroyBumpers(player_t *player, UINT8 amount);
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source);
void K_SpawnMineExplosion(mobj_t *source, UINT8 color);
void K_RunFinishLineBeam(void);
UINT16 K_DriftSparkColor(player_t *player, INT32 charge);
void K_SpawnBoostTrail(player_t *player);
void K_SpawnSparkleTrail(mobj_t *mo);
@ -81,6 +82,7 @@ void K_StripItems(player_t *player);
void K_StripOther(player_t *player);
void K_MomentumToFacing(player_t *player);
boolean K_ApplyOffroad(player_t *player);
boolean K_SlopeResistance(player_t *player);
INT16 K_GetSpindashChargeTime(player_t *player);
fixed_t K_GetSpindashChargeSpeed(player_t *player);
fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed);

421
src/k_race.c Normal file
View file

@ -0,0 +1,421 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 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 k_race.c
/// \brief Race Mode specific code.
#include "k_race.h"
#include "k_kart.h"
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_color.h"
#include "k_respawn.h"
#include "doomdef.h"
#include "hu_stuff.h"
#include "g_game.h"
#include "m_random.h"
#include "p_local.h"
#include "p_slopes.h"
#include "p_setup.h"
#include "r_draw.h"
#include "r_local.h"
#include "s_sound.h"
#include "st_stuff.h"
#include "v_video.h"
#include "z_zone.h"
#include "m_misc.h"
#include "m_cond.h"
#include "f_finale.h"
#include "lua_hud.h" // For Lua hud checks
#include "lua_hook.h" // For MobjDamage and ShouldDamage
#include "m_cheat.h" // objectplacing
#include "p_spec.h"
#include "k_waypoint.h"
#include "k_bot.h"
#include "k_hud.h"
line_t *finishBeamLine = NULL;
static mobj_t *beamPoints[2];
static UINT8 numBeamPoints = 0;
/*--------------------------------------------------
void K_ClearFinishBeamLine(void)
See header file for description.
--------------------------------------------------*/
void K_ClearFinishBeamLine(void)
{
size_t i;
finishBeamLine = NULL;
for (i = 0; i < 2; i++)
{
beamPoints[i] = NULL;
}
numBeamPoints = 0;
}
/*--------------------------------------------------
static void K_FreeFinishBeamLine(void)
See header file for description.
--------------------------------------------------*/
static void K_FreeFinishBeamLine(void)
{
if (finishBeamLine != NULL)
{
if (finishBeamLine->v1 != NULL)
{
Z_Free(finishBeamLine->v1);
}
if (finishBeamLine->v2 != NULL)
{
Z_Free(finishBeamLine->v2);
}
Z_Free(finishBeamLine);
}
K_ClearFinishBeamLine();
}
/*--------------------------------------------------
static void K_CreateFinishLineFromPoints(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
See header file for description.
--------------------------------------------------*/
static void K_CreateFinishLineFromPoints(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2)
{
I_Assert(finishBeamLine == NULL); // Needs to be NULL
finishBeamLine = Z_Calloc(sizeof (*finishBeamLine), PU_LEVEL, NULL);
finishBeamLine->v1 = Z_Calloc(sizeof (*finishBeamLine->v1), PU_LEVEL, NULL);
finishBeamLine->v1->x = x1;
finishBeamLine->v1->y = y1;
finishBeamLine->v2 = Z_Calloc(sizeof (*finishBeamLine->v2), PU_LEVEL, NULL);
finishBeamLine->v2->x = x2;
finishBeamLine->v2->y = y2;
finishBeamLine->dx = x2 - x1;
finishBeamLine->dy = y2 - y1;
finishBeamLine->flags = 0;
}
/*--------------------------------------------------
boolean K_GenerateFinishBeamLine(void)
See header file for description.
--------------------------------------------------*/
boolean K_GenerateFinishBeamLine(void)
{
mapthing_t *mt;
INT64 bounds[4];
angle_t angle;
boolean valid = false;
size_t i;
// Ensure everything's freed by this time.
K_FreeFinishBeamLine();
// First: attempt to create from beam point objects
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
{
if (numBeamPoints >= 2)
{
break;
}
if (mt->type == mobjinfo[MT_BEAMPOINT].doomednum)
{
beamPoints[numBeamPoints] = mt->mobj;
numBeamPoints++;
}
}
if (numBeamPoints == 2)
{
// Found 'em! Really easy to generate a line out of these :)
K_CreateFinishLineFromPoints(
beamPoints[0]->x, beamPoints[0]->y,
beamPoints[1]->x, beamPoints[1]->y
);
return true;
}
bounds[0] = INT64_MAX; // min x
bounds[1] = INT64_MIN; // max x
bounds[2] = INT64_MAX; // min y
bounds[3] = INT64_MIN; // max y
for (i = 0; i < numlines; i++)
{
angle_t thisAngle;
if (lines[i].special != 2001)
{
continue;
}
thisAngle = R_PointToAngle2(0, 0, lines[i].dx, lines[i].dy);
bounds[0] = min(bounds[0], min(lines[i].v1->x, lines[i].v2->x)); // min x
bounds[1] = max(bounds[1], max(lines[i].v1->x, lines[i].v2->x)); // max x
bounds[2] = min(bounds[2], min(lines[i].v1->y, lines[i].v2->y)); // min y
bounds[3] = max(bounds[3], max(lines[i].v1->y, lines[i].v2->y)); // max y
if (valid == false)
{
angle = thisAngle;
valid = true;
}
else if (angle != thisAngle)
{
// Do not even attempt to bother with curved finish lines.
// Will likely just crash.
valid = false;
break;
}
}
if (valid == true)
{
fixed_t span = P_AproxDistance(bounds[1] - bounds[0], bounds[3] - bounds[2]) / 2;
fixed_t cx = (bounds[0] + bounds[1]) / 2;
fixed_t cy = (bounds[2] + bounds[3]) / 2;
fixed_t spanC = FixedMul(span, FINECOSINE(angle >> ANGLETOFINESHIFT));
fixed_t spanS = FixedMul(span, FINESINE(angle >> ANGLETOFINESHIFT));
K_CreateFinishLineFromPoints(
cx - spanC, cy - spanS,
cx + spanC, cy + spanS
);
return true;
}
return false;
}
/*--------------------------------------------------
static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *line, boolean reverse)
Draws a helix out of rainbow colored orbs along a line, unique for each display player.
Called twice for the finish line beam effect.
Input Arguments:-
offset - Offset value for positioning. Changed every tick to make it animate.
aiming - Starting vertical angle value. Changed every tick to make it animate.
line - Linedef to draw along.
reverse - Draw in reverse. Call twice with this toggled to make a double helix.
Return:-
None
--------------------------------------------------*/
static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *line, boolean reverse)
{
const fixed_t linelength = P_AproxDistance(line->dx, line->dy);
const fixed_t xstep = FixedDiv(line->dx, linelength);
const fixed_t ystep = FixedDiv(line->dy, linelength);
fixed_t linex = line->v1->x;
fixed_t liney = line->v1->y;
angle_t lineangle = R_PointToAngle2(0, 0, line->dx, line->dy) + ANGLE_90;
UINT8 i;
if (line->flags & ML_NOCLIMB)
{
// Line is flipped
lineangle += ANGLE_180;
}
linex += FixedMul(offset, xstep);
liney += FixedMul(offset, ystep);
while (offset < linelength)
{
#define COLORCYCLELEN 10
const UINT8 colorcycle[COLORCYCLELEN] = {
SKINCOLOR_PERIWINKLE,
SKINCOLOR_SLATE,
SKINCOLOR_BLOSSOM,
SKINCOLOR_RASPBERRY,
SKINCOLOR_ORANGE,
SKINCOLOR_YELLOW,
SKINCOLOR_LIME,
SKINCOLOR_TURTLE,
SKINCOLOR_ROBIN,
SKINCOLOR_JAWZ
};
const UINT8 numframes = 5;
const angle_t framethreshold = ANGLE_180 / (numframes-1);
const angle_t frameaim = aiming + (framethreshold / 2);
fixed_t x, y, z;
UINT8 spriteframe = 0;
x = linex + FixedMul(FixedMul(FINISHLINEBEAM_SPACING, FINECOSINE(lineangle >> ANGLETOFINESHIFT)), FINECOSINE(aiming >> ANGLETOFINESHIFT));
y = liney + FixedMul(FixedMul(FINISHLINEBEAM_SPACING, FINESINE(lineangle >> ANGLETOFINESHIFT)), FINECOSINE(aiming >> ANGLETOFINESHIFT));
z = FINISHLINEBEAM_SPACING + FixedMul(FINISHLINEBEAM_SPACING, FINESINE(aiming >> ANGLETOFINESHIFT));
if (leveltime >= starttime)
{
spriteframe = 4; // Weakest sprite when passable
}
else if (frameaim > ANGLE_180)
{
spriteframe = (ANGLE_MAX - frameaim) / framethreshold;
}
else
{
spriteframe = frameaim / framethreshold;
}
for (i = 0; i <= r_splitscreen; i++)
{
if (playeringame[displayplayers[i]] && players[displayplayers[i]].mo && !P_MobjWasRemoved(players[displayplayers[i]].mo))
{
mobj_t *beam;
beam = P_SpawnMobj(x, y, players[displayplayers[i]].mo->z + z, MT_THOK);
P_SetMobjState(beam, S_FINISHBEAM1 + spriteframe);
beam->colorized = true;
beam->drawflags = MFD_DONTDRAW & ~K_GetPlayerDontDrawFlag(&players[displayplayers[i]]);
if (reverse)
{
beam->color = colorcycle[((leveltime / 4) + (COLORCYCLELEN/2)) % COLORCYCLELEN];
}
else
{
beam->color = colorcycle[(leveltime / 4) % COLORCYCLELEN];
}
}
}
offset += FINISHLINEBEAM_SPACING;
linex += FixedMul(FINISHLINEBEAM_SPACING, xstep);
liney += FixedMul(FINISHLINEBEAM_SPACING, ystep);
if (reverse)
{
aiming -= ANGLE_45;
}
else
{
aiming += ANGLE_45;
}
}
for (i = 0; i <= r_splitscreen; i++)
{
if (playeringame[displayplayers[i]] && players[displayplayers[i]].mo && !P_MobjWasRemoved(players[displayplayers[i]].mo))
{
UINT8 j;
for (j = 0; j < 2; j++)
{
vertex_t *v = line->v1;
mobj_t *end1, *end2;
angle_t a = R_PointToAngle2(0, 0, line->dx, line->dy);
fixed_t sx;
fixed_t sy;
/*
if (line->flags & ML_NOCLIMB)
{
a += ANGLE_180;
}
*/
sx = FixedMul(3*mapobjectscale, FINECOSINE(a >> ANGLETOFINESHIFT));
sy = FixedMul(3*mapobjectscale, FINESINE(a >> ANGLETOFINESHIFT));
if (j == 1)
{
v = line->v2;
sx = -sx;
sy = -sy;
}
end1 = P_SpawnMobj(
v->x + sx,
v->y + sy,
players[displayplayers[i]].mo->z + FINISHLINEBEAM_SPACING,
MT_THOK
);
P_SetMobjState(end1, S_FINISHBEAMEND1);
end1->drawflags = MFD_DONTDRAW & ~K_GetPlayerDontDrawFlag(&players[displayplayers[i]]);
end1->angle = lineangle;
end2 = P_SpawnMobj(
v->x + (8*sx),
v->y + (8*sy),
players[displayplayers[i]].mo->z + FINISHLINEBEAM_SPACING,
MT_THOK
);
P_SetMobjState(end2, S_FINISHBEAMEND2);
end2->drawflags = MFD_DONTDRAW & ~K_GetPlayerDontDrawFlag(&players[displayplayers[i]]);
end2->angle = lineangle;
P_SetTarget(&end2->tracer, end1);
end2->flags2 |= MF2_LINKDRAW;
}
}
}
}
/*--------------------------------------------------
void K_RunFinishLineBeam(void)
See header file for description.
--------------------------------------------------*/
void K_RunFinishLineBeam(void)
{
if (!(leveltime < starttime || rainbowstartavailable == true))
{
return;
}
if (finishBeamLine != NULL)
{
const angle_t angoffset = ANGLE_45;
const angle_t angadd = ANGLE_11hh;
const fixed_t speed = 6 * mapobjectscale;
fixed_t offseta = (leveltime * speed) % FINISHLINEBEAM_SPACING;
angle_t aiminga = (angoffset * -((leveltime * speed) / FINISHLINEBEAM_SPACING)) + (angadd * leveltime);
fixed_t offsetb = FINISHLINEBEAM_SPACING - offseta;
angle_t aimingb = (angoffset * -((leveltime * speed) / FINISHLINEBEAM_SPACING)) - (angadd * leveltime);
K_DrawFinishLineBeamForLine(offseta, aiminga, finishBeamLine, false);
K_DrawFinishLineBeamForLine(offsetb, aimingb, finishBeamLine, true);
}
}

69
src/k_race.h Normal file
View file

@ -0,0 +1,69 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 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 k_race.h
/// \brief Race Mode specific code.
#ifndef __K_RACE__
#define __K_RACE__
#include "r_defs.h"
extern line_t *finishBeamLine;
#define FINISHLINEBEAM_SPACING (48*mapobjectscale)
/*--------------------------------------------------
void K_ClearFinishBeamLine(void);
Clears variables for finishBeamLine.
Separate from K_FreeFinishBeamLine since this
needs called when PU_LEVEL is freed.
Input Arguments:-
None
Return:-
None
--------------------------------------------------*/
void K_ClearFinishBeamLine(void);
/*--------------------------------------------------
boolean K_GenerateFinishBeamLine(void);
Finds pre-placed "beam points" to create a finish line out of,
or tries to automatically create it from a finish linedef in the map.
The result is stored in the "finishBeamLine" variable.
Input Arguments:-
None
Return:-
True if successful, otherwise false.
--------------------------------------------------*/
boolean K_GenerateFinishBeamLine(void);
/*--------------------------------------------------
void K_RunFinishLineBeam(void);
Updates the finish line beam effect.
Input Arguments:-
None
Return:-
None
--------------------------------------------------*/
void K_RunFinishLineBeam(void);
#endif

View file

@ -122,9 +122,9 @@ void K_DoIngameRespawn(player_t *player)
// If player was tumbling, set variables so that they don't tumble like crazy after they're done respawning
if (player->tumbleBounces > 0)
{
player->tumbleBounces = 3; // Max # of bounces-1 (so you still tumble once)
player->tumbleLastBounce = 0; // Still force them to bounce at least once for the funny
players->tumbleHeight = 20; // force tumble height
player->tumbleBounces = TUMBLEBOUNCES-1; // Max # of bounces-1 (so you still tumble once)
player->tumbleLastBounce = false; // Still force them to bounce at least once for the funny
players->tumbleHeight = 20; // force tumble height
}
P_ResetPlayer(player);

View file

@ -3440,8 +3440,8 @@ static int lib_kExplodePlayer(lua_State *L)
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
K_ExplodePlayer(player, inflictor, source);
return 0;
lua_pushinteger(L, K_ExplodePlayer(player, inflictor, source));
return 1;
}
static int lib_kTakeBumpersFromPlayer(lua_State *L)

View file

@ -34,6 +34,8 @@ extern lua_State *gL;
#define META_SKIN "SKIN_T*"
#define META_POWERS "PLAYER_T*POWERS"
#define META_KARTSTUFF "PLAYER_T*KARTSTUFF"
#define META_KARTHUD "PLAYER_T*KARTHUD"
#define META_RESPAWN "PLAYER_T*RESPAWN"
#define META_COLLIDE "PLAYER_T*COLLIDE"
#define META_SOUNDSID "SKIN_T*SOUNDSID"

View file

@ -192,6 +192,8 @@ static int player_get(lua_State *L)
LUA_PushUserdata(L, plr->mo, META_MOBJ);
else if (fastcmp(field,"cmd"))
LUA_PushUserdata(L, &plr->cmd, META_TICCMD);
else if (fastcmp(field,"respawn"))
LUA_PushUserdata(L, &plr->respawn, META_RESPAWN);
else if (fastcmp(field,"playerstate"))
lua_pushinteger(L, plr->playerstate);
else if (fastcmp(field,"viewz"))
@ -212,8 +214,14 @@ static int player_get(lua_State *L)
LUA_PushUserdata(L, plr->powers, META_POWERS);
else if (fastcmp(field,"kartstuff"))
LUA_PushUserdata(L, plr->kartstuff, META_KARTSTUFF);
else if (fastcmp(field,"karthud"))
LUA_PushUserdata(L, plr->karthud, META_KARTHUD);
else if (fastcmp(field,"airtime"))
lua_pushinteger(L, plr->airtime);
else if (fastcmp(field,"driftInput"))
lua_pushboolean(L, plr->driftInput);
else if (fastcmp(field,"airFailsafe"))
lua_pushboolean(L, plr->airFailsafe);
else if (fastcmp(field,"tumbleBounces"))
lua_pushinteger(L, plr->tumbleBounces);
else if (fastcmp(field,"tumbleHeight"))
@ -222,6 +230,8 @@ static int player_get(lua_State *L)
lua_pushboolean(L, plr->tumbleLastBounce);
else if (fastcmp(field,"tumbleSound"))
lua_pushboolean(L, plr->tumbleSound);
else if (fastcmp(field,"glanceDir"))
lua_pushinteger(L, plr->glanceDir);
else if (fastcmp(field,"trickpanel"))
lua_pushinteger(L, plr->trickpanel);
else if (fastcmp(field,"trickdelay"))
@ -471,6 +481,8 @@ static int player_set(lua_State *L)
}
else if (fastcmp(field,"cmd"))
return NOSET;
else if (fastcmp(field,"respawn"))
return NOSET;
else if (fastcmp(field,"playerstate"))
plr->playerstate = luaL_checkinteger(L, 3);
else if (fastcmp(field,"viewz"))
@ -521,6 +533,10 @@ static int player_set(lua_State *L)
return NOSET;
else if (fastcmp(field,"airtime"))
plr->airtime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"driftInput"))
plr->driftInput = luaL_checkboolean(L, 3);
else if (fastcmp(field,"airFailsafe"))
plr->airFailsafe = luaL_checkboolean(L, 3);
else if (fastcmp(field,"tumbleBounces"))
plr->tumbleBounces = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"tumbleHeight"))
@ -529,6 +545,8 @@ static int player_set(lua_State *L)
plr->tumbleLastBounce = luaL_checkboolean(L, 3);
else if (fastcmp(field,"tumbleSound"))
plr->tumbleSound = luaL_checkboolean(L, 3);
else if (fastcmp(field,"glanceDir"))
plr->glanceDir = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickpanel"))
plr->trickpanel = luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickdelay"))
@ -848,13 +866,48 @@ static int kartstuff_set(lua_State *L)
return 0;
}
// #kartstuff -> NUMKARTSTUFF
// #karthud -> NUMKARTSTUFF
static int kartstuff_len(lua_State *L)
{
lua_pushinteger(L, NUMKARTSTUFF);
return 1;
}
// karthud, ks -> karthud[ks]
static int karthud_get(lua_State *L)
{
INT32 *karthud = *((INT32 **)luaL_checkudata(L, 1, META_KARTHUD));
karthudtype_t ks = luaL_checkinteger(L, 2);
if (ks >= NUMKARTHUD)
return luaL_error(L, LUA_QL("karthudtype_t") " cannot be %u", ks);
lua_pushinteger(L, karthud[ks]);
return 1;
}
// karthud, ks, value -> kartstuff[ks] = value
static int karthud_set(lua_State *L)
{
INT32 *karthud = *((INT32 **)luaL_checkudata(L, 1, META_KARTHUD));
karthudtype_t ks = luaL_checkinteger(L, 2);
INT32 i = (INT32)luaL_checkinteger(L, 3);
if (ks >= NUMKARTHUD)
return luaL_error(L, LUA_QL("karthudtype_t") " cannot be %u", ks);
if (hud_running)
return luaL_error(L, "Do not alter player_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter player_t in BuildCMD code!");
karthud[ks] = i;
return 0;
}
// #karthud -> NUMKARTHUD
static int karthud_len(lua_State *L)
{
lua_pushinteger(L, NUMKARTHUD);
return 1;
}
// player.cmd get/set
#define NOFIELD luaL_error(L, LUA_QL("ticcmd_t") " has no field named " LUA_QS, field)
#define NOSET luaL_error(L, LUA_QL("ticcmd_t") " field " LUA_QS " cannot be set.", field)
@ -913,6 +966,82 @@ static int ticcmd_set(lua_State *L)
#undef NOFIELD
// Same shit for player.respawn variable... Why is everything in different sub-variables again now???
#define RNOFIELD luaL_error(L, LUA_QL("respawnvars_t") " has no field named " LUA_QS, field)
#define RUNIMPLEMENTED luaL_error(L, LUA_QL("respawnvars_t") " unimplemented field " LUA_QS " cannot be read or set.", field)
// @TODO: Waypoints in Lua possibly maybe? No don't count on me to do it...
static int respawn_get(lua_State *L)
{
respawnvars_t *rsp = *((respawnvars_t **)luaL_checkudata(L, 1, META_RESPAWN));
const char *field = luaL_checkstring(L, 2);
if (!rsp)
return LUA_ErrInvalid(L, "player_t");
if (fastcmp(field,"state"))
lua_pushinteger(L, rsp->state);
else if (fastcmp(field,"waypoint"))
return RUNIMPLEMENTED;
else if (fastcmp(field,"pointx"))
lua_pushfixed(L, rsp->pointx);
else if (fastcmp(field,"pointy"))
lua_pushfixed(L, rsp->pointy);
else if (fastcmp(field,"pointz"))
lua_pushfixed(L, rsp->pointz);
else if (fastcmp(field,"flip"))
lua_pushboolean(L, rsp->flip);
else if (fastcmp(field,"timer"))
lua_pushinteger(L, rsp->timer);
else if (fastcmp(field,"distanceleft"))
lua_pushinteger(L, rsp->distanceleft); // Can't possibly foresee any problem when pushing UINT32 to Lua's INT32 hahahahaha, get ready for dumb hacky shit on high distances.
else if (fastcmp(field,"dropdash"))
lua_pushinteger(L, rsp->dropdash);
else
return RNOFIELD;
return 1;
}
static int respawn_set(lua_State *L)
{
respawnvars_t *rsp = *((respawnvars_t **)luaL_checkudata(L, 1, META_RESPAWN));
const char *field = luaL_checkstring(L, 2);
if (!rsp)
return LUA_ErrInvalid(L, "respawnvars_t");
if (hud_running)
return luaL_error(L, "Do not alter player_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter player_t in CMD building code!");
if (fastcmp(field,"state"))
rsp->state = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"waypoint"))
return RUNIMPLEMENTED;
else if (fastcmp(field,"pointx"))
rsp->pointx = luaL_checkfixed(L, 3);
else if (fastcmp(field,"pointy"))
rsp->pointy = luaL_checkfixed(L, 3);
else if (fastcmp(field,"pointz"))
rsp->pointz = luaL_checkfixed(L, 3);
else if (fastcmp(field,"flip"))
rsp->flip = luaL_checkboolean(L, 3);
else if (fastcmp(field,"timer"))
rsp->timer = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"distanceleft"))
rsp->distanceleft = (UINT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"dropdash"))
rsp->dropdash = (tic_t)luaL_checkinteger(L, 3);
else
return RNOFIELD;
return 0;
}
#undef RNOFIELD
#undef RUNIMPLEMENTED
int LUA_PlayerLib(lua_State *L)
{
luaL_newmetatable(L, META_PLAYER);
@ -948,6 +1077,25 @@ int LUA_PlayerLib(lua_State *L)
lua_setfield(L, -2, "__len");
lua_pop(L,1);
luaL_newmetatable(L, META_KARTHUD);
lua_pushcfunction(L, karthud_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, karthud_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, karthud_len);
lua_setfield(L, -2, "__len");
lua_pop(L,1);
luaL_newmetatable(L, META_RESPAWN);
lua_pushcfunction(L, respawn_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, respawn_set);
lua_setfield(L, -2, "__newindex");
lua_pop(L,1);
luaL_newmetatable(L, META_TICCMD);
lua_pushcfunction(L, ticcmd_get);
lua_setfield(L, -2, "__index");

View file

@ -4229,7 +4229,7 @@ void A_AttractChase(mobj_t *actor)
else
actor->drawflags &= ~MFD_DONTDRAW;
// spilled rings have ghost trails and get capped to a certain speed
// spilled rings get capped to a certain speed
if (actor->type == (mobjtype_t)actor->info->reactiontime)
{
const fixed_t maxspeed = 4<<FRACBITS;
@ -4241,9 +4241,6 @@ void A_AttractChase(mobj_t *actor)
actor->momx = FixedMul(FixedDiv(actor->momx, oldspeed), newspeed);
actor->momy = FixedMul(FixedDiv(actor->momy, oldspeed), newspeed);
}
if (!P_IsObjectOnGround(actor))
P_SpawnGhostMobj(actor)->tics = 3;
}
if (actor->tracer && actor->tracer->player && actor->tracer->health

View file

@ -1371,13 +1371,47 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
case MT_PLAYER:
{
angle_t flingAngle;
mobj_t *kart;
target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player)
target->momx = target->momy = target->momz = 0;
if (target->player && target->player->pflags & PF_GAMETYPEOVER)
break;
kart = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_KART_LEFTOVER);
if (kart && !P_MobjWasRemoved(kart))
{
kart->angle = target->angle;
kart->color = target->color;
kart->hitlag = target->hitlag;
P_SetObjectMomZ(kart, 6*FRACUNIT, false);
kart->extravalue1 = target->player->kartweight;
}
if (source && !P_MobjWasRemoved(source))
{
flingAngle = R_PointToAngle2(
source->x - source->momx, source->y - source->momy,
target->x, target->y
);
}
else
{
flingAngle = target->angle + ANGLE_180;
if (P_RandomByte() & 1)
{
flingAngle -= ANGLE_45;
}
else
{
flingAngle += ANGLE_45;
}
}
P_InstaThrust(target, flingAngle, 14 * target->scale);
P_SetObjectMomZ(target, 14*FRACUNIT, false);
P_PlayDeathSound(target);
}
break;
@ -2012,10 +2046,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
break;
case DMG_TUMBLE:
K_TumblePlayer(player, inflictor, source);
ringburst = 10;
break;
case DMG_EXPLODE:
case DMG_KARMA:
K_ExplodePlayer(player, inflictor, source);
ringburst = K_ExplodePlayer(player, inflictor, source);
break;
case DMG_WIPEOUT:
if (P_IsDisplayPlayer(player))
@ -2100,6 +2135,56 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return true;
}
static void P_FlingBurst
( player_t *player,
angle_t fa,
fixed_t z,
mobjtype_t objType,
tic_t objFuse,
fixed_t objScale,
INT32 i)
{
mobj_t *mo;
fixed_t ns;
fixed_t momxy = 5<<FRACBITS, momz = 12<<FRACBITS; // base horizonal/vertical thrusts
INT32 mx = (i + 1) >> 1;
z = player->mo->z;
if (player->mo->eflags & MFE_VERTICALFLIP)
z += player->mo->height - mobjinfo[objType].height;
mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType);
mo->threshold = 10; // not useful for spikes
mo->fuse = objFuse;
P_SetTarget(&mo->target, player->mo);
mo->destscale = objScale;
P_SetScale(mo, objScale);
/*
0: 0
1: 1 = (1+1)/2 = 1
2: 1 = (2+1)/2 = 1
3: 2 = (3+1)/2 = 2
4: 2 = (4+1)/2 = 2
5: 3 = (4+1)/2 = 2
*/
// Angle / height offset changes every other ring
momxy -= mx * FRACUNIT;
momz += mx * (2<<FRACBITS);
if (i & 1)
fa += ANGLE_180;
ns = FixedMul(momxy, player->mo->scale);
mo->momx = (mo->target->momx/2) + FixedMul(FINECOSINE(fa>>ANGLETOFINESHIFT), ns);
mo->momy = (mo->target->momy/2) + FixedMul(FINESINE(fa>>ANGLETOFINESHIFT), ns);
ns = FixedMul(momz, player->mo->scale);
mo->momz = (mo->target->momz/2) + ((ns) * P_MobjFlip(mo));
}
/** Spills an injured player's rings.
*
* \param player The player who is losing rings.
@ -2109,12 +2194,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
*/
void P_PlayerRingBurst(player_t *player, INT32 num_rings)
{
INT32 num_fling_rings;
INT32 i;
mobj_t *mo;
angle_t fa;
fixed_t ns;
fixed_t z;
fixed_t momxy = 5<<FRACBITS, momz = 12<<FRACBITS; // base horizonal/vertical thrusts
// Rings shouldn't be in Battle!
if (gametyperules & GTR_SPHERES)
@ -2134,52 +2217,26 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
else if (num_rings <= 0)
return;
// Cap the maximum loss automatically to 2 in ring debt
if (player->rings <= 0 && num_rings > 2)
num_rings = 2;
num_fling_rings = min(num_rings, player->rings);
P_GivePlayerRings(player, -num_rings);
// determine first angle
fa = player->mo->angle + ((P_RandomByte() & 1) ? -ANGLE_90 : ANGLE_90);
for (i = 0; i < num_rings; i++)
z = player->mo->z;
if (player->mo->eflags & MFE_VERTICALFLIP)
z += player->mo->height - mobjinfo[MT_RING].height;
for (i = 0; i < num_fling_rings; i++)
{
INT32 objType = mobjinfo[MT_RING].reactiontime;
P_FlingBurst(player, fa, z,
MT_FLINGRING, 60*TICRATE, player->mo->scale, i);
}
z = player->mo->z;
if (player->mo->eflags & MFE_VERTICALFLIP)
z += player->mo->height - mobjinfo[objType].height;
mo = P_SpawnMobj(player->mo->x, player->mo->y, z, objType);
mo->threshold = 10;
mo->fuse = 60*TICRATE;
P_SetTarget(&mo->target, player->mo);
mo->destscale = player->mo->scale;
P_SetScale(mo, player->mo->scale);
// Angle / height offset changes every other ring
if (i != 0)
{
if (i & 1)
{
momxy -= FRACUNIT;
momz += 2<<FRACBITS;
}
fa += ANGLE_180;
}
ns = FixedMul(momxy, mo->scale);
mo->momx = (mo->target->momx/2) + FixedMul(FINECOSINE(fa>>ANGLETOFINESHIFT), ns);
mo->momy = (mo->target->momy/2) + FixedMul(FINESINE(fa>>ANGLETOFINESHIFT), ns);
ns = FixedMul(momz, mo->scale);
P_SetObjectMomZ(mo, (mo->target->momz/2) + ns, false);
if (player->mo->eflags & MFE_VERTICALFLIP)
mo->momz *= -1;
while (i < num_rings)
{
P_FlingBurst(player, fa, z,
MT_DEBTSPIKE, 0, 3 * player->mo->scale / 2, i++);
}
}

View file

@ -213,6 +213,7 @@ static boolean P_SpecialIsLinedefCrossType(UINT16 ldspecial)
switch (ldspecial)
{
case 2001: // Finish line
case 2003: // Respawn line
{
linedefcrossspecial = true;
}
@ -1398,6 +1399,21 @@ static boolean PIT_CheckThing(mobj_t *thing)
return false;
}
else if (thing->type == MT_KART_LEFTOVER)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (P_IsObjectOnGround(thing) && tmthing->momz < 0)
K_KartBouncing(tmthing, thing, true, false);
else
K_KartBouncing(tmthing, thing, false, false);
return false;
}
else if (thing->flags & MF_SOLID)
{
// see if it went over / under

View file

@ -221,17 +221,29 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
case S_KART_STILL:
case S_KART_STILL_L:
case S_KART_STILL_R:
player->panim = PA_IDLE;
case S_KART_STILL_GLANCE_L:
case S_KART_STILL_GLANCE_R:
case S_KART_STILL_LOOK_L:
case S_KART_STILL_LOOK_R:
player->panim = PA_STILL;
break;
case S_KART_SLOW:
case S_KART_SLOW_L:
case S_KART_SLOW_R:
player->panim = PA_WALK;
case S_KART_SLOW_GLANCE_L:
case S_KART_SLOW_GLANCE_R:
case S_KART_SLOW_LOOK_L:
case S_KART_SLOW_LOOK_R:
player->panim = PA_SLOW;
break;
case S_KART_FAST:
case S_KART_FAST_L:
case S_KART_FAST_R:
player->panim = PA_RUN;
case S_KART_FAST_GLANCE_L:
case S_KART_FAST_GLANCE_R:
case S_KART_FAST_LOOK_L:
case S_KART_FAST_LOOK_R:
player->panim = PA_FAST;
break;
case S_KART_DRIFT_L:
case S_KART_DRIFT_L_OUT:
@ -239,11 +251,11 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
case S_KART_DRIFT_R:
case S_KART_DRIFT_R_OUT:
case S_KART_DRIFT_R_IN:
player->panim = PA_DASH;
player->panim = PA_DRIFT;
break;
case S_KART_SPINOUT:
case S_KART_SQUISH:
player->panim = PA_PAIN;
case S_KART_DEAD:
player->panim = PA_HURT;
break;
default:
player->panim = PA_ETC;
@ -1300,7 +1312,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
&& !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) /*&& (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)*/))
{
// if in a walking frame, stop moving
if (player->panim == PA_WALK)
if (player->panim == PA_SLOW)
{
P_SetPlayerMobjState(mo, S_KART_STILL);
}
@ -2280,6 +2292,16 @@ boolean P_ZMovement(mobj_t *mo)
else
mo->flags2 ^= MFD_DONTDRAW;
}
else if (mo->type == MT_DEBTSPIKE)
{
mom.x = mom.y = 0;
mom.z = -mom.z/2;
if (mo->fuse == 0)
{
mo->fuse = 90;
}
}
else if (mo->flags & MF_MISSILE)
{
if (!(mo->flags & MF_NOCLIP))
@ -2334,6 +2356,68 @@ boolean P_ZMovement(mobj_t *mo)
if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something
mom.z = -mom.z;
else if (mo->type == MT_KART_LEFTOVER)
{
if (mo->health > 1)
{
const fixed_t tireOffset = 32;
const angle_t aOffset = ANGLE_22h;
UINT8 i;
angle_t tireAngle;
mobj_t *tire;
// Spawn tires!
mo->health = 1;
P_SetMobjState(mo, S_KART_LEFTOVER_NOTIRES);
// Front tires
tireAngle = mo->angle - aOffset;
for (i = 0; i < 2; i++)
{
tire = P_SpawnMobjFromMobj(
mo,
tireOffset * FINECOSINE(tireAngle >> ANGLETOFINESHIFT),
tireOffset * FINESINE(tireAngle >> ANGLETOFINESHIFT),
0,
MT_KART_TIRE
);
tire->angle = mo->angle;
tire->fuse = 3*TICRATE;
P_InstaThrust(tire, tireAngle, 4 * mo->scale);
P_SetObjectMomZ(tire, 4*FRACUNIT, false);
tireAngle += (aOffset * 2);
}
// Back tires
tireAngle = (mo->angle + ANGLE_180) - aOffset;
for (i = 0; i < 2; i++)
{
tire = P_SpawnMobjFromMobj(
mo,
tireOffset * FINECOSINE(tireAngle >> ANGLETOFINESHIFT),
tireOffset * FINESINE(tireAngle >> ANGLETOFINESHIFT),
0,
MT_KART_TIRE
);
tire->angle = mo->angle;
tire->fuse = 3*TICRATE;
P_InstaThrust(tire, tireAngle, 4 * mo->scale);
P_SetObjectMomZ(tire, 4*FRACUNIT, false);
P_SetMobjState(tire, S_KART_TIRE2);
tireAngle += (aOffset * 2);
}
}
}
else if (mo->type == MT_KART_TIRE)
{
mom.z = -mom.z;
}
else if (mo->type == MT_BIGTUMBLEWEED
|| mo->type == MT_LITTLETUMBLEWEED
|| mo->type == MT_CANNONBALLDECOR
@ -2633,7 +2717,7 @@ void P_PlayerZMovement(mobj_t *mo)
mo->z = mo->floorz;
// Get up if you fell.
if (mo->player->panim == PA_PAIN && mo->player->kartstuff[k_spinouttimer] == 0 && mo->player->tumbleBounces == 0)
if (mo->player->panim == PA_HURT && mo->player->kartstuff[k_spinouttimer] == 0 && mo->player->tumbleBounces == 0)
P_SetPlayerMobjState(mo, S_KART_STILL);
if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) {
@ -5867,8 +5951,11 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
{ // Go away.
/// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it.
mobj->momz = 0;
if (mobj->player)
{
mobj->drawflags |= MFD_DONTDRAW;
}
else // safe to remove, nobody's going to complain!
{
P_RemoveMobj(mobj);
@ -5877,16 +5964,6 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
}
else // Apply gravity to fall downwards.
{
if (mobj->player && !(mobj->fuse % 8) && (mobj->player->charflags & SF_MACHINE))
{
fixed_t r = mobj->radius >> FRACBITS;
mobj_t *explosion = P_SpawnMobj(
mobj->x + (P_RandomRange(r, -r) << FRACBITS),
mobj->y + (P_RandomRange(r, -r) << FRACBITS),
mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS),
MT_SONIC3KBOSSEXPLODE);
S_StartSound(explosion, sfx_s3kb4);
}
P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true);
}
break;
@ -6671,6 +6748,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (mobj->fuse == 16)/* to red*/
K_SpawnDriftBoostClip(mobj->target->player);
break;
case 0:/* air failsafe boost */
mobj->color = SKINCOLOR_SILVER; // force white
break;
}
{
@ -9079,6 +9160,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
switch (thing->type)
{
case MT_PLAYER:
case MT_KART_LEFTOVER:
case MT_SMALLMACE:
case MT_BIGMACE:
case MT_PUMA:
@ -9124,6 +9206,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
thing->shadowscale = FRACUNIT;
break;
case MT_RING:
case MT_FLINGRING:
case MT_DEBTSPIKE:
case MT_FLOATINGITEM:
case MT_BLUESPHERE:
case MT_EMERALD:
@ -9371,6 +9455,19 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUAMARINE);
break;
case MT_BALLOON:
{
static const UINT8 BALLOONCOLORS[] = {
// Carnival Night balloon colors
SKINCOLOR_KETCHUP,
SKINCOLOR_SAPPHIRE,
SKINCOLOR_TANGERINE,
SKINCOLOR_JET
};
mobj->color = BALLOONCOLORS[P_RandomKey(sizeof(BALLOONCOLORS))];
}
break;
case MT_KART_LEFTOVER:
mobj->color = SKINCOLOR_RED;
break;
case MT_EGGROBO1:

View file

@ -255,7 +255,11 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, players[i].distancetofinish);
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint));
WRITEUINT32(save_p, players[i].airtime);
WRITEUINT8(save_p, players[i].driftInput);
WRITEUINT8(save_p, players[i].airFailsafe);
WRITEUINT8(save_p, players[i].trickpanel);
WRITEUINT8(save_p, players[i].trickdelay);
WRITEUINT32(save_p, players[i].trickmomx);
@ -271,6 +275,8 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].tumbleLastBounce);
WRITEUINT8(save_p, players[i].tumbleSound);
WRITESINT8(save_p, players[i].glanceDir);
// respawnvars_t
WRITEUINT8(save_p, players[i].respawn.state);
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].respawn.wp));
@ -455,7 +461,11 @@ static void P_NetUnArchivePlayers(void)
players[i].distancetofinish = READUINT32(save_p);
players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save_p);
players[i].airtime = READUINT32(save_p);
players[i].driftInput = (boolean)READUINT8(save_p);
players[i].airFailsafe = (boolean)READUINT8(save_p);
players[i].trickpanel = READUINT8(save_p);
players[i].trickdelay = READUINT8(save_p);
players[i].trickmomx = READUINT32(save_p);
@ -471,6 +481,8 @@ static void P_NetUnArchivePlayers(void)
players[i].tumbleLastBounce = (boolean)READUINT8(save_p);
players[i].tumbleSound = (boolean)READUINT8(save_p);
players[i].glanceDir = READSINT8(save_p);
// respawnvars_t
players[i].respawn.state = READUINT8(save_p);
players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save_p);

View file

@ -83,6 +83,7 @@
// SRB2Kart
#include "k_kart.h"
#include "k_race.h"
#include "k_battle.h" // K_SpawnBattleCapsules
#include "k_pwrlv.h"
#include "k_waypoint.h"
@ -4059,6 +4060,8 @@ boolean P_LoadLevel(boolean fromnetsave)
// The waypoint data that's in PU_LEVEL needs to be reset back to 0/NULL now since PU_LEVEL was cleared
K_ClearWaypoints();
K_ClearFinishBeamLine();
// Load the waypoints please!
if (gametyperules & GTR_CIRCUIT)
{
@ -4066,6 +4069,11 @@ boolean P_LoadLevel(boolean fromnetsave)
{
CONS_Alert(CONS_ERROR, "Waypoints were not able to be setup! Player positions will not work correctly.\n");
}
if (K_GenerateFinishBeamLine() == false)
{
CONS_Alert(CONS_ERROR, "No valid finish line beam setup could be found.\n");
}
}
#ifdef HWRENDER // not win32 only 19990829 by Kin

View file

@ -2182,6 +2182,20 @@ void P_CrossSpecialLine(line_t *line, INT32 side, mobj_t *thing)
}
break;
case 2003: // Respawn Line
{
/* No Climb: only trigger from front side */
if
(
player->respawn.state == RESPAWNST_NONE &&
(!(line->flags & ML_NOCLIMB) || side == 0)
)
{
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT);
}
}
break;
default:
{
// Do nothing
@ -6973,6 +6987,11 @@ void P_SpawnSpecials(boolean fromnetsave)
break;
case 2002: // Linedef Trigger: Race Lap
break;
case 2003: // Respawn Line
break;
case 2004: // Bot controller
break;
case 499: // Linedef Executor: Enable/Disable Waypoints
break;

View file

@ -30,6 +30,7 @@
// SRB2Kart
#include "k_kart.h"
#include "k_race.h"
#include "k_battle.h"
#include "k_waypoint.h"
@ -332,6 +333,9 @@ static inline void P_RunThinkers(void)
ps_thlist_times[i] = I_GetTimeMicros() - ps_thlist_times[i];
}
if (gametyperules & GTR_CIRCUIT)
K_RunFinishLineBeam();
if (gametyperules & GTR_PAPERITEMS)
K_RunPaperItemSpawners();

View file

@ -1851,7 +1851,7 @@ static void P_3dMovement(player_t *player)
totalthrust.x = totalthrust.y = 0; // I forget if this is needed
totalthrust.z = FRACUNIT*P_MobjFlip(player->mo)/3; // A bit of extra push-back on slopes
if (player->kartstuff[k_sneakertimer] > 0)
if (K_SlopeResistance(player) == true)
{
totalthrust.z = -(totalthrust.z);
}
@ -2632,9 +2632,6 @@ static void P_DeathThink(player_t *player)
if (player->deadtimer < INT32_MAX)
player->deadtimer++;
if (player->bot) // don't allow bots to do any of the below, B_CheckRespawn does all they need for respawning already
goto notrealplayer;
if ((player->pflags & PF_GAMETYPEOVER) && (gametyperules & GTR_CIRCUIT))
{
player->karthud[khud_timeovercam]++;
@ -2677,8 +2674,6 @@ static void P_DeathThink(player_t *player)
}
}
notrealplayer:
if (!player->mo)
return;
@ -3075,6 +3070,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
mo = player->mo;
if (mo->hitlag > 0 || player->playerstate == PST_DEAD)
{
// Do not move the camera while in hitlag!
// The camera zooming out after you got hit makes it hard to focus on the vibration.
return true;
}
#ifndef NOCLIPCAM
cameranoclip = ((player->pflags & PF_NOCLIP)
|| (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)) // Noclipping player camera noclips too!!

View file

@ -623,13 +623,13 @@ extracolormap_t *R_ColormapForName(char *name)
// custom colormaps at runtime. NOTE: For GL mode, we only need to color
// data and not the colormap data.
//
static double deltas[256][3], map[256][3];
static double brightChange[256], map[256][3];
static int RoundUp(double number);
lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
{
double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb;
double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb, cdestbright;
double maskamt = 0, othermask = 0;
UINT8 cr = R_GetRgbaR(extra_colormap->rgba),
@ -668,6 +668,7 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
cdestr = cfr;
cdestg = cfg;
cdestb = cfb;
cdestbright = sqrt((cfr*cfr) + (cfg*cfg) + (cfb*cfb));
// fade alpha unused in software
// maskamt = (double)(cfa/24.0l);
@ -682,15 +683,15 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
// This code creates the colormap array used by software renderer
/////////////////////
{
double r, g, b, cbrightness;
double r, g, b, cbrightness, cbest, cdist;
int p;
lighttable_t *colormap_p;
// Initialise the map and delta arrays
// map[i] stores an RGB color (as double) for index i,
// which is then converted to SRB2's palette later
// deltas[i] stores a corresponding fade delta between the RGB color and the final fade color;
// map[i]'s values are decremented by after each use
// brightChange[i] is the value added/subtracted every step for the fade;
// map[i]'s values are in/decremented by it after each use
for (i = 0; i < 256; i++)
{
r = pMasterPalette[i].s.red;
@ -701,17 +702,31 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
map[i][0] = (cbrightness * cmaskr) + (r * othermask);
if (map[i][0] > 255.0l)
map[i][0] = 255.0l;
deltas[i][0] = (map[i][0] - cdestr) / (double)fadedist;
map[i][1] = (cbrightness * cmaskg) + (g * othermask);
if (map[i][1] > 255.0l)
map[i][1] = 255.0l;
deltas[i][1] = (map[i][1] - cdestg) / (double)fadedist;
map[i][2] = (cbrightness * cmaskb) + (b * othermask);
if (map[i][2] > 255.0l)
map[i][2] = 255.0l;
deltas[i][2] = (map[i][2] - cdestb) / (double)fadedist;
// Get the "best" color.
// Our brightest color's value, if we're fading to a darker color,
// or our (inverted) darkest color's value, if we're fading to a brighter color.
if (cbrightness < cdestbright)
{
cbest = 255.0l - min(r, min(g, b));
cdist = 255.0l - cdestbright;
}
else
{
cbest = max(r, max(g, b));
cdist = cdestbright;
}
// Add/subtract this value during fading.
brightChange[i] = fabs(cbest - cdist) / (double)fadedist;
}
// Now allocate memory for the actual colormap array itself!
@ -732,22 +747,28 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
if ((UINT32)p < fadestart)
continue;
#define ABS2(x) ((x) < 0 ? -(x) : (x))
if (ABS2(map[i][0] - cdestr) > ABS2(deltas[i][0]))
map[i][0] -= deltas[i][0];
else
// Add/subtract towards the destination color.
if (fabs(map[i][0] - cdestr) <= brightChange[i])
map[i][0] = cdestr;
if (ABS2(map[i][1] - cdestg) > ABS2(deltas[i][1]))
map[i][1] -= deltas[i][1];
else if (map[i][0] > cdestr)
map[i][0] -= brightChange[i];
else
map[i][0] += brightChange[i];
if (fabs(map[i][1] - cdestg) <= brightChange[i])
map[i][1] = cdestg;
if (ABS2(map[i][2] - cdestb) > ABS2(deltas[i][1]))
map[i][2] -= deltas[i][2];
else if (map[i][1] > cdestg)
map[i][1] -= brightChange[i];
else
map[i][1] += brightChange[i];
if (fabs(map[i][2] - cdestb) <= brightChange[i])
map[i][2] = cdestb;
#undef ABS2
else if (map[i][2] > cdestb)
map[i][2] -= brightChange[i];
else
map[i][2] += brightChange[i];
}
}

View file

@ -1236,28 +1236,24 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
patch_t *patch;
fixed_t xscale, yscale, shadowxscale, shadowyscale, shadowskew, x1, x2;
INT32 light = 0;
fixed_t scalemul; UINT8 trans;
fixed_t floordiff;
UINT8 trans = tr_transsub;
fixed_t groundz;
pslope_t *groundslope;
boolean isflipped = thing->eflags & MFE_VERTICALFLIP;
groundz = R_GetShadowZ(thing, &groundslope);
if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes
floordiff = abs((isflipped ? thing->height : 0) + thing->z - groundz);
if (thing->whiteshadow == true)
{
trans = tr_transadd;
}
trans = floordiff / (100*FRACUNIT) + 3;
if (trans >= 9) return;
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
patch = W_CachePatchName((thing->whiteshadow == true ? "LSHADOW" : "DSHADOW"), PU_CACHE);
patch = W_CachePatchName("DSHADOW", PU_CACHE);
xscale = FixedDiv(projection[viewssnum], tz);
yscale = FixedDiv(projectiony[viewssnum], tz);
shadowxscale = FixedMul(thing->radius*2, scalemul);
shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(groundz - viewz), tz));
shadowxscale = FixedMul(thing->radius*2, scale);
shadowyscale = FixedMul(FixedMul(thing->radius*2, scale), FixedDiv(abs(groundz - viewz), tz));
shadowyscale = min(shadowyscale, shadowxscale) / SHORT(patch->height);
shadowxscale /= SHORT(patch->width);
shadowskew = 0;
@ -1274,9 +1270,9 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
//CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope);
if (viewz < groundz)
shadowyscale += FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope);
shadowyscale += FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scale), zslope);
else
shadowyscale -= FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope);
shadowyscale -= FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scale), zslope);
shadowyscale = abs(shadowyscale);
@ -1354,16 +1350,9 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
else
shadow->extra_colormap = thing->subsector->sector->extra_colormap;
shadow->transmap = transtables + (trans<<FF_TRANSSHIFT);
shadow->transmap = transtables + ((trans-1) << FF_TRANSSHIFT);
if (thing->whiteshadow == true)
{
shadow->colormap = scalelight[LIGHTLEVELS - 1][0]; // full bright!
}
else
{
shadow->colormap = scalelight[0][0]; // full dark!
}
shadow->colormap = colormaps;
objectsdrawn++;
}

View file

@ -551,7 +551,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
else if (alphalevel == 15)
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
if (alphalevel >= 12)
return; // invis
if (alphalevel)
@ -744,7 +744,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_
else if (alphalevel == 15)
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
if (alphalevel >= 12)
return; // invis
if (alphalevel)
@ -997,7 +997,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
else if (alphalevel == 15)
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
if (alphalevel >= 12)
return; // invis
}

View file

@ -120,6 +120,8 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_70TRANS 0x00070000
#define V_80TRANS 0x00080000 // used to be V_8020TRANS
#define V_90TRANS 0x00090000
#define V_ADDTRANS 0x000A0000
#define V_SUBTRANS 0x000B0000
#define V_HUDTRANSHALF 0x000D0000
#define V_HUDTRANS 0x000E0000 // draw the hud translucent
#define V_HUDTRANSDOUBLE 0x000F0000