From 580f909c6ca805e1421f955779f55a259f8c3b3b Mon Sep 17 00:00:00 2001 From: ZTsukei Date: Tue, 7 Feb 2017 17:19:04 -0500 Subject: [PATCH] Added Accelcode, start boosting, reverted drifting, etc. --- src/d_clisrv.c | 4 + src/d_clisrv.h | 4 + src/d_main.c | 10 +- src/d_netcmd.c | 14 +- src/d_player.h | 8 + src/dehacked.c | 2 + src/doomdef.h | 6 +- src/doomstat.h | 6 +- src/g_game.c | 94 +++++--- src/hu_stuff.c | 86 ++++++- src/info.c | 236 ++++++++++++++---- src/info.h | 29 +++ src/k_kart.c | 330 +++++++++++++++++-------- src/k_kart.h | 8 +- src/lua_playerlib.c | 12 + src/lua_skinlib.c | 16 ++ src/m_menu.c | 31 ++- src/m_misc.h | 2 +- src/p_inter.c | 125 +++++++++- src/p_local.h | 4 + src/p_map.c | 532 +++++++++++++++++++++++++++++++++++++++++ src/p_saveg.c | 8 + src/p_setup.c | 10 +- src/p_spec.c | 195 ++++++++++----- src/p_user.c | 39 ++- src/r_main.c | 2 +- src/r_things.c | 14 ++ src/r_things.h | 5 + src/s_sound.c | 8 +- src/s_sound.h | 2 +- src/win32/Makefile.cfg | 4 +- src/win32/Srb2win.ico | Bin 372798 -> 82992 bytes src/y_inter.c | 389 +++++++++++++++++++++--------- src/y_inter.h | 18 +- 34 files changed, 1837 insertions(+), 416 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c0f81ba3..9ea9e842 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -506,6 +506,10 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->skin = LONG(players[i].skin); // Just in case Lua does something like // modify these at runtime + // SRB2kart + rsp->kartspeed = (fixed_t)LONG(players[i].kartspeed); + rsp->kartweight = (fixed_t)LONG(players[i].kartweight); + // rsp->normalspeed = (fixed_t)LONG(players[i].normalspeed); rsp->runspeed = (fixed_t)LONG(players[i].runspeed); rsp->thrustfactor = players[i].thrustfactor; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 79ade64f..6ebe8f53 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -168,6 +168,10 @@ typedef struct INT32 skin; // Just in case Lua does something like // modify these at runtime + // SRB2kart + UINT8 kartspeed; + UINT8 kartweight; + // fixed_t normalspeed; fixed_t runspeed; UINT8 thrustfactor; diff --git a/src/d_main.c b/src/d_main.c index d114a843..6023b906 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -259,7 +259,7 @@ static void D_Display(void) { if (intertype == int_spec) // Special Stage wipedefindex = wipe_specinter_toblack; - else if (intertype != int_coop) // Multiplayer + else //if (intertype != int_coop) // Multiplayer wipedefindex = wipe_multinter_toblack; } @@ -642,7 +642,7 @@ void D_StartTitle(void) INT32 i; if (netgame) { - if (gametype == GT_COOP) + if (gametype == GT_RACE) // SRB2kart { G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat @@ -687,7 +687,7 @@ void D_StartTitle(void) playerdeadview = false; displayplayer = consoleplayer = 0; //demosequence = -1; - gametype = GT_COOP; + gametype = GT_RACE; // SRB2kart paused = false; advancedemo = false; F_StartTitleScreen(); @@ -1244,9 +1244,9 @@ void D_SRB2Main(void) // user settings come before "+" parameters. if (dedicated) - COM_ImmedExecute(va("exec \"%s"PATHSEP"adedserv.cfg\"\n", srb2home)); + COM_ImmedExecute(va("exec \"%s"PATHSEP"kartserv.cfg\"\n", srb2home)); else - COM_ImmedExecute(va("exec \"%s"PATHSEP"autoexec.cfg\" -noerror\n", srb2home)); + COM_ImmedExecute(va("exec \"%s"PATHSEP"kartexec.cfg\" -noerror\n", srb2home)); if (!autostart) M_PushSpecialParameters(); // push all "+" parameters at the command buffer diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 50d06424..ab798549 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -351,7 +351,7 @@ static CV_PossibleValue_t timelimit_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NUL consvar_t cv_timelimit = {"timelimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t numlaps_cons_t[] = {{0, "MIN"}, {50, "MAX"}, {0, NULL}}; -consvar_t cv_numlaps = {"numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, +consvar_t cv_numlaps = {"numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_usemapnumlaps = {"usemaplaps", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -386,9 +386,9 @@ consvar_t cv_mute = {"mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange, consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL}; -INT16 gametype = GT_COOP; +INT16 gametype = GT_RACE; // SRB2kart boolean splitscreen = false; -boolean circuitmap = false; +boolean circuitmap = true; // SRB2kart INT32 adminplayer = -1; // ========================================================================= @@ -1017,8 +1017,8 @@ UINT8 CanChangeSkin(INT32 playernum) if (gametype == GT_COOP) return true; - // Can change skin during initial countdown. - if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE) + // Can change skin during initial countdown. // SRB2kart - Can always change skin in the level + if (gametype == GT_RACE || gametype == GT_COMPETITION) // if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE) return true; if (G_TagGametype()) @@ -2601,7 +2601,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) // Clear player score and rings if a spectator. if (players[playernum].spectator) { - players[playernum].score = 0; + //players[playernum].score = 0; // SRB2kart players[playernum].health = 1; if (players[playernum].mo) players[playernum].mo->health = 1; @@ -3453,7 +3453,7 @@ void D_GameTypeChanged(INT32 lastgametype) } else if (!multiplayer && !netgame) { - gametype = GT_COOP; + gametype = GT_RACE; // SRB2kart // These shouldn't matter anymore //CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); //CV_SetValue(&cv_itemrespawn, 0); diff --git a/src/d_player.h b/src/d_player.h index a3286828..06792418 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -247,6 +247,7 @@ typedef enum k_sounds, // Used this to avoid sounds being played every tic k_boosting, // Determines if you're currently shroom-boosting to change how drifting works + k_floorboost, // Prevents Mushroom sounds for a breif duration when triggered by a floor panel k_spinout, // Separate confirmation to prevent endless wipeout loops k_spinouttype, // Determines whether to thrust forward or not while spinning out; 0 = move forwards, 1 = stay still @@ -255,6 +256,7 @@ typedef enum k_boostcharge, // Charge-up for boosting at the start of the race, or when Lakitu drops you k_jmp, // In Mario Kart, letting go of the jump button stops the drift k_lakitu, // > 0 = Lakitu fishing, < 0 = Lakitu lap counter (was "player->airtime") // NOTE: Check for ->lakitu, replace with this + k_offroad, // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed k_itemroulette, // Used for the roulette when deciding what item to give you (was "pw_kartitem") k_itemclose, // Used to animate the item window closing (was "pw_psychic") @@ -297,6 +299,7 @@ typedef enum k_tripleredshell, // 0x1 = 1 Red Shell orbiting, 0x2 = 2 Red Shells orbiting // 0x4 = 3 Red Shells orbiting, 0x8 = Triple Red Shell in inventory k_lightning, // 0x1 = Lightning in inventory + k_kitchensink, // 0x1 = Sink in inventory NUMKARTSTUFF } kartstufftype_t; @@ -381,6 +384,11 @@ typedef struct player_s fixed_t dashspeed; // dashing speed INT32 dashtime; // tics dashing, used for rev sound + // SRB2kart + UINT8 kartspeed; // Kart speed stat between 1 and 9 + UINT8 kartweight; // Kart weight stat between 1 and 9 + // + fixed_t normalspeed; // Normal ground fixed_t runspeed; // Speed you break into the run animation UINT8 thrustfactor; // Thrust = thrustfactor * acceleration diff --git a/src/dehacked.c b/src/dehacked.c index 9d4e56af..a55519e8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -994,6 +994,8 @@ static const struct { {"CHRISTMAS",TOL_XMAS}, {"WINTER",TOL_XMAS}, + {"KART",TOL_KART}, // SRB2kart + {NULL, 0} }; diff --git a/src/doomdef.h b/src/doomdef.h index af7ed97b..06958eb8 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -220,8 +220,8 @@ extern FILE *logstream; // The maximum number of players, multiplayer/networking. // NOTE: it needs more than this to increase the number of players... -#define MAXPLAYERS 32 -#define MAXSKINS MAXPLAYERS +#define MAXPLAYERS 16 +#define MAXSKINS 32 #define PLAYERSMASK (MAXPLAYERS-1) #define MAXPLAYERNAME 21 @@ -325,7 +325,7 @@ typedef enum #define NEWTICRATERATIO 1 // try 4 for 140 fps :) #define NEWTICRATE (TICRATE*NEWTICRATERATIO) -#define RING_DIST 512*FRACUNIT // how close you need to be to a ring to attract it +#define RING_DIST 1280*FRACUNIT // how close you need to be to a ring to attract it #define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items. diff --git a/src/doomstat.h b/src/doomstat.h index 4fb391ec..8ac5e5ba 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -249,6 +249,9 @@ typedef struct // (This is not ifdeffed so the map header structure can stay identical, just in case.) UINT8 numCustomOptions; ///< Internal. For Lua custom value support. customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful. + + // SRB2kart + boolean automap; ///< Displays a level's white map outline in modified games } mapheader_t; // level flags @@ -287,7 +290,8 @@ enum TypeOfLevel TOL_MARIO = 0x0200, ///< Mario TOL_NIGHTS = 0x0400, ///< NiGHTS TOL_ERZ3 = 0x0800, ///< ERZ3 - TOL_XMAS = 0x1000 ///< Christmas NiGHTS + TOL_XMAS = 0x1000, ///< Christmas NiGHTS + TOL_KART = 0x4000 ///< Kart 32768 }; // Gametypes diff --git a/src/g_game.c b/src/g_game.c index 6c71e7de..dd9c46b2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -61,8 +61,9 @@ JoyType_t Joystick2; // 1024 bytes is plenty for a savegame #define SAVEGAMESIZE (1024) -char gamedatafilename[64] = "gamedata.dat"; -char timeattackfolder[64] = "main"; +// SRB2kart +char gamedatafilename[64] = "kartdata.dat"; +char timeattackfolder[64] = "kart"; char customversionstring[32] = "\0"; static void G_DoCompleted(void); @@ -189,7 +190,7 @@ boolean CheckForReverseGravity; // Powerup durations UINT16 invulntics = 20*TICRATE; UINT16 sneakertics = 20*TICRATE; -UINT16 flashingtics = 3*TICRATE; +UINT16 flashingtics = 3*TICRATE/2; // SRB2kart UINT16 tailsflytics = 8*TICRATE; UINT16 underwatertics = 30*TICRATE; UINT16 spacetimetics = 11*TICRATE + (TICRATE/2); @@ -446,7 +447,7 @@ consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "None", CV_SAVE, joyaxis_cons_ #endif -#if MAXPLAYERS > 32 +#if MAXPLAYERS > 16 #error "please update player_name table using the new value for MAXPLAYERS" #endif @@ -471,24 +472,8 @@ char player_names[MAXPLAYERS][MAXPLAYERNAME+1] = "Player 13", "Player 14", "Player 15", - "Player 16", - "Player 17", - "Player 18", - "Player 19", - "Player 20", - "Player 21", - "Player 22", - "Player 23", - "Player 24", - "Player 25", - "Player 26", - "Player 27", - "Player 28", - "Player 29", - "Player 30", - "Player 31", - "Player 32" -}; + "Player 16" +}; // SRB2kart - removed Players 17 through 32 INT16 rw_maximums[NUM_WEAPONS] = { @@ -1094,12 +1079,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) // some people strafe left & right with mouse buttons // those people are weird + + /* // SRB2kart - these aren't used in kart if (PLAYER1INPUTDOWN(gc_straferight)) side += sidemove[speed]; if (PLAYER1INPUTDOWN(gc_strafeleft)) side -= sidemove[speed]; - /* // SRB2kart - these aren't used in kart if (PLAYER1INPUTDOWN(gc_driftleft)) cmd->buttons |= BT_WEAPONNEXT; // Next Weapon if (PLAYER1INPUTDOWN(gc_driftright)) @@ -1983,6 +1969,7 @@ void G_Ticker(boolean run) { UINT32 i; INT32 buf; + ticcmd_t *cmd; P_MapStart(); // do player reborns if needed @@ -2023,8 +2010,20 @@ void G_Ticker(boolean run) // read/write demo and check turbo cheat for (i = 0; i < MAXPLAYERS; i++) { + cmd = &players[i].cmd; + if (playeringame[i]) - G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); + G_CopyTiccmd(cmd, &netcmds[buf][i], 1); + + // SRB2kart + // Save the dir the player is holding + // to allow items to be thrown forward or backward. + if (cmd->forwardmove > 0) + players[i].kartstuff[k_throwdir] = 1; + else if (cmd->forwardmove < 0) + players[i].kartstuff[k_throwdir] = -1; + else + players[i].kartstuff[k_throwdir] = 0; } // do main actions @@ -2146,6 +2145,10 @@ void G_PlayerReborn(INT32 player) INT32 continues; UINT8 charability; UINT8 charability2; + // SRB2kart + UINT8 kartspeed; + UINT8 kartweight; + // fixed_t normalspeed; fixed_t runspeed; UINT8 thrustfactor; @@ -2185,7 +2188,7 @@ void G_PlayerReborn(INT32 player) INT32 playerahead; INT32 starpostwp; INT32 lakitu; - + INT32 offroad; score = players[player].score; lives = players[player].lives; @@ -2208,6 +2211,10 @@ void G_PlayerReborn(INT32 player) skin = players[player].skin; charability = players[player].charability; charability2 = players[player].charability2; + // SRB2kart + kartspeed = players[player].kartspeed; + kartweight = players[player].kartweight; + // normalspeed = players[player].normalspeed; runspeed = players[player].runspeed; thrustfactor = players[player].thrustfactor; @@ -2238,6 +2245,7 @@ void G_PlayerReborn(INT32 player) playerahead = players[player].kartstuff[k_playerahead]; starpostwp = players[player].kartstuff[k_starpostwp]; lakitu = players[player].kartstuff[k_lakitu]; + offroad = players[player].kartstuff[k_offroad]; p = &players[player]; memset(p, 0, sizeof (*p)); @@ -2255,6 +2263,10 @@ void G_PlayerReborn(INT32 player) p->skin = skin; p->charability = charability; p->charability2 = charability2; + // SRB2kart + p->kartspeed = kartspeed; + p->kartweight = kartweight; + // p->normalspeed = normalspeed; p->runspeed = runspeed; p->thrustfactor = thrustfactor; @@ -2291,6 +2303,7 @@ void G_PlayerReborn(INT32 player) p->kartstuff[k_playerahead] = playerahead; p->kartstuff[k_starpostwp] = starpostwp; p->kartstuff[k_lakitu] = lakitu; + p->kartstuff[k_offroad] = offroad; // Don't do anything immediately p->pflags |= PF_USEDOWN; @@ -2646,7 +2659,7 @@ void G_DoReborn(INT32 playernum) // Do a wipe wipegamestate = -1; - if (player->starposttime) + if (player->starpostnum) // SRB2kart starpost = true; if (camera.chase) @@ -2691,7 +2704,7 @@ void G_DoReborn(INT32 playernum) // respawn at the start mobj_t *oldmo = NULL; - if (player->starposttime) + if (player->starpostnum) // SRB2kart starpost = true; // first dissasociate the corpse @@ -2832,7 +2845,7 @@ boolean G_TagGametype(void) INT16 G_TOLFlag(INT32 pgametype) { if (!multiplayer) return TOL_SP; - if (pgametype == GT_COOP) return TOL_COOP; + if (pgametype == GT_COOP) return TOL_RACE; // SRB2kart if (pgametype == GT_COMPETITION) return TOL_COMPETITION; if (pgametype == GT_RACE) return TOL_RACE; if (pgametype == GT_MATCH) return TOL_MATCH; @@ -3050,7 +3063,7 @@ static void G_DoWorldDone(void) { if (server) { - if (gametype == GT_COOP) + if (gametype == GT_RACE) // SRB2kart // don't reset player between maps D_MapChange(nextmap+1, gametype, ultimatemode, false, 0, false, false); else @@ -3683,6 +3696,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean { players[i].lives = cv_startinglives.value; players[i].continues = 0; + players[i].kartstuff[k_lakitu] = 0; // SRB2kart } else if (pultmode) { @@ -3693,6 +3707,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean { players[i].lives = 3; players[i].continues = 1; + players[i].kartstuff[k_lakitu] = 0; // SRB2kart } // The latter two should clear by themselves, but just in case @@ -4806,6 +4821,10 @@ void G_BeginRecording(void) WRITEUINT8(demo_p,player->actionspd>>FRACBITS); WRITEUINT8(demo_p,player->mindash>>FRACBITS); WRITEUINT8(demo_p,player->maxdash>>FRACBITS); + // SRB2kart + WRITEUINT8(demo_p,player->kartspeed>>FRACBITS); + WRITEUINT8(demo_p,player->kartweight>>FRACBITS); + // WRITEUINT8(demo_p,player->normalspeed>>FRACBITS); WRITEUINT8(demo_p,player->runspeed>>FRACBITS); WRITEUINT8(demo_p,player->thrustfactor); @@ -5041,7 +5060,7 @@ void G_DoPlayDemo(char *defdemoname) char skin[17],color[17],*n,*pdemoname; UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration; UINT32 randseed; - fixed_t actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor; + fixed_t actionspd,mindash,maxdash,kartspeed,kartweight,normalspeed,runspeed,jumpfactor; char msg[1024]; skin[16] = '\0'; @@ -5182,6 +5201,10 @@ void G_DoPlayDemo(char *defdemoname) actionspd = (fixed_t)READUINT8(demo_p)<width/4); + y = 100 - (AutomapPic->height/4); + } + else + { + x = 312 - (AutomapPic->width/2); + y = 60; + } + + V_DrawSmallScaledPatch(x, y, 0, AutomapPic); + + // Player's tiny icons on the Automap. + if (lumpnum != -1 && (!modifiedgame || (modifiedgame && mapheaderinfo[gamemap-1].automap))) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (players[i].mo && !players[i].spectator) + { + // amnum xpos & ypos are the icon's speed around the HUD. + // The number being divided by is for how fast it moves. + // The higher the number, the slower it moves. + + // am xpos & ypos are the icon's starting position. Withouht + // it, they wouldn't 'spawn' on the top-right side of the HUD. + amnumxpos = (players[i].mo->x / 320) >> FRACBITS; + amnumypos = (-players[i].mo->y / 340) >> FRACBITS; + + amxpos = (x + amnumxpos) - (iconprefix[players[i].skin]->width/4); + amypos = (y + amnumypos) - (iconprefix[players[i].skin]->height/4); + + if (!players[i].skincolor) // 'default' color + { + V_DrawSmallScaledPatch(amxpos, amypos, 0, iconprefix[players[i].skin]); + } + else + { + UINT8 *colormap = translationtables[players[i].skin] - 256 + (players[i].skincolor<<8); + V_DrawSmallMappedPatch(amxpos, amypos, 0,iconprefix[players[i].skin], colormap); + } + } + } + } + if (!splitscreen && maptol & TOL_KART && !hu_showscores) + HU_DrawRaceRankings(); + } + */ + // + // draw chat string plus cursor if (chat_on) HU_DrawChat(); @@ -1272,9 +1345,18 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (circuitmap) { if (players[tab[i].num].exiting) - V_DrawRightAlignedString(x+240, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); + V_DrawRightAlignedString(x+240, y, V_YELLOWMAP, va("%d:%02d.%02d", + players[tab[i].num].realtime/(60*TICRATE), + players[tab[i].num].realtime/TICRATE % 60, + players[tab[i].num].realtime % TICRATE)); + //V_DrawRightAlignedString(x+240, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); else - V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count)); + V_DrawRightAlignedString(x+240, y, 0, va("(CP%02d) %d:%02d.%02d", + tab[i].count, + players[tab[i].num].starposttime/(60*TICRATE), + players[tab[i].num].starposttime/TICRATE % 60, + (int)((players[tab[i].num].starposttime % TICRATE) * (100.00f/TICRATE)))); + //V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%u", tab[i].count)); } else V_DrawRightAlignedString(x+240, y, ((players[tab[i].num].health > 0) ? 0 : V_60TRANS), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); diff --git a/src/info.c b/src/info.c index 8c51df09..984fb250 100644 --- a/src/info.c +++ b/src/info.c @@ -56,7 +56,8 @@ char sprnames[NUMSPRITES + 1][5] = "SRBJ","SRBK","SRBL","SRBM","SRBN","SRBO", //SRB2kart Sprites "SPRG","BSPR","RNDM","SPRK","KFRE","DRIF","DSMO","FAKE","DFAK","BANA", - "DBAN","GSHE","GSTR","DGSH","RSHE","RSTR","DRSH","BOMB","BLIG","LIGH" + "DBAN","GSHE","GSTR","DGSH","RSHE","RSTR","DRSH","BOMB","BLIG","LIGH", + "SINK","SITR","POKE" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -2589,30 +2590,30 @@ state_t states[NUMSTATES] = {SPR_KFRE, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_KARTFIRE8}, // S_KARTFIRE7 {SPR_KFRE, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_NULL}, // S_KARTFIRE8 - {SPR_FAKE, 0, 3, {NULL}, 0, 0, S_FAKEITEM2}, // S_FAKEITEM1 - {SPR_FAKE, 1, 3, {NULL}, 0, 0, S_FAKEITEM3}, // S_FAKEITEM2 - {SPR_FAKE, 2, 3, {NULL}, 0, 0, S_FAKEITEM4}, // S_FAKEITEM3 - {SPR_FAKE, 3, 3, {NULL}, 0, 0, S_FAKEITEM5}, // S_FAKEITEM4 - {SPR_FAKE, 4, 3, {NULL}, 0, 0, S_FAKEITEM6}, // S_FAKEITEM5 - {SPR_FAKE, 5, 3, {NULL}, 0, 0, S_FAKEITEM7}, // S_FAKEITEM6 - {SPR_FAKE, 6, 3, {NULL}, 0, 0, S_FAKEITEM8}, // S_FAKEITEM7 - {SPR_FAKE, 7, 3, {NULL}, 0, 0, S_FAKEITEM9}, // S_FAKEITEM8 - {SPR_FAKE, 8, 3, {NULL}, 0, 0, S_FAKEITEM10}, // S_FAKEITEM9 - {SPR_FAKE, 9, 3, {NULL}, 0, 0, S_FAKEITEM11}, // S_FAKEITEM10 - {SPR_FAKE, 10, 3, {NULL}, 0, 0, S_FAKEITEM12}, // S_FAKEITEM11 - {SPR_FAKE, 11, 3, {NULL}, 0, 0, S_FAKEITEM13}, // S_FAKEITEM12 - {SPR_FAKE, 12, 3, {NULL}, 0, 0, S_FAKEITEM14}, // S_FAKEITEM13 - {SPR_FAKE, 13, 3, {NULL}, 0, 0, S_FAKEITEM15}, // S_FAKEITEM14 - {SPR_FAKE, 14, 3, {NULL}, 0, 0, S_FAKEITEM16}, // S_FAKEITEM15 - {SPR_FAKE, 15, 3, {NULL}, 0, 0, S_FAKEITEM17}, // S_FAKEITEM16 - {SPR_FAKE, 16, 3, {NULL}, 0, 0, S_FAKEITEM18}, // S_FAKEITEM17 - {SPR_FAKE, 17, 3, {NULL}, 0, 0, S_FAKEITEM19}, // S_FAKEITEM18 - {SPR_FAKE, 18, 3, {NULL}, 0, 0, S_FAKEITEM20}, // S_FAKEITEM19 - {SPR_FAKE, 19, 3, {NULL}, 0, 0, S_FAKEITEM21}, // S_FAKEITEM20 - {SPR_FAKE, 20, 3, {NULL}, 0, 0, S_FAKEITEM22}, // S_FAKEITEM21 - {SPR_FAKE, 21, 3, {NULL}, 0, 0, S_FAKEITEM23}, // S_FAKEITEM22 - {SPR_FAKE, 22, 3, {NULL}, 0, 0, S_FAKEITEM24}, // S_FAKEITEM23 - {SPR_FAKE, 23, 3, {NULL}, 0, 0, S_FAKEITEM1}, // S_FAKEITEM24 + {SPR_FITE, 0, 3, {NULL}, 0, 0, S_FAKEITEM2}, // S_FAKEITEM1 + {SPR_FITE, 1, 3, {NULL}, 0, 0, S_FAKEITEM3}, // S_FAKEITEM2 + {SPR_FITE, 2, 3, {NULL}, 0, 0, S_FAKEITEM4}, // S_FAKEITEM3 + {SPR_FITE, 3, 3, {NULL}, 0, 0, S_FAKEITEM5}, // S_FAKEITEM4 + {SPR_FITE, 4, 3, {NULL}, 0, 0, S_FAKEITEM6}, // S_FAKEITEM5 + {SPR_FITE, 5, 3, {NULL}, 0, 0, S_FAKEITEM7}, // S_FAKEITEM6 + {SPR_FITE, 6, 3, {NULL}, 0, 0, S_FAKEITEM8}, // S_FAKEITEM7 + {SPR_FITE, 7, 3, {NULL}, 0, 0, S_FAKEITEM9}, // S_FAKEITEM8 + {SPR_FITE, 8, 3, {NULL}, 0, 0, S_FAKEITEM10}, // S_FAKEITEM9 + {SPR_FITE, 9, 3, {NULL}, 0, 0, S_FAKEITEM11}, // S_FAKEITEM10 + {SPR_FITE, 10, 3, {NULL}, 0, 0, S_FAKEITEM12}, // S_FAKEITEM11 + {SPR_FITE, 11, 3, {NULL}, 0, 0, S_FAKEITEM13}, // S_FAKEITEM12 + {SPR_FITE, 12, 3, {NULL}, 0, 0, S_FAKEITEM14}, // S_FAKEITEM13 + {SPR_FITE, 13, 3, {NULL}, 0, 0, S_FAKEITEM15}, // S_FAKEITEM14 + {SPR_FITE, 14, 3, {NULL}, 0, 0, S_FAKEITEM16}, // S_FAKEITEM15 + {SPR_FITE, 15, 3, {NULL}, 0, 0, S_FAKEITEM17}, // S_FAKEITEM16 + {SPR_FITE, 16, 3, {NULL}, 0, 0, S_FAKEITEM18}, // S_FAKEITEM17 + {SPR_FITE, 17, 3, {NULL}, 0, 0, S_FAKEITEM19}, // S_FAKEITEM18 + {SPR_FITE, 18, 3, {NULL}, 0, 0, S_FAKEITEM20}, // S_FAKEITEM19 + {SPR_FITE, 19, 3, {NULL}, 0, 0, S_FAKEITEM21}, // S_FAKEITEM20 + {SPR_FITE, 20, 3, {NULL}, 0, 0, S_FAKEITEM22}, // S_FAKEITEM21 + {SPR_FITE, 21, 3, {NULL}, 0, 0, S_FAKEITEM23}, // S_FAKEITEM22 + {SPR_FITE, 22, 3, {NULL}, 0, 0, S_FAKEITEM24}, // S_FAKEITEM23 + {SPR_FITE, 23, 3, {NULL}, 0, 0, S_FAKEITEM1}, // S_FAKEITEM24 {SPR_DFAK, 0, 175, {NULL}, 0, 0, S_FAKEITEM1}, // S_DEADFAKEITEM {SPR_BANA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BANANAITEM @@ -2642,15 +2643,15 @@ state_t states[NUMSTATES] = {SPR_GSHE, 5, 2, {A_SmokeTrailer}, MT_GREENTRAIL, 0, S_GREENITEM7}, // S_GREENITEM6 {SPR_GSHE, 6, 2, {A_SmokeTrailer}, MT_GREENTRAIL, 0, S_GREENITEM8}, // S_GREENITEM7 {SPR_GSHE, 7, 2, {A_SmokeTrailer}, MT_GREENTRAIL, 0, S_GREENITEM1}, // S_GREENITEM8 - {SPR_GSHE, 0, 1, {NULL}, 0, 0, S_GREENTRAIL2}, // S_GREENTRAIL1 - {SPR_GSHE, 1, 1, {NULL}, 0, 0, S_GREENTRAIL3}, // S_GREENTRAIL2 - {SPR_GSHE, 2, 1, {NULL}, 0, 0, S_GREENTRAIL4}, // S_GREENTRAIL3 - {SPR_GSHE, 3, 1, {NULL}, 0, 0, S_GREENTRAIL5}, // S_GREENTRAIL4 - {SPR_GSHE, 4, 1, {NULL}, 0, 0, S_GREENTRAIL6}, // S_GREENTRAIL5 - {SPR_GSHE, 5, 1, {NULL}, 0, 0, S_GREENTRAIL7}, // S_GREENTRAIL6 - {SPR_GSHE, 6, 1, {NULL}, 0, 0, S_GREENTRAIL8}, // S_GREENTRAIL7 - {SPR_GSHE, 7, 1, {NULL}, 0, 0, S_GREENTRAIL9}, // S_GREENTRAIL8 - {SPR_GSHE, 8, 1, {NULL}, 0, 0, S_NULL}, // S_GREENTRAIL9 + {SPR_GSTR, 0, 1, {NULL}, 0, 0, S_GREENTRAIL2}, // S_GREENTRAIL1 + {SPR_GSTR, 1, 1, {NULL}, 0, 0, S_GREENTRAIL3}, // S_GREENTRAIL2 + {SPR_GSTR, 2, 1, {NULL}, 0, 0, S_GREENTRAIL4}, // S_GREENTRAIL3 + {SPR_GSTR, 3, 1, {NULL}, 0, 0, S_GREENTRAIL5}, // S_GREENTRAIL4 + {SPR_GSTR, 4, 1, {NULL}, 0, 0, S_GREENTRAIL6}, // S_GREENTRAIL5 + {SPR_GSTR, 5, 1, {NULL}, 0, 0, S_GREENTRAIL7}, // S_GREENTRAIL6 + {SPR_GSTR, 6, 1, {NULL}, 0, 0, S_GREENTRAIL8}, // S_GREENTRAIL7 + {SPR_GSTR, 7, 1, {NULL}, 0, 0, S_GREENTRAIL9}, // S_GREENTRAIL8 + {SPR_GSTR, 8, 1, {NULL}, 0, 0, S_NULL}, // S_GREENTRAIL9 {SPR_DGSH, 0, 175, {NULL}, 0, 0, S_NULL}, // S_DEADGREEN {SPR_RSHE, 0, 2, {A_RotateSpikeBall}, 0, 0, S_TRIPLEREDSHIELD2}, // S_TRIPLEREDSHIELD1 @@ -2679,15 +2680,15 @@ state_t states[NUMSTATES] = {SPR_RSHE, 7, 2, {A_DualAction}, S_REDITEMCHASE, S_REDITEMTRAIL, S_REDITEM1}, // S_REDITEM8 {SPR_RSHE, 0, 2, {A_RedShellChase}, 0, 0, S_REDITEM2}, // S_REDITEMCHASE {SPR_RSHE, 1, 2, {A_SmokeTrailer}, MT_REDTRAIL, 0, S_REDITEM3}, // S_REDITEMTRAIL - {SPR_RSHE, 0, 1, {NULL}, 0, 0, S_REDTRAIL2}, // S_REDTRAIL1 - {SPR_RSHE, 1, 1, {NULL}, 0, 0, S_REDTRAIL3}, // S_REDTRAIL2 - {SPR_RSHE, 2, 1, {NULL}, 0, 0, S_REDTRAIL4}, // S_REDTRAIL3 - {SPR_RSHE, 3, 1, {NULL}, 0, 0, S_REDTRAIL5}, // S_REDTRAIL4 - {SPR_RSHE, 4, 1, {NULL}, 0, 0, S_REDTRAIL6}, // S_REDTRAIL5 - {SPR_RSHE, 5, 1, {NULL}, 0, 0, S_REDTRAIL7}, // S_REDTRAIL6 - {SPR_RSHE, 6, 1, {NULL}, 0, 0, S_REDTRAIL8}, // S_REDTRAIL7 - {SPR_RSHE, 7, 1, {NULL}, 0, 0, S_REDTRAIL9}, // S_REDTRAIL8 - {SPR_RSHE, 8, 1, {NULL}, 0, 0, S_NULL}, // S_REDTRAIL9 + {SPR_RSTR, 0, 1, {NULL}, 0, 0, S_REDTRAIL2}, // S_REDTRAIL1 + {SPR_RSTR, 1, 1, {NULL}, 0, 0, S_REDTRAIL3}, // S_REDTRAIL2 + {SPR_RSTR, 2, 1, {NULL}, 0, 0, S_REDTRAIL4}, // S_REDTRAIL3 + {SPR_RSTR, 3, 1, {NULL}, 0, 0, S_REDTRAIL5}, // S_REDTRAIL4 + {SPR_RSTR, 4, 1, {NULL}, 0, 0, S_REDTRAIL6}, // S_REDTRAIL5 + {SPR_RSTR, 5, 1, {NULL}, 0, 0, S_REDTRAIL7}, // S_REDTRAIL6 + {SPR_RSTR, 6, 1, {NULL}, 0, 0, S_REDTRAIL8}, // S_REDTRAIL7 + {SPR_RSTR, 7, 1, {NULL}, 0, 0, S_REDTRAIL9}, // S_REDTRAIL8 + {SPR_RSTR, 8, 1, {NULL}, 0, 0, S_NULL}, // S_REDTRAIL9 {SPR_DRSH, 0, 175, {NULL}, 0, 0, S_NULL}, // S_DEADRED {SPR_BOMB, 0, 1, {NULL}, 0, 0, S_BOMBSHIELD}, // S_BOMBSHIELD @@ -2706,6 +2707,20 @@ state_t states[NUMSTATES] = {SPR_LIGH, 0, 2, {NULL}, 0, 0, S_LIGHTNING4}, // S_LIGHTNING3 {SPR_LIGH, 0, 2, {NULL}, 0, 0, S_NULL}, // S_LIGHTNING4 + {SPR_SINK, 0, 4, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK + {SPR_SITR, 0, 1, {NULL}, 0, 0, S_SINKTRAIL2}, // S_SINKTRAIL1 + {SPR_SITR, 1, 5, {NULL}, 0, 0, S_SINKTRAIL3}, // S_SINKTRAIL2 + {SPR_SITR, 2, 3, {NULL}, 0, 0, S_NULL}, // S_SINKTRAIL3 + + {SPR_POKE, 0, 2, {A_MoveAbsolute}, 0, 2, S_POKEY2}, // S_POKEY1 + {SPR_POKE, 1, 2, {A_MoveAbsolute}, 0, 2, S_POKEY3}, // S_POKEY2 + {SPR_POKE, 2, 2, {A_MoveAbsolute}, 0, 2, S_POKEY4}, // S_POKEY3 + {SPR_POKE, 3, 2, {A_MoveAbsolute}, 0, 2, S_POKEY1}, // S_POKEY4 + {SPR_POKE, 0, 2, {A_MoveAbsolute}, 180, 2, S_POKEY6}, // S_POKEY5 + {SPR_POKE, 1, 2, {A_MoveAbsolute}, 180, 2, S_POKEY7}, // S_POKEY6 + {SPR_POKE, 2, 2, {A_MoveAbsolute}, 180, 2, S_POKEY8}, // S_POKEY7 + {SPR_POKE, 3, 2, {A_MoveAbsolute}, 180, 2, S_POKEY5}, // S_POKEY8 + {SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_POKEYIDLE #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK @@ -14881,6 +14896,141 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SINK + -1, // doomednum + S_SINK, // spawnstate + 105, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + 256*FRACUNIT, // painstate + 100, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_shbrk, // deathsound + 0, // speed + 16*FRACUNIT, // radius + 24*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_bomb, // activesound + MF_BOUNCE|MF_FLOAT|MF_NOCLIPTHING|MF_MISSILE|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_SINKTRAIL + -1, // doomednum + S_SINKTRAIL1, // 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 + 8, // speed + 20*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_POKEY + 2002, // doomednum + S_POKEY1, // spawnstate + 1000, // spawnhealth + S_POKEY1, // seestate + sfx_None, // seesound + 32, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 100, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 3, // speed + 21*FRACUNIT, // radius + 69*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_ENEMYFLIP + 2003, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 100, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 32*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_WAYPOINT + 2001, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 100, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 1*FRACUNIT, // radius + 2*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + #ifdef SEENAMES { // MT_NAMECHECK -1, // doomednum diff --git a/src/info.h b/src/info.h index 3ddd9d24..4af684e6 100644 --- a/src/info.h +++ b/src/info.h @@ -598,6 +598,11 @@ typedef enum sprite SPR_BOMB, // Bob-omb SPR_BLIG, // Blue Lightning SPR_LIGH, // Lightning + SPR_SINK, // Kitchen Sink + SPR_SITR, // Kitchen Sink Trail + + // Additional Kart Objects + SPR_POKE, // Lightning SPR_FIRSTFREESLOT, SPR_LASTFREESLOT = SPR_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1, @@ -3194,6 +3199,23 @@ typedef enum state S_LIGHTNING3, S_LIGHTNING4, + // The legend + S_SINK, + S_SINKTRAIL1, + S_SINKTRAIL2, + S_SINKTRAIL3, + + // Pokey + S_POKEY1, + S_POKEY2, + S_POKEY3, + S_POKEY4, + S_POKEY5, + S_POKEY6, + S_POKEY7, + S_POKEY8, + S_POKEYIDLE, + #ifdef SEENAMES S_NAMECHECK, #endif @@ -3764,6 +3786,13 @@ typedef enum mobj_type MT_BLUEEXPLOSION, MT_LIGHTNING, + MT_SINK, // Kitchen Sink Stuff + MT_SINKTRAIL, + + MT_POKEY, // Huh, thought this was a default asset for some reason, guess not. + MT_ENEMYFLIP, + MT_WAYPOINT, + #ifdef SEENAMES MT_NAMECHECK, #endif diff --git a/src/k_kart.c b/src/k_kart.c index bee2aaf2..71210a63 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9,6 +9,7 @@ #include "g_game.h" #include "m_random.h" #include "p_local.h" +#include "p_slopes.h" #include "r_draw.h" #include "r_local.h" #include "s_sound.h" @@ -898,7 +899,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { // This spawns the drift sparks when k_driftcharge hits 30. Its own AI handles life/death and color - if ((player->kartstuff[k_drift] == 1 || player->kartstuff[k_drift] == -1) + if ((player->kartstuff[k_drift] >= 1 || player->kartstuff[k_drift] <= -1) && player->kartstuff[k_driftcharge] == 30) P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_DRIFT)->target = player->mo; @@ -911,12 +912,18 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_spinouttimer]) player->kartstuff[k_spinouttimer]--; + if (player->kartstuff[k_spinout] == 0 && player->kartstuff[k_spinouttimer] == 0 && player->powers[pw_flashing] == flashingtics) + player->powers[pw_flashing]--; + if (player->kartstuff[k_magnettimer]) player->kartstuff[k_magnettimer]--; if (player->kartstuff[k_mushroomtimer]) player->kartstuff[k_mushroomtimer]--; + if (player->kartstuff[k_floorboost]) + player->kartstuff[k_floorboost]--; + if (player->kartstuff[k_startimer]) player->kartstuff[k_startimer]--; @@ -1026,23 +1033,26 @@ void K_PlayTauntSound(mobj_t *source) S_StartSound(source, sfx_taunt4); } -boolean K_SpinPlayer(player_t *player, mobj_t *source) +void K_SpinPlayer(player_t *player, mobj_t *source) { if (player->health <= 0) - return false; + return; if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinout] > 0) || player->kartstuff[k_startimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_bootaketimer] > 0) - return false; + return; player->kartstuff[k_mushroomtimer] = 0; - if (player->kartstuff[k_spinouttype] == 0) + if (player->kartstuff[k_spinouttype] <= 0) { - player->kartstuff[k_spinouttimer] = 2*TICRATE; + if (player->kartstuff[k_spinouttype] == 0) + player->kartstuff[k_spinouttimer] = 2*TICRATE; + else + player->kartstuff[k_spinouttimer] = 3*TICRATE/2; if (player->speed < player->normalspeed/4) - P_InstaThrust(player->mo, player->mo->angle, player->normalspeed*FRACUNIT/4); + P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->normalspeed/4, player->mo->scale)); S_StartSound(player->mo, sfx_slip); } @@ -1058,17 +1068,17 @@ boolean K_SpinPlayer(player_t *player, mobj_t *source) player->kartstuff[k_spinouttype] = 0; - return true; + return; } -boolean K_SquishPlayer(player_t *player, mobj_t *source) +void K_SquishPlayer(player_t *player, mobj_t *source) { if (player->health <= 0) - return false; + return; if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_startimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_bootaketimer] > 0) - return false; + return; player->kartstuff[k_mushroomtimer] = 0; @@ -1083,17 +1093,17 @@ boolean K_SquishPlayer(player_t *player, mobj_t *source) P_PlayRinglossSound(player->mo); - return true; + return; } -boolean K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer +void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer { if (player->health <= 0) - return false; + return; if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinout] > 0) || player->kartstuff[k_startimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_bootaketimer] > 0) - return false; + return; player->mo->momz = 18*FRACUNIT; player->mo->momx = player->mo->momy = 0; @@ -1113,7 +1123,7 @@ boolean K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we P_PlayRinglossSound(player->mo); - return true; + return; } 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) @@ -1281,7 +1291,7 @@ void K_SpawnDriftTrail(player_t *player) ground -= FixedMul(mobjinfo[MT_MUSHROOMTRAIL].height, player->mo->scale); } #endif - if ((player->kartstuff[k_drift] == 1 || player->kartstuff[k_drift] == -1) && player->kartstuff[k_mushroomtimer] == 0) + if ((player->kartstuff[k_drift] >= 1 || player->kartstuff[k_drift] <= -1) && player->kartstuff[k_mushroomtimer] == 0) flame = P_SpawnMobj(newx, newy, ground, MT_DRIFTSMOKE); else flame = P_SpawnMobj(newx, newy, ground, MT_MUSHROOMTRAIL); @@ -1558,9 +1568,11 @@ static void K_DoBooSteal(player_t * player) void K_DoMushroom(player_t *player, boolean doPFlag) { - S_StartSound(player->mo, sfx_mush); + if (!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) + S_StartSound(player->mo, sfx_mush); + player->kartstuff[k_mushroomtimer] = mushroomtime; - + if (doPFlag) player->pflags |= PF_ATTACKDOWN; @@ -1594,6 +1606,187 @@ void K_DoLightning(player_t *player, boolean bluelightning) player->kartstuff[k_sounds] = 70; } +void K_KartDrift(player_t *player, ticcmd_t *cmd, boolean onground) +{ + // Drifting is actually straffing + automatic turning. + // Holding the Jump button will enable drifting. + if (cmd->buttons & BT_DRIFTRIGHT) + player->kartstuff[k_turndir] = 1; + else if (cmd->buttons & BT_DRIFTLEFT) + player->kartstuff[k_turndir] = -1; + else + player->kartstuff[k_turndir] = 0; + + // Drift Release (Moved here so you can't "chain" drifts) + if ((player->kartstuff[k_drift] == 0) + // || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1)) + && player->kartstuff[k_driftcharge] < 30 + && onground) + { + player->kartstuff[k_drift] = 0; + player->kartstuff[k_driftcharge] = 0; + } + else if ((player->kartstuff[k_drift] == 0) + // || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1)) + && (player->kartstuff[k_driftcharge] >= 30 && player->kartstuff[k_driftcharge] < 60) + && onground) + { + player->powers[pw_sneakers] += 17; + S_StartSound(player->mo, sfx_mush); + player->kartstuff[k_drift] = 0; + player->kartstuff[k_driftcharge] = 0; + } + else if ((player->kartstuff[k_drift] == 0) + // || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1)) + && player->kartstuff[k_driftcharge] >= 60 + && onground) + { + player->powers[pw_sneakers] += 35; + S_StartSound(player->mo, sfx_mush); + player->kartstuff[k_drift] = 0; + player->kartstuff[k_driftcharge] = 0; + } + + // Drifting: left or right? + if (player->kartstuff[k_turndir] == 1 && player->speed > 10 && player->kartstuff[k_jmp] == 1 + && player->kartstuff[k_drift] < 3 && player->kartstuff[k_drift] > -1) // && player->kartstuff[k_drift] != 1) + player->kartstuff[k_drift] = 1; + else if (player->kartstuff[k_turndir] == -1 && player->speed > 10 && player->kartstuff[k_jmp] == 1 + && player->kartstuff[k_drift] > -3 && player->kartstuff[k_drift] < 1) // && player->kartstuff[k_drift] != -1) + player->kartstuff[k_drift] = -1; + else if (player->kartstuff[k_jmp] == 0) // || player->kartstuff[k_turndir] == 0) + player->kartstuff[k_drift] = 0; + + // Incease/decrease the drift value to continue drifting in that direction + if (player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_jmp] == 1 && onground + && (player->kartstuff[k_drift] >= 1 || player->kartstuff[k_drift] <= -1)) + { + player->kartstuff[k_driftcharge]++; + + if (player->kartstuff[k_drift] >= 1) // Drifting to the Right + { + player->kartstuff[k_drift]++; + if (player->kartstuff[k_drift] > 3) + player->kartstuff[k_drift] = 3; + + // Left = +450 Right = -450 + // Player 1 + if (player == &players[consoleplayer]) + { + if (player->kartstuff[k_turndir] == -1) // Turning Left while Drifting Right + localangle -= 600*FRACUNIT; + else if (player->kartstuff[k_turndir] == 1) // Turning Right while Drifting Right + localangle -= 225*FRACUNIT; + else // No Direction while Drifting Right + localangle -= 450*FRACUNIT; + } + + // Player 2 + if (splitscreen && player == &players[secondarydisplayplayer]) + { + + } + } + else if (player->kartstuff[k_drift] <= -1) // Drifting to the Left + { + player->kartstuff[k_drift]--; + if (player->kartstuff[k_drift] < -3) + player->kartstuff[k_drift] = -3; + + // Left = +450 Right = -450 + // Player 1 + if (player == &players[consoleplayer]) + { + if (player->kartstuff[k_turndir] == 1) // Turning Right while Drifting Left + localangle += 600*FRACUNIT; + else if (player->kartstuff[k_turndir] == -1) // Turning Left while Drifting Left + localangle += 225*FRACUNIT; + else // No Direction while Drifting Left + localangle += 450*FRACUNIT; + } + + // Player 2 + if (splitscreen && player == &players[secondarydisplayplayer] && player->kartstuff[k_turndir] == 1) + localangle2 += (300+192)*FRACUNIT; + else if (splitscreen && player == &players[secondarydisplayplayer]) + localangle2 += (300)*FRACUNIT; + } + } + + // Stop drifting + if (player->kartstuff[k_spinouttimer] > 0 // banana peel + || player->speed < 10) // you're too slow! + { + player->kartstuff[k_drift] = 0; + player->kartstuff[k_driftcharge] = 0; + } +} + +UINT64 K_GetKartSpeed(player_t *player) +{ + UINT64 k_speed = 47*FRACUNIT + FRACUNIT/2; + + // Speed is a value between 48 and 52, incremented by halves + k_speed += player->kartspeed*FRACUNIT/2; + + return k_speed; +} + +UINT64 K_GetKartAccel(player_t *player) +{ + UINT64 k_accel = 45; + + // Acceleration is a given base, minus the speed value. + k_accel -= 3*player->kartspeed; + + return k_accel; +} + +fixed_t K_3dKartMovement(player_t *player, boolean onground) +{ + // If the player isn't on the ground, there is no change in speed + if (!onground) return 0; + + fixed_t accelmax = 2000; // AccelMax + fixed_t f_beater = 2*FRACUNIT - (0xE8<<(FRACBITS-8)); //1.10345f; // Friction Beater Friction = (0xE8 << (FRACBITS-8)) + fixed_t g_cc = 1*FRACUNIT; // Game CC + + fixed_t newspeed, oldspeed, finalspeed; + fixed_t boostpower = 1*FRACUNIT; + fixed_t p_speed = K_GetKartSpeed(player); + fixed_t p_accel = K_GetKartAccel(player); + + sector_t *nextsector = R_PointInSubsector(player->mo->x + player->mo->momx*2, player->mo->y + player->mo->momy*2)->sector; + + // Determine boostpower by checking every power. There's probably a cleaner way to do this, but eh whatever. + if (!(player->kartstuff[k_startimer] || player->kartstuff[k_bootaketimer] || player->powers[pw_sneakers] || + player->kartstuff[k_mushroomtimer] || player->kartstuff[k_growshrinktimer] > 1) && P_IsObjectOnGround(player->mo) && + nextsector->special & 256 && nextsector->special != 768 && (nextsector->special != 1024 || nextsector->special != 4864)) + boostpower = FixedMul(boostpower, FRACUNIT/4); // Off-road, unless you're ignoring off-road. + if (player->kartstuff[k_growshrinktimer] < -1) boostpower = FixedMul(boostpower, FRACUNIT/3); // Shrink + if (player->kartstuff[k_squishedtimer] > 0) boostpower = FixedMul(boostpower, FRACUNIT/2); // Squished + if (player->powers[pw_sneakers]) boostpower = FixedMul(boostpower, FRACUNIT+FRACUNIT/4); // Slide Boost + if (player->kartstuff[k_growshrinktimer] > 1) boostpower = FixedMul(boostpower, FRACUNIT+FRACUNIT/3); // Mega Mushroom + if (player->kartstuff[k_startimer]) boostpower = FixedMul(boostpower, FRACUNIT+FRACUNIT/2); // Star + if (player->kartstuff[k_mushroomtimer]) boostpower = FixedMul(boostpower, FRACUNIT+FRACUNIT/1); // Mushroom + + // Boostpower is applied to each stat individually, and NOT the calculation. + // Applying to the calculation fails due to friction never getting beaten, or getting overshot really far. + // It's easier this way. + // Similarly, the CC of the game is also multiplied directly. + // This assures a growth in speed without affecting acceleration curving. + p_speed = FixedMul(FixedMul(p_speed, boostpower), g_cc); + p_accel = FixedMul(FixedMul(p_accel, boostpower), g_cc); + accelmax = FixedMul(FixedMul(accelmax, boostpower), g_cc); + + // Now, the code that made Iceman's eyes rub erotically against a toaster. + oldspeed = FixedMul(FixedMul(P_AproxDistance(player->rmomx, player->rmomy), player->mo->scale), f_beater); + newspeed = FixedMul(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), f_beater); + finalspeed = newspeed - oldspeed; + + return (fixed_t)finalspeed; +} + void K_MoveKartPlayer(player_t *player, ticcmd_t *cmd, boolean onground) { boolean ATTACK_IS_DOWN = ((cmd->buttons & BT_ATTACK) && !(player->pflags & PF_ATTACKDOWN)); @@ -1972,9 +2165,9 @@ void K_MoveKartPlayer(player_t *player, ticcmd_t *cmd, boolean onground) if (player->kartstuff[k_mushroomtimer] > 0 && player->kartstuff[k_boosting] == 0 && onground) { cmd->forwardmove = 1; - if (player->kartstuff[k_drift] == 1) + if (player->kartstuff[k_drift] >= 1) P_InstaThrust(player->mo, player->mo->angle+ANGLE_45, 55*FRACUNIT); - else if (player->kartstuff[k_drift] == -1) + else if (player->kartstuff[k_drift] <= -1) P_InstaThrust(player->mo, player->mo->angle-ANGLE_45, 55*FRACUNIT); else P_InstaThrust(player->mo, player->mo->angle, 55*FRACUNIT); @@ -2020,79 +2213,7 @@ void K_MoveKartPlayer(player_t *player, ticcmd_t *cmd, boolean onground) if (splitscreen && player == &players[secondarydisplayplayer]) CV_SetValue(&cv_cam2_dist, 190); - // DRRRRIIIIFFFFFFTTT!!!! - // Drifting is actually straffing + automatic turning. - // Holding the Jump button will enable drifting. - - // Instead of instantly straffing, you go from running - // straight to slowly turning left/right. - // 536870912 is the normal straffing angle, 90 degrees. - // 35791394 is the speed that's added from 0 to 90. - - // localangle is SRB2's turning code, not angle direction. - // Adding or subtracting by 300 is how much you can turn. - // The higher it is, the faster you turn. - - if (cmd->buttons & BT_DRIFTRIGHT) - player->kartstuff[k_turndir] = 1; - else if (cmd->buttons & BT_DRIFTLEFT) - player->kartstuff[k_turndir] = -1; - else - player->kartstuff[k_turndir] = 0; - - // Moved here so you can't "chain" drifts - // Drift Release - if (((player->kartstuff[k_drift] == 0) || (player->kartstuff[k_drift] == 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] == -1 && player->kartstuff[k_turndir] != -1)) - && player->kartstuff[k_driftcharge] < 30 - && onground) - { - player->kartstuff[k_drift] = 0; - player->kartstuff[k_driftcharge] = 0; - } - else if (((player->kartstuff[k_drift] == 0) || (player->kartstuff[k_drift] == 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] == -1 && player->kartstuff[k_turndir] != -1)) - && (player->kartstuff[k_driftcharge] >= 30 && player->kartstuff[k_driftcharge] < 60) - && onground) - { - player->powers[pw_sneakers] += 17; - S_StartSound(player->mo, sfx_mush); - player->kartstuff[k_drift] = 0; - player->kartstuff[k_driftcharge] = 0; - } - else if (((player->kartstuff[k_drift] == 0) || (player->kartstuff[k_drift] == 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] == -1 && player->kartstuff[k_turndir] != -1)) - && player->kartstuff[k_driftcharge] >= 60 - && onground) - { - player->powers[pw_sneakers] += 35; - S_StartSound(player->mo, sfx_mush); - player->kartstuff[k_drift] = 0; - player->kartstuff[k_driftcharge] = 0; - } - - if (player->kartstuff[k_turndir] == 1 && player->speed > 10 - && player->kartstuff[k_jmp] == 1 - && player->kartstuff[k_drift] != 1) - player->kartstuff[k_drift] = 1; - else if (player->kartstuff[k_turndir] == -1 && player->speed > 10 - && player->kartstuff[k_jmp] == 1 - && player->kartstuff[k_drift] != -1) - player->kartstuff[k_drift] = -1; - else if (player->kartstuff[k_jmp] == 0 || player->kartstuff[k_turndir] == 0) - player->kartstuff[k_drift] = 0; - - // If you press any strafe key while turning right, then drift right. - if (player->kartstuff[k_spinouttimer] == 0 - && player->kartstuff[k_jmp] == 1 && (player->kartstuff[k_drift] == 1 || player->kartstuff[k_drift] == -1) - && onground) //Right - { - player->kartstuff[k_driftcharge]++; - } - // Stop drifting - if (player->kartstuff[k_spinouttimer] > 0 // banana peel - || player->speed < 10) // you're too slow! - { - player->kartstuff[k_drift] = 0; - player->kartstuff[k_driftcharge] = 0; - } + K_KartDrift(player, cmd, onground); // Quick Turning // You can't turn your kart when you're not moving. @@ -2161,7 +2282,6 @@ void K_MoveKartPlayer(player_t *player, ticcmd_t *cmd, boolean onground) } } */ - player->kartstuff[k_boostcharge] = 0; // Play the stop light's sounds if ((leveltime == (TICRATE-4)*2) || (leveltime == (TICRATE-2)*3)) @@ -2175,7 +2295,7 @@ void K_MoveKartPlayer(player_t *player, ticcmd_t *cmd, boolean onground) player->kartstuff[k_boostcharge] = 0; // Increase your size while charging your engine. if (leveltime < 150) - player->mo->destscale = FRACUNIT*((100 + player->kartstuff[k_boostcharge])/100); + player->mo->destscale = FRACUNIT + (player->kartstuff[k_boostcharge]*655); // Determine the outcome of your charge. if (leveltime > 140 && player->kartstuff[k_boostcharge]) @@ -2187,7 +2307,10 @@ void K_MoveKartPlayer(player_t *player, ticcmd_t *cmd, boolean onground) } // You overcharged your engine? Those things are expensive!!! if (player->kartstuff[k_boostcharge] > 10) - player->kartstuff[k_boostcharge] = 40; + { + player->powers[pw_nocontrol] = 40; + S_StartSound(player->mo, sfx_slip); + } player->kartstuff[k_boostcharge] = 0; } @@ -2351,6 +2474,7 @@ static patch_t *kp_blueshell; static patch_t *kp_fireflower; static patch_t *kp_tripleredshell; static patch_t *kp_lightning; +static patch_t *kp_kitchensink; static patch_t *kp_itemused1; static patch_t *kp_itemused2; static patch_t *kp_itemused3; @@ -2447,6 +2571,7 @@ void K_LoadKartHUDGraphics(void) kp_fireflower = W_CachePatchName("K_ITFIRE", PU_HUDGFX); kp_tripleredshell = W_CachePatchName("K_ITTRED", PU_HUDGFX); kp_lightning = W_CachePatchName("K_ITLIGH", PU_HUDGFX); + kp_kitchensink = W_CachePatchName("K_ITSINK", PU_HUDGFX); // Item-used - Closing the item window after an item is used kp_itemused1 = W_CachePatchName("K_ITUSE1", PU_HUDGFX); @@ -2725,6 +2850,7 @@ static void K_drawKartRetroItem(void) if ((stplyr->kartstuff[k_bootaketimer] > 0 || stplyr->kartstuff[k_boostolentimer] > 0) && (leveltime & 2)) localpatch = kp_boosteal; else if (stplyr->kartstuff[k_boostolentimer] > 0 && !(leveltime & 2)) localpatch = kp_noitem; + else if (stplyr->kartstuff[k_kitchensink] == 1) localpatch = kp_kitchensink; else if (stplyr->kartstuff[k_lightning] == 1) localpatch = kp_lightning; else if (stplyr->kartstuff[k_tripleredshell] & 8) localpatch = kp_tripleredshell; else if (stplyr->kartstuff[k_fireflower] == 1) localpatch = kp_fireflower; @@ -3083,15 +3209,9 @@ void K_drawKartHUD(void) K_DrawKartPositionNum(stplyr->kartstuff[k_spinout]); //K_DrawKartPositionNum(stplyr->kartstuff[k_position]); - // Why is this here????? - /* + // Plays the music after the starting countdown. This is here since it checks every frame regularly. if (leveltime > 157 && leveltime < (TICRATE+1)*7) - { - if (!(mapmusic & 2048)) // TODO: Might not need this here - mapmusic = mapheaderinfo[gamemap-1].musicslot; - - S_ChangeMusic(mapmusic & 2047, true); - }*/ + S_ChangeMusicInternal(mapmusname, true); } //} diff --git a/src/k_kart.h b/src/k_kart.h index 5f822cd6..014eb581 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -16,11 +16,13 @@ UINT8 K_GetKartColorByName(const char *name); void K_RegisterKartStuff(void); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); -boolean K_SpinPlayer(player_t *player, mobj_t *source); -boolean K_SquishPlayer(player_t *player, mobj_t *source); -boolean K_ExplodePlayer(player_t *player, mobj_t *source); +void K_SpinPlayer(player_t *player, mobj_t *source); +void K_SquishPlayer(player_t *player, mobj_t *source); +void K_ExplodePlayer(player_t *player, mobj_t *source); 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); void K_SpawnDriftTrail(player_t *player); +void K_DoMushroom(player_t *player, boolean doPFlag); +fixed_t K_3dKartMovement(player_t *player, boolean onground); void K_MoveKartPlayer(player_t *player, ticcmd_t *cmd, boolean onground); void K_LoadKartHUDGraphics(void); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index bd5605f2..29bcd736 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -144,6 +144,12 @@ static int player_get(lua_State *L) lua_pushfixed(L, plr->dashspeed); else if (fastcmp(field,"dashtime")) lua_pushinteger(L, plr->dashtime); + // SRB2kart + else if (fastcmp(field,"kartspeed")) + lua_pushfixed(L, plr->kartspeed); + else if (fastcmp(field,"kartweight")) + lua_pushfixed(L, plr->kartweight); + // else if (fastcmp(field,"normalspeed")) lua_pushfixed(L, plr->normalspeed); else if (fastcmp(field,"runspeed")) @@ -401,6 +407,12 @@ static int player_set(lua_State *L) plr->dashspeed = luaL_checkfixed(L, 3); else if (fastcmp(field,"dashtime")) plr->dashtime = (INT32)luaL_checkinteger(L, 3); + // SRB2kart + else if (fastcmp(field,"kartspeed")) + plr->kartspeed = (UINT8)luaL_checkfixed(L, 3); + else if (fastcmp(field,"kartweight")) + plr->kartweight = (UINT8)luaL_checkfixed(L, 3); + // else if (fastcmp(field,"normalspeed")) plr->normalspeed = luaL_checkfixed(L, 3); else if (fastcmp(field,"runspeed")) diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index 28d5fed2..85e029e6 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -38,6 +38,10 @@ enum skin { skin_actionspd, skin_mindash, skin_maxdash, + // SRB2kart + skin_kartspeed, + skin_kartweight, + // skin_normalspeed, skin_runspeed, skin_thrustfactor, @@ -68,6 +72,10 @@ static const char *const skin_opt[] = { "actionspd", "mindash", "maxdash", + // SRB2kart + "kartspeed", + "kartweight", + // "normalspeed", "runspeed", "thrustfactor", @@ -155,6 +163,14 @@ static int skin_get(lua_State *L) case skin_maxdash: lua_pushfixed(L, skin->maxdash); break; + // SRB2kart + case skin_kartspeed: + lua_pushfixed(L, skin->kartspeed); + break; + case skin_kartweight: + lua_pushfixed(L, skin->kartweight); + break; + // case skin_normalspeed: lua_pushfixed(L, skin->normalspeed); break; diff --git a/src/m_menu.c b/src/m_menu.c index 2b623651..38c9acfe 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -376,6 +376,9 @@ consvar_t cv_chooseskin = {"chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_co // When you add gametypes here, don't forget to update them in CV_AddValue! CV_PossibleValue_t gametype_cons_t[] = { + {GT_RACE, "Race"}, {GT_MATCH, "Match"}, + + /* // SRB2kart {GT_COOP, "Co-op"}, {GT_COMPETITION, "Competition"}, @@ -388,9 +391,10 @@ CV_PossibleValue_t gametype_cons_t[] = {GT_HIDEANDSEEK, "Hide and Seek"}, {GT_CTF, "CTF"}, + */ {0, NULL} }; -consvar_t cv_newgametype = {"newgametype", "Co-op", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_newgametype = {"newgametype", "Race", CV_HIDEN|CV_CALL, gametype_cons_t, Newgametype_OnChange, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t serversort_cons_t[] = { {0,"Ping"}, @@ -1899,19 +1903,19 @@ static void Newgametype_OnChange(void) if(!mapheaderinfo[cv_nextmap.value-1]) P_AllocMapHeader((INT16)(cv_nextmap.value-1)); - if ((cv_newgametype.value == GT_COOP && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_COOP)) || - (cv_newgametype.value == GT_COMPETITION && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_COMPETITION)) || - (cv_newgametype.value == GT_RACE && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_RACE)) || - ((cv_newgametype.value == GT_MATCH || cv_newgametype.value == GT_TEAMMATCH) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_MATCH)) || - ((cv_newgametype.value == GT_TAG || cv_newgametype.value == GT_HIDEANDSEEK) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_TAG)) || - (cv_newgametype.value == GT_CTF && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_CTF))) + if ((cv_newgametype.value == GT_RACE && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_RACE)) || // SRB2kart + //(cv_newgametype.value == GT_COMPETITION && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_COMPETITION)) || + //(cv_newgametype.value == GT_RACE && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_RACE)) || + ((cv_newgametype.value == GT_MATCH || cv_newgametype.value == GT_TEAMMATCH) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_MATCH))) // || + //((cv_newgametype.value == GT_TAG || cv_newgametype.value == GT_HIDEANDSEEK) && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_TAG)) || + //(cv_newgametype.value == GT_CTF && !(mapheaderinfo[cv_nextmap.value-1]->typeoflevel & TOL_CTF))) { INT32 value = 0; switch (cv_newgametype.value) { case GT_COOP: - value = TOL_COOP; + value = TOL_RACE; // SRB2kart break; case GT_COMPETITION: value = TOL_COMPETITION; @@ -4264,7 +4268,7 @@ static void M_NewGame(void) fromlevelselect = false; startmap = spstage_start; - CV_SetValue(&cv_newgametype, GT_COOP); // Graue 09-08-2004 + CV_SetValue(&cv_newgametype, GT_RACE); // SRB2kart M_SetupChoosePlayer(0); } @@ -6213,6 +6217,15 @@ static void M_DrawServerMenu(void) } #endif + // SRB2kart + // A 70x70 image of the level's gametype + /* + if (mapheaderinfo[cv_nextmap.value-1].typeoflevel & TOL_KART) + V_DrawSmallScaledPatch(BASEVIDWIDTH/2,130,0,W_CachePatchName("KART", PU_STATIC)); + else + V_DrawSmallScaledPatch(BASEVIDWIDTH/2,130,0,W_CachePatchName("SONR", PU_STATIC)); + */ + // A 160x100 image of the level as entry MAPxxP lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); diff --git a/src/m_misc.h b/src/m_misc.h index fa1f3b33..f2a8bb54 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -38,7 +38,7 @@ void M_StopMovie(void); #elif defined (PSP) #define CONFIGFILENAME "srb2psp.cfg" #else -#define CONFIGFILENAME "config.cfg" +#define CONFIGFILENAME "kartconfig.cfg" #endif INT32 M_MapNumber(char first, char second); diff --git a/src/p_inter.c b/src/p_inter.c index 1c97302d..15d2e1f1 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1151,6 +1151,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_STARPOST: if (player->bot) return; + // SRB2kart - 150117 + if (player->exiting) //STOP MESSING UP MY STATS FASDFASDF + { + player->kartstuff[k_starpostwp] = player->kartstuff[k_waypoint]; + return; + } + // // In circuit, player must have touched all previous starposts if (circuitmap && special->health - player->starpostnum > 1) @@ -1173,7 +1180,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // Already hit this post // Save the player's time and position. - player->starposttime = leveltime; + player->starposttime = player->realtime; //this makes race mode's timers work correctly whilst not affecting sp -x + if (((special->health - 1) + (numstarposts+1)*player->laps) < 256) // SIGSEGV prevention + player->checkpointtimes[(special->health - 1) + (numstarposts+1)*player->laps] = player->realtime; + //player->starposttime = leveltime; player->starpostx = toucher->x>>FRACBITS; player->starposty = toucher->y>>FRACBITS; player->starpostz = special->z>>FRACBITS; @@ -1181,6 +1191,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->starpostnum = special->health; P_ClearStarPost(special->health); + // SRB2kart + if (gametype == GT_RACE) + player->kartstuff[k_playerahead] = P_CheckPlayerAhead(player, (special->health - 1) + (numstarposts+1)*player->laps); + // Find all starposts in the level with this value. { thinker_t *th; @@ -1479,6 +1493,58 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_KillMobj(special, NULL, toucher); } +// SRB2kart +INT32 P_CheckPlayerAhead(player_t *player, INT32 tocheck) +{ + INT32 i, retvalue = 0, me = -1; + tic_t besttime = 0xffffffff; + + if (tocheck >= 256) + return 0; //Don't SIGSEGV. + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (player == &players[i]) //you're me! + { + me = i; + continue; + } + + if (!players[i].checkpointtimes[tocheck]) + continue; + + if (players[i].checkpointtimes[tocheck] >= besttime) + continue; + + besttime = players[i].checkpointtimes[tocheck]; + retvalue = i+1; + } + + if (!retvalue) + return 0; + + if (besttime >= player->realtime) // > sign is practically paranoia + { + if (!players[retvalue-1].kartstuff[k_playerahead] && me != -1 + && players[retvalue-1].laps == player->laps + && players[retvalue-1].starpostnum == player->starpostnum) + players[retvalue-1].kartstuff[k_playerahead] = 65536; + return 65536; //we're tied! + } + + //checkplayerahead does this too! + if (!players[retvalue-1].kartstuff[k_playerahead] && me != -1 + && players[retvalue-1].laps == player->laps + && players[retvalue-1].starpostnum == player->starpostnum) + players[retvalue-1].kartstuff[k_playerahead] = 257 + me; + + return retvalue; +} +// + /** Prints death messages relating to a dying or hit player. * * \param player Affected player. @@ -1956,14 +2022,60 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL)) P_SetTarget(&target->tracer, inflictor); + // SRB2kart + // I wish I knew a better way to do this + if (target->target && target->target->player && target->target->player->mo) + { + if (target->type == MT_GREENSHIELD && target->target->player->kartstuff[k_greenshell] & 1) + target->target->player->kartstuff[k_greenshell] &= ~1; + else if (target->type == MT_REDSHIELD && target->target->player->kartstuff[k_redshell] & 1) + target->target->player->kartstuff[k_redshell] &= ~1; + else if (target->type == MT_BANANASHIELD && target->target->player->kartstuff[k_banana] & 1) + target->target->player->kartstuff[k_banana] &= ~1; + else if (target->type == MT_FAKESHIELD && target->target->player->kartstuff[k_fakeitem] & 1) + target->target->player->kartstuff[k_fakeitem] &= ~1; + else if (target->type == MT_BOMBSHIELD && target->target->player->kartstuff[k_bobomb] & 1) + target->target->player->kartstuff[k_bobomb] &= ~1; + else if (target->type == MT_TRIPLEGREENSHIELD1 && target->target->player->kartstuff[k_triplegreenshell] & 1) + target->target->player->kartstuff[k_triplegreenshell] &= ~1; + else if (target->type == MT_TRIPLEGREENSHIELD2 && target->target->player->kartstuff[k_triplegreenshell] & 2) + target->target->player->kartstuff[k_triplegreenshell] &= ~2; + else if (target->type == MT_TRIPLEGREENSHIELD3 && target->target->player->kartstuff[k_triplegreenshell] & 4) + target->target->player->kartstuff[k_triplegreenshell] &= ~4; + else if (target->type == MT_TRIPLEREDSHIELD1 && target->target->player->kartstuff[k_tripleredshell] & 1) + target->target->player->kartstuff[k_tripleredshell] &= ~1; + else if (target->type == MT_TRIPLEREDSHIELD2 && target->target->player->kartstuff[k_tripleredshell] & 2) + target->target->player->kartstuff[k_tripleredshell] &= ~2; + else if (target->type == MT_TRIPLEREDSHIELD3 && target->target->player->kartstuff[k_tripleredshell] & 4) + target->target->player->kartstuff[k_tripleredshell] &= ~4; + else if (target->type == MT_TRIPLEBANANASHIELD1 && target->target->player->kartstuff[k_triplebanana] & 1) + target->target->player->kartstuff[k_triplebanana] &= ~1; + else if (target->type == MT_TRIPLEBANANASHIELD2 && target->target->player->kartstuff[k_triplebanana] & 2) + target->target->player->kartstuff[k_triplebanana] &= ~2; + else if (target->type == MT_TRIPLEBANANASHIELD3 && target->target->player->kartstuff[k_triplebanana] & 4) + target->target->player->kartstuff[k_triplebanana] &= ~4; + } + // + if (!useNightsSS && G_IsSpecialStage(gamemap) && target->player && sstimer > 6) sstimer = 6; // Just let P_Ticker take care of the rest. if (target->flags & (MF_ENEMY|MF_BOSS)) target->momx = target->momy = target->momz = 0; - if (target->type != MT_PLAYER && !(target->flags & MF_MONITOR)) - target->flags |= MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT; // Don't drop Tails 03-08-2000 + // SRB2kart + if (target->type != MT_PLAYER && !(target->flags & MF_MONITOR) + && !(target->type == MT_GREENITEM || target->type == MT_GREENSHIELD + || target->type == MT_TRIPLEGREENSHIELD1 || target->type == MT_TRIPLEGREENSHIELD2 || target->type == MT_TRIPLEGREENSHIELD3 + || target->type == MT_REDITEM || target->type == MT_REDITEMDUD || target->type == MT_REDSHIELD + || target->type == MT_TRIPLEREDSHIELD1 || target->type == MT_TRIPLEREDSHIELD2 || target->type == MT_TRIPLEREDSHIELD3 + || target->type == MT_BANANAITEM || target->type == MT_BANANASHIELD + || target->type == MT_TRIPLEBANANASHIELD1 || target->type == MT_TRIPLEBANANASHIELD2 || target->type == MT_TRIPLEBANANASHIELD3 + || target->type == MT_FAKEITEM || target->type == MT_FAKESHIELD)) // kart dead items + target->flags |= MF_NOGRAVITY; // Don't drop Tails 03-08-2000 + else + target->flags &= ~MF_NOGRAVITY; // lose it if you for whatever reason have it, I'm looking at you shields + // if (target->flags2 & MF2_NIGHTSPULL) P_SetTarget(&target->tracer, NULL); @@ -2894,6 +3006,13 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return false; } + // SRB2kart 011617 - Special Case for Pokey so it doesn't die. + if (target->type == MT_POKEY) + { + target->threshold = 1; + return false; + } + // Special case for Crawla Commander if (target->type == MT_CRAWLACOMMANDER) { diff --git a/src/p_local.h b/src/p_local.h index c8930aed..707b861c 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -387,6 +387,10 @@ void P_CheckPointLimit(void); void P_CheckSurvivors(void); boolean P_CheckRacers(void); +// SRB2kart +INT32 P_CheckPlayerAhead(player_t *player, INT32 tocheck); +// + void P_ClearStarPost(INT32 postnum); void P_ResetStarposts(void); diff --git a/src/p_map.c b/src/p_map.c index 79ae5ddf..b9ff1597 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -24,6 +24,7 @@ #include "r_sky.h" #include "s_sound.h" #include "w_wad.h" +#include "k_kart.h" // SRB2kart 011617 #include "r_splats.h" @@ -553,6 +554,537 @@ static boolean PIT_CheckThing(mobj_t *thing) } } + // SRB2kart 011617 - Colission code for kart items //{ + + if (tmthing->type == MT_GREENITEM || tmthing->type == MT_REDITEM || tmthing->type == MT_REDITEMDUD || + tmthing->type == MT_GREENSHIELD || tmthing->type == MT_REDSHIELD || + tmthing->type == MT_TRIPLEGREENSHIELD1 || tmthing->type == MT_TRIPLEGREENSHIELD2 || tmthing->type == MT_TRIPLEGREENSHIELD3 || + tmthing->type == MT_TRIPLEREDSHIELD1 || tmthing->type == MT_TRIPLEREDSHIELD2 || tmthing->type == MT_TRIPLEREDSHIELD3) + { + // 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 (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) + return true; + + if (tmthing->health <= 0 || thing->health <= 0) + return true; + + if (((tmthing->type == MT_TRIPLEGREENSHIELD1 || tmthing->type == MT_TRIPLEGREENSHIELD2 || tmthing->type == MT_TRIPLEGREENSHIELD3 + || tmthing->type == MT_TRIPLEREDSHIELD1 || tmthing->type == MT_TRIPLEREDSHIELD2 || tmthing->type == MT_TRIPLEREDSHIELD3) + && (thing->type == MT_TRIPLEGREENSHIELD1 || thing->type == MT_TRIPLEGREENSHIELD2 || thing->type == MT_TRIPLEGREENSHIELD3 + || thing->type == MT_TRIPLEREDSHIELD1 || thing->type == MT_TRIPLEREDSHIELD2 || thing->type == MT_TRIPLEREDSHIELD3)) + && (tmthing->target == thing->target)) // Don't hit each other if you have the same target + return true; + + if (thing->type == MT_PLAYER) + { + // Player Damage + P_DamageMobj(thing, tmthing, tmthing->target, 1); + + + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_GREENITEM || thing->type == MT_REDITEM || thing->type == MT_REDITEMDUD + || thing->type == MT_GREENSHIELD || thing->type == MT_REDSHIELD + || thing->type == MT_TRIPLEGREENSHIELD1 || thing->type == MT_TRIPLEGREENSHIELD2 || thing->type == MT_TRIPLEGREENSHIELD3 + || thing->type == MT_TRIPLEREDSHIELD1 || thing->type == MT_TRIPLEREDSHIELD2 || thing->type == MT_TRIPLEREDSHIELD3 + || thing->type == MT_BANANAITEM || thing->type == MT_BANANASHIELD + || thing->type == MT_TRIPLEBANANASHIELD1 || thing->type == MT_TRIPLEBANANASHIELD2 || thing->type == MT_TRIPLEBANANASHIELD3 + ) + { + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + + + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_FAKEITEM || thing->type == MT_FAKESHIELD) + { + if (tmthing->type == MT_GREENSHIELD || tmthing->type == MT_REDSHIELD + || tmthing->type == MT_TRIPLEGREENSHIELD1 || tmthing->type == MT_TRIPLEGREENSHIELD2 || tmthing->type == MT_TRIPLEGREENSHIELD3 + || tmthing->type == MT_TRIPLEREDSHIELD1 || tmthing->type == MT_TRIPLEREDSHIELD2 || tmthing->type == MT_TRIPLEREDSHIELD3) + { + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_BOMBSHIELD || thing->type == MT_BOMBITEM) + { + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + + + // Bomb death + P_KillMobj(thing, tmthing, tmthing); + } + else if (thing->flags & MF_SPRING && (tmthing->type == MT_REDITEM || tmthing->type == MT_REDITEMDUD || tmthing->type == MT_GREENITEM)) + P_DoSpring(thing, tmthing); + + return true; + } + else if (tmthing->flags & MF_SPRING && (thing->type == MT_REDITEM || thing->type == MT_REDITEMDUD || thing->type == MT_GREENITEM)) + { + // 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 (thing->health <= 0) + return true; + + P_DoSpring(tmthing, thing); + + return true; + } + else if (tmthing->type == MT_SINK) + { + // 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 (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) + return true; + + if (thing->type == MT_PLAYER) + { + S_StartSound(NULL, sfx_cgot); //let all players hear it. + HU_SetCEchoFlags(0); + HU_SetCEchoDuration(5); + HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[thing->player-players])); + I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[thing->player-players]); + P_DamageMobj(thing, tmthing, tmthing->target, 10000); + P_KillMobj(tmthing, thing, thing); + } + + return true; + } + else if (tmthing->type == MT_BOMBEXPLOSION) + { + // 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 (!(thing->type == MT_PLAYER)) + return true; + + if (thing->type == MT_PLAYER) + { + K_SpinPlayer(thing->player, tmthing->target); + } + + return true; // This doesn't collide with anything, but we want it to effect the player anyway. + } + else if (tmthing->type == MT_BANANASHIELD || tmthing->type == MT_BANANAITEM + || tmthing->type == MT_TRIPLEBANANASHIELD1 || tmthing->type == MT_TRIPLEBANANASHIELD2 || tmthing->type == MT_TRIPLEBANANASHIELD3) + { + // 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 (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) + return true; + + if (tmthing->health <= 0 || thing->health <= 0) + return true; + + if (((tmthing->type == MT_BANANASHIELD || tmthing->type == MT_TRIPLEBANANASHIELD1 || tmthing->type == MT_TRIPLEBANANASHIELD2 || tmthing->type == MT_TRIPLEBANANASHIELD3) + && (thing->type == MT_BANANASHIELD || thing->type == MT_TRIPLEBANANASHIELD1 || thing->type == MT_TRIPLEBANANASHIELD2 || thing->type == MT_TRIPLEBANANASHIELD3)) + && (tmthing->target == thing->target)) // Don't hit each other if you have the same target + return true; + + if (thing->type == MT_PLAYER) + { + // Player Damage + K_SpinPlayer(thing->player, tmthing->target); + + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_BANANASHIELD || thing->type == MT_BANANAITEM + || thing->type == MT_TRIPLEBANANASHIELD1 || thing->type == MT_TRIPLEBANANASHIELD2 || thing->type == MT_TRIPLEBANANASHIELD3 + || thing->type == MT_GREENITEM || thing->type == MT_REDITEM || thing->type == MT_REDITEMDUD + || thing->type == MT_GREENSHIELD || thing->type == MT_TRIPLEGREENSHIELD1 || thing->type == MT_TRIPLEGREENSHIELD2 || thing->type == MT_TRIPLEGREENSHIELD3 + || thing->type == MT_REDSHIELD || thing->type == MT_TRIPLEREDSHIELD1 || thing->type == MT_TRIPLEREDSHIELD2 || thing->type == MT_TRIPLEREDSHIELD3) + { + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_FAKEITEM || thing->type == MT_FAKESHIELD) + { + if (tmthing->type == MT_BANANASHIELD || tmthing->type == MT_TRIPLEBANANASHIELD1 || tmthing->type == MT_TRIPLEBANANASHIELD2 || tmthing->type == MT_TRIPLEBANANASHIELD3) + { + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + } + + return true; + } + else if (tmthing->type == MT_FAKESHIELD || tmthing->type == MT_FAKEITEM) + { + // 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 (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) + return true; + + if (tmthing->health <= 0 || thing->health <= 0) + return true; + + if (thing->type == MT_GREENITEM // When these items collide with the fake item, just the fake item is destroyed + || thing->type == MT_REDITEM || thing->type == MT_REDITEMDUD + || thing->type == MT_BOMBITEM + || thing->type == MT_BANANAITEM) + { + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_GREENSHIELD || thing->type == MT_TRIPLEGREENSHIELD1 || thing->type == MT_TRIPLEGREENSHIELD2 || thing->type == MT_TRIPLEGREENSHIELD3 // When these items collide with the fake item, both of them are destroyed + || thing->type == MT_REDSHIELD || thing->type == MT_TRIPLEREDSHIELD1 || thing->type == MT_TRIPLEREDSHIELD2 || thing->type == MT_TRIPLEREDSHIELD3 + || thing->type == MT_BOMBSHIELD + || thing->type == MT_BANANASHIELD || thing->type == MT_TRIPLEBANANASHIELD1 || thing->type == MT_TRIPLEBANANASHIELD2 || thing->type == MT_TRIPLEBANANASHIELD3 + || thing->type == MT_FAKEITEM || thing->type == MT_FAKESHIELD) + { + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_PLAYER) + { + // Player Damage + P_DamageMobj(thing, tmthing, tmthing->target, 1); + + // This Item Damage + if (tmthing->eflags & MFE_VERTICALFLIP) + tmthing->z -= tmthing->height; + else + tmthing->z += tmthing->height; + + S_StartSound(tmthing, tmthing->info->deathsound); + P_KillMobj(tmthing, thing, thing); + + P_SetObjectMomZ(tmthing, 8*FRACUNIT, false); + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); + } + + return true; + } + else if (tmthing->type == MT_BOMBSHIELD || tmthing->type == MT_BOMBITEM) + { + // 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 (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) + return true; + + if (tmthing->health <= 0 || thing->health <= 0) + return true; + + if (thing->type == MT_PLAYER) + { + P_KillMobj(tmthing, thing, thing); + } + else if (thing->type == MT_GREENITEM || thing->type == MT_REDITEM || thing->type == MT_REDITEMDUD + || thing->type == MT_GREENSHIELD || thing->type == MT_TRIPLEGREENSHIELD1 || thing->type == MT_TRIPLEGREENSHIELD2 || thing->type == MT_TRIPLEGREENSHIELD3 + || thing->type == MT_REDSHIELD || thing->type == MT_TRIPLEREDSHIELD1 || thing->type == MT_TRIPLEREDSHIELD2 || thing->type == MT_TRIPLEREDSHIELD3) + { + P_KillMobj(tmthing, thing, thing); + + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + } + + return true; + } + else if (tmthing->type == MT_PLAYER && + (thing->type == MT_GREENSHIELD || thing->type == MT_GREENITEM + || thing->type == MT_REDSHIELD || thing->type == MT_REDITEM || thing->type == MT_REDITEMDUD + || thing->type == MT_TRIPLEGREENSHIELD1 || thing->type == MT_TRIPLEGREENSHIELD2 || thing->type == MT_TRIPLEGREENSHIELD3 + || thing->type == MT_TRIPLEREDSHIELD1 || thing->type == MT_TRIPLEREDSHIELD2 || thing->type == MT_TRIPLEREDSHIELD3 + || thing->type == MT_FAKESHIELD || thing->type == MT_FAKEITEM + || thing->type == MT_BANANASHIELD || thing->type == MT_BANANAITEM + || thing->type == MT_TRIPLEBANANASHIELD1 || thing->type == MT_TRIPLEBANANASHIELD2 || thing->type == MT_TRIPLEBANANASHIELD3 + || thing->type == MT_BOMBSHIELD || thing->type == MT_BOMBITEM + || thing->type == MT_BOMBEXPLOSION + || thing->type == MT_SINK + )) + { + // 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 (thing->type == MT_GREENSHIELD || thing->type == MT_TRIPLEGREENSHIELD1 || thing->type == MT_TRIPLEGREENSHIELD2 || thing->type == MT_TRIPLEGREENSHIELD3 + || thing->type == MT_REDSHIELD || thing->type == MT_TRIPLEREDSHIELD1 || thing->type == MT_TRIPLEREDSHIELD2 || thing->type == MT_TRIPLEREDSHIELD3 + || thing->type == MT_GREENITEM || thing->type == MT_REDITEM || thing->type == MT_REDITEMDUD + || thing->type == MT_FAKESHIELD || thing->type == MT_FAKEITEM) + { + if ((thing->target == tmthing) && (thing->threshold > 0)) + return true; + + if (tmthing->health <= 0 || thing->health <= 0) + return true; + + // Player Damage + P_DamageMobj(tmthing, thing, thing->target, 1); + + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_BANANASHIELD || thing->type == MT_BANANAITEM + || thing->type == MT_TRIPLEBANANASHIELD1 || thing->type == MT_TRIPLEBANANASHIELD2 || thing->type == MT_TRIPLEBANANASHIELD3) + { + if ((thing->target == tmthing) && (thing->threshold > 0)) + return true; + + if (tmthing->health <= 0 || thing->health <= 0) + return true; + + // Player Damage + K_SpinPlayer(tmthing->player, thing->target); + + // Other Item Damage + if (thing->eflags & MFE_VERTICALFLIP) + thing->z -= thing->height; + else + thing->z += thing->height; + + S_StartSound(thing, thing->info->deathsound); + P_KillMobj(thing, tmthing, tmthing); + + P_SetObjectMomZ(thing, 8*FRACUNIT, false); + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); + } + else if (thing->type == MT_BOMBSHIELD || thing->type == MT_BOMBITEM) + { + if ((thing->target == tmthing) && (thing->threshold > 0)) + return true; + + if (tmthing->health <= 0 || thing->health <= 0) + return true; + + P_KillMobj(thing, tmthing, tmthing); + } + else if (thing->type == MT_BOMBEXPLOSION) + { + // Player Damage + K_SpinPlayer(tmthing->player, thing->target); + + return true; + } + else if (thing->type == MT_SINK) + { + if ((thing->target == tmthing) && (thing->threshold > 0)) + return true; + + S_StartSound(NULL, sfx_cgot); //let all players hear it. + HU_SetCEchoFlags(0); + HU_SetCEchoDuration(5); + HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[tmthing->player-players])); + I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[tmthing->player-players]); + P_DamageMobj(tmthing, thing, thing->target, 10000); + P_KillMobj(thing, tmthing, tmthing); + } + + return true; + } + + + if (thing->type == MT_POKEY) + { + // 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 (tmthing->type == MT_ENEMYFLIP) + { + if (tmthing->angle) + P_SetMobjState(thing, S_POKEY5); + else + P_SetMobjState(thing, S_POKEY1); + } + if (tmthing->type == MT_PLAYER && !thing->threshold) + P_DamageMobj(tmthing, thing, thing->target, 1); + } + + //} + if ((thing->type == MT_SPRINGSHELL || thing->type == MT_YELLOWSHELL) && thing->health > 0 && (tmthing->player || (tmthing->flags & MF_PUSHABLE)) && tmthing->health > 0) { diff --git a/src/p_saveg.c b/src/p_saveg.c index aee50e61..0454232e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -268,6 +268,10 @@ static void P_NetArchivePlayers(void) WRITEFIXED(save_p, players[i].actionspd); WRITEFIXED(save_p, players[i].mindash); WRITEFIXED(save_p, players[i].maxdash); + // SRB2kart + WRITEUINT8(save_p, players[i].kartspeed); + WRITEUINT8(save_p, players[i].kartweight); + // WRITEFIXED(save_p, players[i].normalspeed); WRITEFIXED(save_p, players[i].runspeed); WRITEUINT8(save_p, players[i].thrustfactor); @@ -434,6 +438,10 @@ static void P_NetUnArchivePlayers(void) players[i].actionspd = READFIXED(save_p); players[i].mindash = READFIXED(save_p); players[i].maxdash = READFIXED(save_p); + // SRB2kart + players[i].kartspeed = READUINT8(save_p); + players[i].kartweight = READUINT8(save_p); + // players[i].normalspeed = READFIXED(save_p); players[i].runspeed = READFIXED(save_p); players[i].thrustfactor = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index b36bf0b8..bf229271 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2481,9 +2481,13 @@ boolean P_SetupLevel(boolean skipprecip) S_StopSounds(); S_ClearSfx(); - // As oddly named as this is, this handles music only. - // We should be fine starting it here. - S_Start(); + // SRB2kart 010217 + if (leveltime < 157) + S_StopMusic(); + if (leveltime > 157) + // As oddly named as this is, this handles music only. + // We should be fine starting it here. + S_Start(); // Let's fade to black here // But only if we didn't do the special stage wipe diff --git a/src/p_spec.c b/src/p_spec.c index 18378b84..2ec4d7b2 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -35,6 +35,8 @@ #include "m_cond.h" //unlock triggers #include "lua_hook.h" // LUAh_LinedefExecute +#include "k_kart.h" // SRB2kart + #ifdef HW3SOUND #include "hardware/hw3sound.h" #endif @@ -50,6 +52,9 @@ mobj_t *skyboxmo[2]; // Amount (dx, dy) vector linedef is shifted right to get scroll amount #define SCROLL_SHIFT 5 + +// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize. +#define MAXFLATSIZE (2048<mo, S_PLAY_FALL1); break; - case 6: // Super Sonic transformer - if (player->mo->health > 0 && !player->bot && (player->charflags & SF_SUPER) && !player->powers[pw_super] && ALL7EMERALDS(emeralds)) - P_DoSuperTransformation(player, true); + + case 6: // Super Sonic transformer // SRB2kart 190117- Replaced. This is now a Mushroom Boost Panel + if (!player->kartstuff[k_floorboost]) + player->kartstuff[k_floorboost] = 3; + else + player->kartstuff[k_floorboost] = 2; + K_DoMushroom(player, false); break; - case 7: // Make player spin - /* // SRB2kart - no. - if (!(player->pflags & PF_SPINNING) && P_IsObjectOnGround(player->mo) && (player->charability2 == CA2_SPINDASH)) + /* if (player->mo->health > 0 && !player->bot && (player->charflags & SF_SUPER) && !player->powers[pw_super] && ALL7EMERALDS(emeralds)) + P_DoSuperTransformation(player, true); + break; */ + + case 7: // Make player spin // SRB2kart 190117- Replaced. This is now an Oil Slick (Oddly ironic considering) + player->kartstuff[k_spinouttype] = -1; + K_SpinPlayer(player, NULL); + break; + + /* if (!(player->pflags & PF_SPINNING) && P_IsObjectOnGround(player->mo) && (player->charability2 == CA2_SPINDASH)) { player->pflags |= PF_SPINNING; P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); @@ -3861,8 +3877,8 @@ DoneSection2: if (abs(player->rmomx) < FixedMul(5*FRACUNIT, player->mo->scale) && abs(player->rmomy) < FixedMul(5*FRACUNIT, player->mo->scale)) P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale)); - }*/ - break; + } + break; */ case 8: // Zoom Tube Start { @@ -3924,11 +3940,15 @@ DoneSection2: P_SetTarget(&player->mo->tracer, waypoint); player->speed = speed; + player->pflags &= ~PF_SPINNING; // SRB2kart 200117 player->pflags |= PF_SPINNING; player->pflags &= ~PF_JUMPED; player->pflags &= ~PF_GLIDING; player->climbing = 0; + if (!(player->mo->state >= &states[S_KART_RUN1] && player->mo->state <= &states[S_KART_RUN2])) + P_SetPlayerMobjState(player->mo, S_KART_RUN1); + //if (!(player->mo->state >= &states[S_PLAY_ATK1] && player->mo->state <= &states[S_PLAY_ATK4])) // SRB2kart //{ // P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); @@ -3998,9 +4018,13 @@ DoneSection2: P_SetTarget(&player->mo->tracer, waypoint); player->speed = speed; + player->pflags &= ~PF_SPINNING; // SRB2kart 200117 player->pflags |= PF_SPINNING; player->pflags &= ~PF_JUMPED; + if (!(player->mo->state >= &states[S_KART_RUN1] && player->mo->state <= &states[S_KART_RUN2])) + P_SetPlayerMobjState(player->mo, S_KART_RUN1); + //if (!(player->mo->state >= &states[S_PLAY_ATK1] && player->mo->state <= &states[S_PLAY_ATK4])) // SRB2kart //{ // P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); @@ -4010,6 +4034,10 @@ DoneSection2: break; case 10: // Finish Line + // SRB2kart - 150117 + if (gametype == GT_RACE && (player->starpostnum == numstarposts || player->exiting)) + player->kartstuff[k_starpostwp] = player->kartstuff[k_waypoint] = 0; + // if (gametype == GT_RACE && !player->exiting) { if (player->starpostnum == numstarposts) // Must have touched all the starposts @@ -4021,16 +4049,47 @@ DoneSection2: if (player->laps >= (UINT8)cv_numlaps.value) CONS_Printf(M_GetText("%s has finished the race.\n"), player_names[player-players]); + else if (player->laps == (UINT8)(cv_numlaps.value - 1)) + CONS_Printf("%s started the final lap\n", player_names[player-players]); else CONS_Printf(M_GetText("%s started lap %u\n"), player_names[player-players], (UINT32)player->laps+1); // Reset starposts (checkpoints) info - player->starpostangle = player->starposttime = player->starpostnum = 0; + // SRB2kart 200117 + player->starpostangle = player->starpostnum = 0; player->starpostx = player->starposty = player->starpostz = 0; + //except the time! + player->starposttime = player->realtime; + if (((numstarposts+1)*player->laps - 1) < 256) //SIGSEGV prevention + player->checkpointtimes[(numstarposts+1)*player->laps - 1] = player->realtime; + player->kartstuff[k_playerahead] = P_CheckPlayerAhead(player, (numstarposts+1)*player->laps - 1); + + if (P_IsLocalPlayer(player)) + { + if (player->laps < (UINT8)(cv_numlaps.value - 1)) + { + S_StartSound(NULL, sfx_mlap); + player->kartstuff[k_lakitu] = -64; + } + else if (player->laps == (UINT8)(cv_numlaps.value - 1)) + { + player->kartstuff[k_lakitu] = -64; + + if (!splitscreen || (splitscreen && !players[consoleplayer].exiting + && !players[secondarydisplayplayer].exiting)) + { + //player->powers[pw_sounds] = 1; + S_ChangeMusicInternal("finlap", false); + } + } + } + // + //player->starpostangle = player->starposttime = player->starpostnum = 0; + //player->starpostx = player->starposty = player->starpostz = 0; P_ResetStarposts(); // Play the starpost sound for 'consistency' - S_StartSound(player->mo, sfx_strpst); + // S_StartSound(player->mo, sfx_strpst); } else if (player->starpostnum) { @@ -4044,9 +4103,22 @@ DoneSection2: { if (P_IsLocalPlayer(player)) { - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho("FINISHED!"); + // SRB2kart 200117 + if (!splitscreen) + { + if (player->kartstuff[k_position] == 1) + S_ChangeMusicInternal("karwin", true); + else if (player->kartstuff[k_position] == 2 || player->kartstuff[k_position] == 3) + S_ChangeMusicInternal("karok", true); + else if (player->kartstuff[k_position] >= 4) + S_ChangeMusicInternal("karlos", true); + } + else + S_ChangeMusicInternal("karwin", true); + // + //HU_SetCEchoFlags(0); + //HU_SetCEchoDuration(5); + //HU_DoCEcho("FINISHED!"); } P_DoPlayerExit(player); @@ -5485,37 +5557,31 @@ void P_SpawnSpecials(INT32 fromnetsave) secthinkers[secnum].thinkers[secthinkers[secnum].count++] = th; } - // Init line EFFECTs for (i = 0; i < numlines; i++) { - // set line specials to 0 here too, same reason as above - if (netgame || multiplayer) + if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment with arbitrary skin setups... { - // future: nonet flag? - } - else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) - { - lines[i].special = 0; - continue; - } - else - { - if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) + // set line specials to 0 here too, same reason as above + if (netgame || multiplayer) + { + // future: nonet flag? + } + else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) { lines[i].special = 0; continue; } - if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) + /*else -- commented out because irrelevant to kart { - lines[i].special = 0; - continue; - } - if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)) - { - lines[i].special = 0; - continue; - } + if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) + || (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) + || (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))) + { + lines[i].special = 0; + continue; + } + }*/ } switch (lines[i].special) @@ -5559,50 +5625,55 @@ void P_SpawnSpecials(INT32 fromnetsave) I_Error("Failed to catch a disable linedef"); break; #endif - - case 7: // Flat alignment - if (lines[i].flags & ML_EFFECT4) // Align angle + case 7: // Flat alignment - redone by toast + if ((lines[i].flags & (ML_NOSONIC|ML_NOTAILS)) != (ML_NOSONIC|ML_NOTAILS)) // If you can do something... { - if (!(lines[i].flags & ML_EFFECT5)) // Align floor unless ALLTRIGGER flag is set + angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)); + fixed_t xoffs; + fixed_t yoffs; + + if (lines[i].flags & ML_NOKNUX) // Set offset through x and y texture offsets if NOKNUX flag is set { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); + xoffs = sides[lines[i].sidenum[0]].textureoffset; + yoffs = sides[lines[i].sidenum[0]].rowoffset; } - - if (!(lines[i].flags & ML_BOUNCY)) // Align ceiling unless BOUNCY flag is set + else // Otherwise, set calculated offsets such that line's v1 is the apparent origin { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); + fixed_t cosinecomponent = FINECOSINE(flatangle>>ANGLETOFINESHIFT); + fixed_t sinecomponent = FINESINE(flatangle>>ANGLETOFINESHIFT); + xoffs = (-FixedMul(lines[i].v1->x, cosinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, sinecomponent) % MAXFLATSIZE); // No danger of overflow thanks to the strategically placed modulo operations. + yoffs = (FixedMul(lines[i].v1->x, sinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, cosinecomponent) % MAXFLATSIZE); // Ditto. } - } - else // Do offsets - { - if (!(lines[i].flags & ML_BLOCKMONSTERS)) // Align floor unless BLOCKMONSTERS flag is set + + for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + if (!(lines[i].flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set { - sectors[s].floor_xoffs += lines[i].dx; - sectors[s].floor_yoffs += lines[i].dy; + sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = flatangle; + sectors[s].floor_xoffs += xoffs; + sectors[s].floor_yoffs += yoffs; // saved for netgames sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs; sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs; } - } - - if (!(lines[i].flags & ML_NOCLIMB)) // Align ceiling unless NOCLIMB flag is set - { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + + if (!(lines[i].flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set { - sectors[s].ceiling_xoffs += lines[i].dx; - sectors[s].ceiling_yoffs += lines[i].dy; + sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = flatangle; + sectors[s].ceiling_xoffs += xoffs; + sectors[s].ceiling_yoffs += yoffs; // saved for netgames sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs; sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs; } } } + else // Otherwise, print a helpful warning. Can I do no less? + CONS_Alert(CONS_WARNING, + M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), + lines[i].tag); break; - + case 8: // Sector Parameters for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) { @@ -6976,7 +7047,9 @@ void T_Friction(friction_t *f) // apparently, all I had to do was comment out part of the next line and // friction works for all mobj's // (or at least MF_PUSHABLEs, which is all I care about anyway) - if (!(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) && thing->z == thing->floorz) + if ((!(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) && thing->z == thing->floorz) && (thing->player + && (thing->player->kartstuff[k_startimer] && thing->player->kartstuff[k_bootaketimer] + && thing->player->kartstuff[k_mushroomtimer] && thing->player->kartstuff[k_growshrinktimer] <= 0))) { if (f->roverfriction) { diff --git a/src/p_user.c b/src/p_user.c index 06f7ca80..59d529a2 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4571,9 +4571,9 @@ static void P_3dMovement(player_t *player) } else { - if (player->kartstuff[k_drift] == 1) + if (player->kartstuff[k_drift] >= 1) movepushangle = player->mo->angle+ANGLE_45; - else if (player->kartstuff[k_drift] == -1) + else if (player->kartstuff[k_drift] <= -1) movepushangle = player->mo->angle-ANGLE_45; else movepushangle = player->mo->angle; @@ -4715,7 +4715,11 @@ static void P_3dMovement(player_t *player) && cmd->forwardmove != 0 && !(player->pflags & PF_GLIDING || player->exiting || (P_PlayerInPain(player) && !onground))) { - movepushforward = cmd->forwardmove * (thrustfactor * acceleration); + //movepushforward = cmd->forwardmove * (thrustfactor * acceleration); + if (cmd->forwardmove > 0) + movepushforward = K_3dKartMovement(player, onground); + else + movepushforward = -(K_3dKartMovement(player, onground)); // allow very small movement while in air for gameplay if (!onground) @@ -4764,7 +4768,11 @@ static void P_3dMovement(player_t *player) // (Why was it so complicated before? ~Red) controldirection = R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT)+movepushangle; - movepushforward = max(abs(cmd->sidemove), abs(cmd->forwardmove)) * (thrustfactor * acceleration); + //movepushforward = max(abs(cmd->sidemove), abs(cmd->forwardmove)) * (thrustfactor * acceleration); + if (max(abs(cmd->sidemove), abs(cmd->forwardmove)) > 0) + movepushforward = K_3dKartMovement(player, onground); + else + movepushforward = -(K_3dKartMovement(player, onground)); // allow very small movement while in air for gameplay if (!onground) @@ -4800,7 +4808,11 @@ static void P_3dMovement(player_t *player) } else if (cmd->sidemove && !(player->pflags & PF_GLIDING) && !player->exiting && !P_PlayerInPain(player)) { - movepushside = cmd->sidemove * (thrustfactor * acceleration); + //movepushside = cmd->sidemove * (thrustfactor * acceleration); + if (cmd->sidemove > 0) + movepushside = K_3dKartMovement(player, onground); + else + movepushside = -(K_3dKartMovement(player, onground)); if (!onground) { @@ -6664,10 +6676,12 @@ static void P_MovePlayer(player_t *player) // Drifting sound { // Start looping the sound now. - if (leveltime % 50 == 0 && ((player->kartstuff[k_drift] == 1 || player->kartstuff[k_drift] == -1) && onground)) + if (leveltime % 50 == 0 && onground + && ((player->kartstuff[k_drift] >= 1 && player->kartstuff[k_drift] <= 3) + || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_drift] >= -3))) S_StartSound(player->mo, sfx_mkdrft); // Leveltime being 50 might take a while at times. We'll start it up once, isntantly. - else if ((player->kartstuff[k_drift] == 1 || player->kartstuff[k_drift] == -1) && !S_SoundPlaying(player->mo, sfx_mkdrft) && onground) + else if ((player->kartstuff[k_drift] >= 1 || player->kartstuff[k_drift] <= -1) && !S_SoundPlaying(player->mo, sfx_mkdrft) && onground) S_StartSound(player->mo, sfx_mkdrft); // Ok, we'll stop now. else if ((player->kartstuff[k_drift] == 0) @@ -7906,11 +7920,13 @@ static void P_DeathThink(player_t *player) countdown2 = 1*TICRATE; skipstats = true; + /* // SRB2kart 010217 - Score doesn't need to be reset in Kart. for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) players[i].score = 0; } + */ //emeralds = 0; tokenbits = 0; @@ -9037,7 +9053,7 @@ void P_PlayerThink(player_t *player) // Make sure spectators always have a score and ring count of 0. if (player->spectator) { - player->score = 0; + //player->score = 0; player->mo->health = 1; player->health = 1; } @@ -9052,12 +9068,17 @@ void P_PlayerThink(player_t *player) if (player == &players[displayplayer]) playerdeadview = false; + // SRB2kart 010217 + if (gametype == GT_RACE && leveltime < 4*TICRATE) + player->powers[pw_nocontrol] = 2; + /* if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE) { - cmd->buttons &= BT_BRAKE; // Remove all buttons except BT_BRAKE // TODO: ? + cmd->buttons &= BT_BRAKE; // Remove all buttons except BT_BRAKE cmd->forwardmove = 0; cmd->sidemove = 0; } + */ // Synchronizes the "real" amount of time spent in the level. if (!player->exiting) diff --git a/src/r_main.c b/src/r_main.c index 97d6876e..1655a566 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -139,7 +139,7 @@ static void FlipCam2_OnChange(void); void SendWeaponPref(void); void SendWeaponPref2(void); -consvar_t cv_tailspickup = {"tailspickup", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_tailspickup = {"tailspickup", "Off", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasecam = {"chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_chasecam2 = {"chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/r_things.c b/src/r_things.c index 44883f2c..331ff726 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2279,6 +2279,11 @@ static void Sk_SetDefaultValue(skin_t *skin) skin->starttranscolor = 160; skin->prefcolor = SKINCOLOR_GREEN; + // SRB2kart + skin->kartspeed = 7; + skin->kartweight = 5; + // + skin->normalspeed = 36<runspeed = 28<thrustfactor = 5; @@ -2422,6 +2427,11 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->mindash = skin->mindash; player->maxdash = skin->maxdash; + // SRB2kart + player->kartspeed = skin->kartspeed; + player->kartweight = skin->kartweight; + // + player->normalspeed = skin->normalspeed; player->runspeed = skin->runspeed; player->thrustfactor = skin->thrustfactor; @@ -2644,6 +2654,10 @@ void R_AddSkins(UINT16 wadnum) #undef GETSPEED #define GETINT(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value); + // SRB2kart + GETINT(kartspeed) + GETINT(kartweight) + // GETINT(thrustfactor) GETINT(accelstart) GETINT(acceleration) diff --git a/src/r_things.h b/src/r_things.h index 483db7e9..e634b527 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -86,6 +86,11 @@ typedef struct fixed_t mindash; fixed_t maxdash; + // SRB2kart + UINT8 kartspeed; // Normal ground + UINT8 kartweight; // Normal ground + // + fixed_t normalspeed; // Normal ground fixed_t runspeed; // Speed that you break into your run animation diff --git a/src/s_sound.c b/src/s_sound.c index 5a654649..e19f9265 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1159,7 +1159,7 @@ void S_StartSoundName(void *mo, const char *soundname) /// ------------------------ #ifdef MUSICSLOT_COMPATIBILITY -const char *compat_special_music_slots[16] = +const char *compat_special_music_slots[21] = { "titles", // 1036 title screen "read_m", // 1037 intro @@ -1176,6 +1176,12 @@ const char *compat_special_music_slots[16] = "credit", // 1048 credits "racent", // 1049 Race Results "stjr", // 1050 Sonic Team Jr. Presents + // SRB2kart 040217 + "finlap", // 1051 Sonic Team Jr. Presents + "karwin", // 1052 Sonic Team Jr. Presents + "karok", // 1053 Sonic Team Jr. Presents + "karlos", // 1054 Sonic Team Jr. Presents + "mega", // 1055 Sonic Team Jr. Presents "" }; #endif diff --git a/src/s_sound.h b/src/s_sound.h index bcc7979a..1f308447 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -142,7 +142,7 @@ void S_StopSoundByNum(sfxenum_t sfxnum); #ifdef MUSICSLOT_COMPATIBILITY // For compatibility with code/scripts relying on older versions // This is a list of all the "special" slot names and their associated numbers -const char *compat_special_music_slots[16]; +const char *compat_special_music_slots[21]; #endif #endif diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg index f309f7db..a064dc38 100644 --- a/src/win32/Makefile.cfg +++ b/src/win32/Makefile.cfg @@ -57,9 +57,9 @@ endif # name of the exefile ifdef SDL - EXENAME?=srb2win.exe + EXENAME?=srb2kart.exe else - EXENAME?=srb2dd.exe + EXENAME?=srb2kartdd.exe endif ifdef SDL diff --git a/src/win32/Srb2win.ico b/src/win32/Srb2win.ico index 700276fd4b9ac2810a6981eb054921f3708c702b..6e667b61c84414bc9758ea57721bb07d85a62083 100644 GIT binary patch literal 82992 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 G1OE?SzcGja diff --git a/src/y_inter.c b/src/y_inter.c index e5ff97ed..74f6978f 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -114,6 +114,9 @@ typedef union patch_t *redflag; // int_ctf uses this struct too. INT32 numplayers; // Number of players being displayed char levelstring[40]; // holds levelnames up to 32 characters + // SRB2kart + int increase[MAXPLAYERS]; //how much did the score increase by? + int time[MAXPLAYERS]; //Tournament Time } match; struct @@ -151,10 +154,12 @@ static INT32 endtic = -1; intertype_t intertype = int_none; -static void Y_AwardCoopBonuses(void); -static void Y_AwardSpecialStageBonus(void); +//static void Y_AwardCoopBonuses(void); +//static void Y_AwardSpecialStageBonus(void); +static void Y_CalculateTournamentPoints(void); // SRB2kart + static void Y_CalculateCompetitionWinners(void); -static void Y_CalculateTimeRaceWinners(void); +//static void Y_CalculateTimeRaceWinners(void); static void Y_CalculateMatchWinners(void); static void Y_FollowIntermission(void); static void Y_UnloadData(void); @@ -199,34 +204,32 @@ void Y_IntermissionDrawer(void) else V_DrawPatchFill(bgtile); - if (intertype == int_coop) + // SRB2kart 290117 - compeltely replaced this block. + if (intertype == int_timeattack) { - INT32 bonusy; - - // draw score - V_DrawScaledPatch(hudinfo[HUD_SCORE].x, hudinfo[HUD_SCORE].y, V_SNAPTOLEFT, sboscore); - V_DrawTallNum(hudinfo[HUD_SCORENUM].x, hudinfo[HUD_SCORENUM].y, V_SNAPTOLEFT, data.coop.score); - // draw time V_DrawScaledPatch(hudinfo[HUD_TIME].x, hudinfo[HUD_TIME].y, V_SNAPTOLEFT, sbotime); - if (cv_timetic.value == 1) + if (cv_timetic.value) V_DrawTallNum(hudinfo[HUD_SECONDS].x, hudinfo[HUD_SECONDS].y, V_SNAPTOLEFT, data.coop.tics); else { - // we should show centiseconds on the intermission screen too, if the conditions are right. - if (modeattacking || cv_timetic.value == 2) - { - V_DrawPaddedTallNum(hudinfo[HUD_TICS].x, hudinfo[HUD_TICS].y, V_SNAPTOLEFT, - G_TicsToCentiseconds(data.coop.tics), 2); - V_DrawScaledPatch(hudinfo[HUD_TIMETICCOLON].x, hudinfo[HUD_TIMETICCOLON].y, V_SNAPTOLEFT, sboperiod); - } - - V_DrawPaddedTallNum(hudinfo[HUD_SECONDS].x, hudinfo[HUD_SECONDS].y, V_SNAPTOLEFT, - G_TicsToSeconds(data.coop.tics), 2); - V_DrawScaledPatch(hudinfo[HUD_TIMECOLON].x, hudinfo[HUD_TIMECOLON].y, V_SNAPTOLEFT, sbocolon); - V_DrawTallNum(hudinfo[HUD_MINUTES].x, hudinfo[HUD_MINUTES].y, V_SNAPTOLEFT, - G_TicsToMinutes(data.coop.tics, false)); + if (G_TicsToSeconds(data.coop.tics) < 10) + V_DrawTallNum(hudinfo[HUD_TICS].x, hudinfo[HUD_TICS].y, 0, 0); + V_DrawTallNum(hudinfo[HUD_SECONDS].x, hudinfo[HUD_SECONDS].y, 0, G_TicsToSeconds(data.coop.tics)); + V_DrawTallNum(hudinfo[HUD_MINUTES].x, hudinfo[HUD_MINUTES].y, 0, G_TicsToMinutes(data.coop.tics, false)); + V_DrawScaledPatch(hudinfo[HUD_TIMECOLON].x, hudinfo[HUD_TIMECOLON].y, 0, sbocolon); + V_DrawTallNum(hudinfo[HUD_TICS].x, hudinfo[HUD_TICS].y, 0, (int)((data.coop.tics%TICRATE) * (100.00f/TICRATE))); + V_DrawScaledPatch(hudinfo[HUD_TIMETICCOLON].x, hudinfo[HUD_TIMETICCOLON].y, 0, sbocolon); } + + /* // SRB2kart - pulled from old coop block, just in case we need it + // we should show centiseconds on the intermission screen too, if the conditions are right. + if (modeattacking || cv_timetic.value == 2) + { + V_DrawPaddedTallNum(hudinfo[HUD_TICS].x, hudinfo[HUD_TICS].y, V_SNAPTOLEFT, + G_TicsToCentiseconds(data.coop.tics), 2); + V_DrawScaledPatch(hudinfo[HUD_TIMETICCOLON].x, hudinfo[HUD_TIMETICCOLON].y, V_SNAPTOLEFT, sboperiod); + }*/ // draw the "got through act" lines and act number V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1); @@ -235,114 +238,141 @@ void Y_IntermissionDrawer(void) if (mapheaderinfo[gamemap-1]->actnum) V_DrawScaledPatch(244, 57, 0, data.coop.ttlnum); - bonusy = 150; - // Total - V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal); - V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total); - bonusy -= (3*SHORT(tallnum[0]->height)/2) + 1; + //if (gottimebonus && endtic != -1) + // V_DrawCenteredString(BASEVIDWIDTH/2, 172, V_YELLOWMAP, "TIME BONUS UNLOCKED!"); + + V_DrawString(70, 106, V_YELLOWMAP, "LAP 1"); + V_DrawString(70, 116, V_YELLOWMAP, "LAP 2"); + V_DrawString(70, 126, V_YELLOWMAP, "LAP 3"); - // Draw bonuses - for (i = 3; i >= 0; --i) { - if (data.coop.bonuses[i].display) - { - V_DrawScaledPatch(152, bonusy, 0, data.coop.bonuspatches[i]); - V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.bonuses[i].points); - } - bonusy -= (3*SHORT(tallnum[0]->height)/2) + 1; + INT32 laptime; + laptime = stplyr->checkpointtimes[(numstarposts+1) - 1]; + V_DrawRightAlignedString(250, 106, 0, va("%d:%02d.%02d", laptime/(60*TICRATE), laptime/TICRATE % 60, (int)((laptime%TICRATE) * (100.00f/TICRATE)))); + laptime = stplyr->checkpointtimes[((numstarposts+1)*2) - 1] - stplyr->checkpointtimes[(numstarposts+1) - 1]; + V_DrawRightAlignedString(250, 116, 0, va("%d:%02d.%02d", laptime/(60*TICRATE), laptime/TICRATE % 60, (int)((laptime%TICRATE) * (100.00f/TICRATE)))); + laptime = stplyr->realtime - stplyr->checkpointtimes[((numstarposts+1)*2) - 1]; + V_DrawRightAlignedString(250, 126, 0, va("%d:%02d.%02d", laptime/(60*TICRATE), laptime/TICRATE % 60, (int)((laptime%TICRATE) * (100.00f/TICRATE)))); } } - else if (intertype == int_spec) + else if (intertype == int_race) { - static tic_t animatetic = 0; - INT32 ttheight = 16; - INT32 xoffset1 = 0; // Line 1 x offset - INT32 xoffset2 = 0; // Line 2 x offset - INT32 xoffset3 = 0; // Line 3 x offset - UINT8 drawsection = 0; + INT32 i = 0, j = 0; + INT32 x = 4; + INT32 y = 48; + char name[MAXPLAYERNAME+1]; - // draw the header - if (intertic <= TICRATE) - animatetic = 0; - else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0') - animatetic = intertic; + boolean completed[MAXPLAYERS]; + memset(completed, 0, sizeof (completed)); - if (animatetic) + // draw the level name + V_DrawCenteredString(BASEVIDWIDTH/2, 20, 0, data.match.levelstring); + V_DrawFill(4, 42, 312, 1, 0); + + if (data.match.numplayers > 8) { - INT32 animatetimer = (intertic - animatetic); - if (animatetimer <= 8) - { - xoffset1 = -(animatetimer * 40); - xoffset2 = -((animatetimer-2) * 40); - if (xoffset2 > 0) xoffset2 = 0; - } - else if (animatetimer <= 19) - { - drawsection = 1; - xoffset1 = (16-animatetimer) * 40; - xoffset2 = (18-animatetimer) * 40; - xoffset3 = (20-animatetimer) * 40; - if (xoffset1 < 0) xoffset1 = 0; - if (xoffset2 < 0) xoffset2 = 0; - } - else - drawsection = 1; + V_DrawFill(160, 32, 1, 152, 0); + + V_DrawCenteredString(x+6+(BASEVIDWIDTH/2), 32, V_YELLOWMAP, "#"); + V_DrawString(x+36+(BASEVIDWIDTH/2), 32, V_YELLOWMAP, "NAME"); + + V_DrawRightAlignedString(x+110, 32, V_YELLOWMAP, "TIME"); + + V_DrawRightAlignedString(x+152, 32, V_YELLOWMAP, "SCORE"); } - if (drawsection == 1) + V_DrawCenteredString(x+6, 32, V_YELLOWMAP, "#"); + V_DrawString(x+36, 32, V_YELLOWMAP, "NAME"); + + if (data.match.numplayers > 8) { - ttheight = 16; - V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); - ttheight += V_LevelNameHeight(data.spec.passed3) + 2; - V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3); - ttheight += V_LevelNameHeight(data.spec.passed4) + 2; - V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4); - } - else if (data.spec.passed1[0] != '\0') - { - ttheight = 24; - V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); - ttheight += V_LevelNameHeight(data.spec.passed2) + 2; - V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2); + V_DrawRightAlignedString(x+(BASEVIDWIDTH/2)+110, 32, V_YELLOWMAP, "TIME"); } else { - ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2; - V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); + V_DrawRightAlignedString(x+(BASEVIDWIDTH/2)+62, 32, V_YELLOWMAP, "TIME"); } - // draw the emeralds - if (intertic & 1) + V_DrawRightAlignedString(x+(BASEVIDWIDTH/2)+152, 32, V_YELLOWMAP, "SCORE"); + + for (i = 0; i < data.match.numplayers; i++) { - INT32 emeraldx = 80; - for (i = 0; i < 7; ++i) + char strtime[10]; + + if (data.match.spectator[i]) + continue; + + V_DrawCenteredString(x+6, y, 0, va("%d", j+1)); + j++; //We skip spectators, but not their number. + + if (playeringame[data.match.num[i]]) { - if (emeralds & (1 << i)) - V_DrawScaledPatch(emeraldx, 74, 0, emeraldpics[i]); - emeraldx += 24; + if (data.match.color[i] == 0) + V_DrawSmallScaledPatch(x+16, y-4, 0,faceprefix[*data.match.character[i]]); + else + { + UINT8 *colormap = R_GetTranslationColormap(*data.match.character[i], *data.match.color[i], GTC_CACHE); + V_DrawSmallMappedPatch(x+16, y-4, 0,faceprefix[*data.match.character[i]], colormap); + } + + if (data.match.numplayers > 8) + { + strlcpy(name, data.match.name[i], 6); + } + else + STRBUFCPY(name, data.match.name[i]); + + V_DrawString(x+36, y, V_ALLOWLOWERCASE, name); + + snprintf(strtime, sizeof strtime, "%d", data.match.scores[i]-data.match.increase[i]); + + if (data.match.numplayers > 8) + { + V_DrawRightAlignedString(x+152, y, V_YELLOWMAP, strtime); + } + else + { + V_DrawRightAlignedString(x+152+BASEVIDWIDTH/2, y, V_YELLOWMAP, strtime); + } + + if (data.match.increase[i] > 9) + snprintf(strtime, sizeof strtime, "(+%02d)", data.match.increase[i]); + else + snprintf(strtime, sizeof strtime, "(+ %d)", data.match.increase[i]); + + if (data.match.numplayers <= 8) // Only draw this with less than 8 players, otherwise we won't be able to fit the times in + { + V_DrawString(x+84+BASEVIDWIDTH/2, y, 0, strtime); + } + + snprintf(strtime, sizeof strtime, "%i:%02i.%02i", G_TicsToMinutes(data.match.time[i], true), + G_TicsToSeconds(data.match.time[i]), G_TicsToCentiseconds(data.match.time[i])); + + strtime[sizeof strtime - 1] = '\0'; + + if (data.match.numplayers > 8) + { + V_DrawRightAlignedString(x+134, y, 0, strtime); + } + else + { + V_DrawRightAlignedString(x+80+BASEVIDWIDTH/2, y, 0, strtime); + } + + + completed[i] = true; } - } - V_DrawScaledPatch(152, 108, 0, data.spec.bonuspatch); - V_DrawTallNum(BASEVIDWIDTH - 68, 109, 0, data.spec.bonus.points); - V_DrawScaledPatch(152, 124, 0, data.spec.pscore); - V_DrawTallNum(BASEVIDWIDTH - 68, 125, 0, data.spec.score); + y += 16; - // Draw continues! - if (!multiplayer /* && (data.spec.continues & 0x80) */) // Always draw outside of netplay - { - UINT8 continues = data.spec.continues & 0x7F; - - V_DrawScaledPatch(152, 150, 0, data.spec.pcontinues); - for (i = 0; i < continues; ++i) + if (y > 160) { - if ((data.spec.continues & 0x80) && i == continues-1 && (endtic < 0 || intertic%20 < 10)) - break; - V_DrawContinueIcon(246 - (i*12), 162, 0, *data.spec.playerchar, *data.spec.playercolor); + y = 48; + x += BASEVIDWIDTH/2; } } } - else if (intertype == int_match || intertype == int_race) + else if (intertype == int_match) { INT32 j = 0; INT32 x = 4; @@ -671,6 +701,7 @@ void Y_Ticker(void) if (endtic != -1) return; // tally is done + /* // SRB2kart if (intertype == int_coop) // coop or single player, normal level { INT32 i; @@ -798,6 +829,39 @@ void Y_Ticker(void) --data.spec.gotlife; } } + */ + if (intertype == int_timeattack) + { + if (!intertic) + endtic = intertic + 10*TICRATE; // 10 second pause after end of tally + } + else if (intertype == int_race) + { + INT32 q=0,r=0; + + /* // SRB2kart - removed temporarily. + if (!intertic) { + if (!((music_playing == "karwin") // Mario Kart Win + || (music_playing == "karok") // Mario Kart Ok + || (music_playing == "karlos"))) // Mario Kart Lose + S_ChangeMusicInternal("racent", true); // Backup Plan + }*/ + + if (intertic < TICRATE || intertic % 8) + return; + + for (q = 0; q < data.match.numplayers; q++) + { + if (data.match.increase[q]) { + data.match.increase[q]--; + r++; + } + } + if (r) + S_StartSound(NULL, sfx_menu1); + else + endtic = intertic + 3*TICRATE; // 3 second pause after end of tally + } else if (intertype == int_match || intertype == int_ctf || intertype == int_teammatch) // match { if (!intertic) // first time only @@ -924,10 +988,16 @@ void Y_StartIntermission(void) { timer = 0; + /* if (G_IsSpecialStage(gamemap)) intertype = (maptol & TOL_NIGHTS) ? int_nightsspec : int_spec; else intertype = (maptol & TOL_NIGHTS) ? int_nights : int_coop; + */ + if (modeattacking) + intertype = int_timeattack; + else + intertype = int_race; } else { @@ -941,6 +1011,7 @@ void Y_StartIntermission(void) timer = 1; } + /* // SRB2kart if (gametype == GT_COOP) { // Nights intermission is single player only @@ -950,7 +1021,8 @@ void Y_StartIntermission(void) else intertype = int_coop; } - else if (gametype == GT_TEAMMATCH) + else */ + if (gametype == GT_TEAMMATCH) intertype = int_teammatch; else if (gametype == GT_MATCH || gametype == GT_TAG @@ -985,11 +1057,11 @@ void Y_StartIntermission(void) } // fall back into the coop intermission for now - intertype = int_coop; - case int_coop: // coop or single player, normal level + intertype = int_timeattack; + case int_timeattack: // coop or single player, normal level // SRB2kart 230117 - replaced int_coop { // award time and ring bonuses - Y_AwardCoopBonuses(); + // Y_AwardCoopBonuses(); // setup time data data.coop.tics = players[consoleplayer].realtime; @@ -1079,6 +1151,7 @@ void Y_StartIntermission(void) break; } + /* // SRB2kart 230117 - removed case int_nightsspec: if (modeattacking && stagefailed) { @@ -1144,7 +1217,7 @@ void Y_StartIntermission(void) data.spec.headx = 48; data.spec.nowsuper = NULL; } */ - +/* // Super form stuff (normally blank) data.spec.passed3[0] = '\0'; data.spec.passed4[0] = '\0'; @@ -1190,7 +1263,7 @@ void Y_StartIntermission(void) data.spec.passedx3 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed3))/2; data.spec.passedx4 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed4))/2; break; - } + }*/ case int_match: { @@ -1224,7 +1297,7 @@ void Y_StartIntermission(void) case int_race: // (time-only race) { // Calculate who won - Y_CalculateTimeRaceWinners(); + Y_CalculateTournamentPoints(); // set up the levelstring if (mapheaderinfo[prevmap]->actnum) @@ -1241,7 +1314,7 @@ void Y_StartIntermission(void) data.match.levelstring[sizeof data.match.levelstring - 1] = '\0'; // get RESULT header - data.match.result = W_CachePatchName("RESULT", PU_STATIC); + //data.match.result = W_CachePatchName("RESULT", PU_STATIC); bgtile = W_CachePatchName("SRB2BACK", PU_STATIC); usetile = true; @@ -1360,6 +1433,7 @@ static void Y_CalculateMatchWinners(void) } } +/* // // Y_CalculateTimeRaceWinners // @@ -1403,6 +1477,7 @@ static void Y_CalculateTimeRaceWinners(void) data.match.numplayers++; } } +*/ // // Y_CalculateCompetitionWinners @@ -1665,7 +1740,7 @@ bonus_f bonuses_list[4][4] = { }; - +/* // SRB2kart 230117 - Replaced with Y_CalculateTournamentPoints // // Y_AwardCoopBonuses // @@ -1759,6 +1834,86 @@ static void Y_AwardSpecialStageBonus(void) } } } +*/ + +// +// Y_CalculateTournamentPoints +// +static void Y_CalculateTournamentPoints(void) +{ + INT32 i, j; + boolean completed[MAXPLAYERS]; + INT32 numplayersingame = 0; + INT32 zz1 = 0, zz2 = 0, zz3 = 0, zz4 = 0, zz5 = 0, zz6 = 0, zz7 = 0, zz8 = 0, + zz9 = 0, zz10 = 0, zz11 = 0, zz12 = 0, zz13 = 0, zz14 = 0, zz15 = 0, zz16 = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + numplayersingame++; + } + + zz1 = numplayersingame; zz2 = numplayersingame-1; zz3 = numplayersingame-2; zz4 = numplayersingame-3; + zz5 = numplayersingame-4; zz6 = numplayersingame-5; zz7 = numplayersingame-6; zz8 = numplayersingame-7; + zz9 = numplayersingame-8; zz10= numplayersingame-9; zz11= numplayersingame-10; zz12= numplayersingame-11; + zz13= numplayersingame-12; zz14= numplayersingame-13; zz15= numplayersingame-14; zz16= numplayersingame-15; + + if (zz1 < 0) zz1 = 0; if (zz2 < 0) zz2 = 0; if (zz3 < 0) zz3 = 0; if (zz4 < 0) zz4 = 0; + if (zz5 < 0) zz5 = 0; if (zz6 < 0) zz6 = 0; if (zz7 < 0) zz7 = 0; if (zz8 < 0) zz8 = 0; + if (zz9 < 0) zz9 = 0; if (zz10< 0) zz10= 0; if (zz11< 0) zz11= 0; if (zz12< 0) zz12= 0; + if (zz13< 0) zz13= 0; if (zz14< 0) zz14= 0; if (zz15< 0) zz15= 0; if (zz16< 0) zz16= 0; + + INT32 increase[MAXPLAYERS] = {zz1,zz2,zz3,zz4,zz5,zz6,zz7,zz8,zz9,zz10,zz11,zz12,zz13,zz14,zz15,zz16}; + + // Initialize variables + + for (j = 0; j < MAXPLAYERS; j++) + data.match.scores[j] = INT32_MAX; + + memset(data.match.time, 0, sizeof (data.match.time)); + memset(data.match.color, 0, sizeof (data.match.color)); + memset(data.match.character, 0, sizeof (data.match.character)); + memset(data.match.spectator, 0, sizeof (data.match.spectator)); + memset(data.match.increase, 0, sizeof (data.match.increase)); + memset(completed, 0, sizeof (completed)); + data.match.numplayers = 0; + i = j = 0; + + for (j = 0; j < MAXPLAYERS; j++) + { + if (!playeringame[j]) + continue; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (players[i].realtime <= data.match.scores[data.match.numplayers] && completed[i] == false) + { + data.match.time[data.match.numplayers] = players[i].realtime; + data.match.scores[data.match.numplayers] = players[i].realtime; + data.match.color[data.match.numplayers] = &players[i].skincolor; + data.match.character[data.match.numplayers] = &players[i].skin; + data.match.name[data.match.numplayers] = player_names[i]; + data.match.spectator[data.match.numplayers] = players[i].spectator; + data.match.num[data.match.numplayers] = i; + } + } + completed[data.match.num[data.match.numplayers]] = true; + if (!(players[data.match.num[data.match.numplayers]].pflags & PF_TIMEOVER + || players[data.match.num[data.match.numplayers]].spectator)) + data.match.increase[data.match.numplayers] = increase[data.match.numplayers]; + players[data.match.num[data.match.numplayers]].score += data.match.increase[data.match.numplayers]; + data.match.scores[data.match.numplayers] = players[data.match.num[data.match.numplayers]].score; + + //players[data.match.num[data.match.numplayers]].newfloorz = 0; + players[data.match.num[data.match.numplayers]].kartstuff[k_lakitu] = 0; + //players[data.match.num[data.match.numplayers]].airtime = 0; + + data.match.numplayers++; + } +} // ====== @@ -1853,6 +2008,7 @@ static void Y_UnloadData(void) switch (intertype) { + /* case int_coop: // unload the coop and single player patches UNLOAD(data.coop.ttlnum); @@ -1870,6 +2026,7 @@ static void Y_UnloadData(void) UNLOAD(data.spec.pscore); UNLOAD(data.spec.pcontinues); break; + */ case int_match: case int_race: UNLOAD(data.match.result); diff --git a/src/y_inter.h b/src/y_inter.h index 9fe95fcc..358debf7 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -20,15 +20,15 @@ void Y_EndGame(void); typedef enum { int_none, - int_coop, // Single Player/Cooperative - int_match, // Match - int_teammatch,// Team Match -// int_tag, // Tag - int_ctf, // CTF - int_spec, // Special Stage - int_nights, // NiGHTS into Dreams - int_nightsspec,// NiGHTS special stage - int_race, // Race + int_timeattack, // Time Attack + int_match, // Match + int_teammatch, // Team Match +// int_tag, // Tag + int_ctf, // CTF + int_spec, // Special Stage + int_nights, // NiGHTS into Dreams + int_nightsspec, // NiGHTS special stage + int_race, // Race int_classicrace, // Competition } intertype_t; extern intertype_t intertype;