diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 036170c29..b59adf9f3 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -546,6 +546,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) // Score is resynched in the rspfirm resync packet rsp->rings = SHORT(players[i].rings); + rsp->spheres = SHORT(players[i].spheres); rsp->lives = players[i].lives; rsp->lostlife = players[i].lostlife; rsp->continues = players[i].continues; @@ -615,6 +616,15 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->kartstuff[j] = LONG(players[i].kartstuff[j]); rsp->airtime = (tic_t)LONG(players[i].airtime); + rsp->trickpanel = (UINT8)players[i].trickpanel; + rsp->trickdelay = (boolean)players[i].trickdelay; + rsp->trickmomx = (fixed_t)LONG(players[i].trickmomx); + rsp->trickmomy = (fixed_t)LONG(players[i].trickmomy); + rsp->trickmomz = (fixed_t)LONG(players[i].trickmomz); + + rsp->bumpers = players[i].bumpers; + rsp->karmadelay = SHORT(players[i].karmadelay); + rsp->eliminated = players[i].eliminated; rsp->tumbleBounces = players[i].tumbleBounces; rsp->tumbleHeight = SHORT(players[i].tumbleHeight); @@ -694,6 +704,7 @@ static void resynch_read_player(resynch_pak *rsp) // Score is resynched in the rspfirm resync packet players[i].rings = SHORT(rsp->rings); + players[i].spheres = SHORT(rsp->spheres); players[i].lives = rsp->lives; players[i].lostlife = rsp->lostlife; players[i].continues = rsp->continues; @@ -762,6 +773,15 @@ static void resynch_read_player(resynch_pak *rsp) players[i].kartstuff[j] = LONG(rsp->kartstuff[j]); players[i].airtime = (tic_t)LONG(rsp->airtime); + players[i].trickpanel = (UINT8)rsp->trickpanel; + players[i].trickdelay = (boolean)rsp->trickdelay; + players[i].trickmomx = (fixed_t)LONG(rsp->trickmomx); + players[i].trickmomy = (fixed_t)LONG(rsp->trickmomy); + players[i].trickmomz = (fixed_t)LONG(rsp->trickmomz); + + players[i].bumpers = rsp->bumpers; + players[i].karmadelay = SHORT(rsp->karmadelay); + players[i].eliminated = rsp->eliminated; players[i].tumbleBounces = rsp->tumbleBounces; players[i].tumbleHeight = SHORT(rsp->tumbleHeight); @@ -1254,7 +1274,7 @@ static inline void CL_DrawConnectionStatus(void) cltext = M_GetText("Server full, waiting for a slot..."); else cltext = M_GetText("Requesting to join..."); - + break; #ifdef HAVE_CURL case CL_PREPAREHTTPFILES: @@ -2123,7 +2143,7 @@ void CL_UpdateServerList (void) static void M_ConfirmConnect(event_t *ev) { -#ifndef NONET +#ifndef NONET if (ev->type == ev_keydown) { if (ev->data1 == ' ' || ev->data1 == 'y' || ev->data1 == KEY_ENTER || ev->data1 == gamecontrol[0][gc_accelerate][0] || ev->data1 == gamecontrol[0][gc_accelerate][1]) @@ -2146,7 +2166,7 @@ static void M_ConfirmConnect(event_t *ev) } else cl_mode = CL_LOADFILES; - + M_ClearMenus(true); } else if (ev->data1 == 'n' || ev->data1 == KEY_ESCAPE|| ev->data1 == gamecontrol[0][gc_brake][0] || ev->data1 == gamecontrol[0][gc_brake][1]) @@ -2394,7 +2414,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic { boolean waitmore; INT32 i; - + #ifdef NONET (void)tmpsave; #endif @@ -2431,7 +2451,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic { curl_transfers++; } - + cl_mode = CL_DOWNLOADHTTPFILES; } break; @@ -2996,9 +3016,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) } } - if (K_IsPlayerWanted(&players[playernum])) - K_CalculateBattleWanted(); - + K_CalculateBattleWanted(); LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting // don't look through someone's view who isn't there diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 05d12250b..99a96fea3 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -214,6 +214,7 @@ typedef struct // Score is resynched in the confirm resync packet INT16 rings; + INT16 spheres; SINT8 lives; boolean lostlife; SINT8 continues; @@ -280,6 +281,15 @@ typedef struct // SRB2kart INT32 kartstuff[NUMKARTSTUFF]; tic_t airtime; + UINT8 trickpanel; + boolean trickdelay; + fixed_t trickmomx; + fixed_t trickmomy; + fixed_t trickmomz; + + UINT8 bumpers; + INT16 karmadelay; + boolean eliminated; UINT8 tumbleBounces; UINT16 tumbleHeight; diff --git a/src/d_main.c b/src/d_main.c index db0f74fb2..045d558ed 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1494,6 +1494,11 @@ void D_SRB2Main(void) CON_Init(); + memset(timelimits, 0, sizeof(timelimits)); + memset(pointlimits, 0, sizeof(pointlimits)); + + timelimits[GT_BATTLE] = 2; + D_RegisterServerCommands(); D_RegisterClientCommands(); // be sure that this is called before D_CheckNetGame R_RegisterEngineStuff(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 46a033bb3..460591817 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -289,10 +289,10 @@ consvar_t cv_skin[MAXSPLITSCREENPLAYERS] = { // player's followers. Also saved. consvar_t cv_follower[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("follower", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower_OnChange), - CVAR_INIT ("follower2", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower2_OnChange), - CVAR_INIT ("follower3", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower3_OnChange), - CVAR_INIT ("follower4", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower4_OnChange) + CVAR_INIT ("follower", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower_OnChange), + CVAR_INIT ("follower2", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower2_OnChange), + CVAR_INIT ("follower3", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower3_OnChange), + CVAR_INIT ("follower4", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower4_OnChange) }; // player's follower colors... Also saved... @@ -454,8 +454,7 @@ consvar_t cv_scrambleonchange = CVAR_INIT ("scrambleonchange", "Off", CV_SAVE|CV consvar_t cv_itemfinder = CVAR_INIT ("itemfinder", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, ItemFinder_OnChange); // Scoring type options -static CV_PossibleValue_t overtime_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Super"}, {0, NULL}}; -consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_NETVAR|CV_CHEAT, overtime_cons_t, NULL); +consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL); consvar_t cv_rollingdemos = CVAR_INIT ("rollingdemos", "On", CV_SAVE, CV_OnOff, NULL); @@ -463,9 +462,9 @@ static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"}, consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange); static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}}; consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange); -static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, NULL}}; -consvar_t cv_numlaps = CVAR_INIT ("numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange); -static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}}; +static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}}; +consvar_t cv_numlaps = CVAR_INIT ("numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange); +static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, "Map default"}, {0, NULL}}; consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange); // Point and time limits for every gametype @@ -2859,13 +2858,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) memset(&luabanks, 0, sizeof(luabanks)); } - if (modeattacking) - { - SetPlayerSkinByNum(0, cv_chooseskin.value-1); - players[0].skincolor = skins[players[0].skin].prefcolor; - CV_StealthSetValue(&cv_playercolor[0], players[0].skincolor); - } - mapnumber = M_MapNumber(mapname[3], mapname[4]); LUAh_MapChange(mapnumber); @@ -3475,8 +3467,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) if (gametyperules & GTR_BUMPERS) // SRB2kart { players[playernum].marescore = 0; - if (K_IsPlayerWanted(&players[playernum])) - K_CalculateBattleWanted(); + K_CalculateBattleWanted(); } K_PlayerForfeit(playernum, true); @@ -4335,15 +4326,13 @@ static void TimeLimit_OnChange(void) if (cv_timelimit.value != 0) { - CONS_Printf(M_GetText("Levels will end after %d second%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003 - timelimitintics = cv_timelimit.value * TICRATE; + CONS_Printf(M_GetText("Rounds will end after %d minute%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003 + timelimitintics = cv_timelimit.value * (60*TICRATE); // Note the deliberate absence of any code preventing // pointlimit and timelimit from being set simultaneously. // Some people might like to use them together. It works. } - else if (netgame || multiplayer) - CONS_Printf(M_GetText("Time limit disabled\n")); #ifdef HAVE_DISCORDRPC DRPC_UpdatePresence(); diff --git a/src/d_player.h b/src/d_player.h index db1777b0f..7f9ffb959 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -336,7 +336,7 @@ typedef enum k_sparkleanim, // Angle offset for ring sparkle animation k_jmp, // In Mario Kart, letting go of the jump button stops the drift k_offroad, // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed - k_pogospring, // Pogo spring bounce effect + k_brakestop, // Wait until you've made a complete stop for a few tics before letting brake go in reverse. k_spindash, // Spindash charge timer k_spindashspeed, // Spindash release speed k_spindashboost, // Spindash release boost timer @@ -450,6 +450,10 @@ typedef enum // QUICKLY GET RING TOTAL, INCLUDING RINGS CURRENTLY IN THE PICKUP ANIMATION #define RINGTOTAL(p) (p->rings + p->kartstuff[k_pickuprings]) +// CONSTANTS FOR TRICK PANELS +#define TRICKMOMZRAMP (30) +#define TRICKLAG (9) + //} // player_t struct for all respawn variables @@ -513,6 +517,7 @@ typedef struct player_s // player's ring count INT16 rings; + INT16 spheres; // Power ups. invinc and invis are tic counters. UINT16 powers[NUMPOWERS]; @@ -523,7 +528,18 @@ typedef struct player_s UINT32 distancetofinish; waypoint_t *nextwaypoint; respawnvars_t respawn; // Respawn info - tic_t airtime; // Keep track of how long you've been in the air + tic_t airtime; // Keep track of how long you've been in the air + + UINT8 trickpanel; // Trick panel state + boolean trickdelay; // Prevent tricks until control stick is neutral + fixed_t trickmomx; + fixed_t trickmomy; + fixed_t trickmomz; // Instead of stupid auxiliary variables let's... just make some ourselves. + + UINT8 bumpers; + INT16 karmadelay; + boolean eliminated; + // Bit flags. // See pflags_t, above. diff --git a/src/dehacked.c b/src/dehacked.c index bb34ebd13..4e2db6975 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1271,8 +1271,6 @@ static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame) sprinfo->pivot[frame].x = value; else if (fastcmp(word, "YPIVOT")) sprinfo->pivot[frame].y = value; - else if (fastcmp(word, "ROTAXIS")) - sprinfo->pivot[frame].rotaxis = value; else { f->curpos = lastline; @@ -6174,10 +6172,43 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_FASTRING11", "S_FASTRING12", - // Blue Sphere for special stages + // Blue Sphere "S_BLUESPHERE", - "S_BLUESPHEREBONUS", - "S_BLUESPHERESPARK", + "S_BLUESPHERE_SPAWN", + + "S_BLUESPHERE_BOUNCE1", + "S_BLUESPHERE_BOUNCE2", + + "S_BLUESPHERE_BOUNCE3", + "S_BLUESPHERE_BOUNCE4", + + "S_BLUESPHERE_BOUNCE5", + "S_BLUESPHERE_BOUNCE6", + "S_BLUESPHERE_BOUNCE7", + "S_BLUESPHERE_BOUNCE8", + + "S_BLUESPHERE_BOUNCE9", + "S_BLUESPHERE_BOUNCE10", + "S_BLUESPHERE_BOUNCE11", + "S_BLUESPHERE_BOUNCE12", + + "S_BLUESPHERE_BOUNCE13", + "S_BLUESPHERE_BOUNCE14", + "S_BLUESPHERE_BOUNCE15", + "S_BLUESPHERE_BOUNCE16", + "S_BLUESPHERE_BOUNCE17", + "S_BLUESPHERE_BOUNCE18", + "S_BLUESPHERE_BOUNCE19", + "S_BLUESPHERE_BOUNCE20", + + "S_BLUESPHERE_BOUNCE21", + "S_BLUESPHERE_BOUNCE22", + "S_BLUESPHERE_BOUNCE23", + "S_BLUESPHERE_BOUNCE24", + "S_BLUESPHERE_BOUNCE25", + "S_BLUESPHERE_BOUNCE26", + "S_BLUESPHERE_BOUNCE27", + "S_BLUESPHERE_BOUNCE28", // Bomb Sphere "S_BOMBSPHERE1", @@ -6236,13 +6267,17 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EMBLEM26", // Chaos Emeralds - "S_CEMG1", - "S_CEMG2", - "S_CEMG3", - "S_CEMG4", - "S_CEMG5", - "S_CEMG6", - "S_CEMG7", + "S_CHAOSEMERALD1", + "S_CHAOSEMERALD2", + "S_CHAOSEMERALD_UNDER", + + "S_EMERALDSPARK1", + "S_EMERALDSPARK2", + "S_EMERALDSPARK3", + "S_EMERALDSPARK4", + "S_EMERALDSPARK5", + "S_EMERALDSPARK6", + "S_EMERALDSPARK7", // Emerald hunt shards "S_SHRD1", @@ -8691,6 +8726,44 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BATTLEBUMPER2", "S_BATTLEBUMPER3", + "S_BATTLEBUMPER_EXCRYSTALA1", + "S_BATTLEBUMPER_EXCRYSTALA2", + "S_BATTLEBUMPER_EXCRYSTALA3", + "S_BATTLEBUMPER_EXCRYSTALA4", + + "S_BATTLEBUMPER_EXCRYSTALB1", + "S_BATTLEBUMPER_EXCRYSTALB2", + "S_BATTLEBUMPER_EXCRYSTALB3", + "S_BATTLEBUMPER_EXCRYSTALB4", + + "S_BATTLEBUMPER_EXCRYSTALC1", + "S_BATTLEBUMPER_EXCRYSTALC2", + "S_BATTLEBUMPER_EXCRYSTALC3", + "S_BATTLEBUMPER_EXCRYSTALC4", + + "S_BATTLEBUMPER_EXSHELLA1", + "S_BATTLEBUMPER_EXSHELLA2", + + "S_BATTLEBUMPER_EXSHELLB1", + "S_BATTLEBUMPER_EXSHELLB2", + + "S_BATTLEBUMPER_EXSHELLC1", + "S_BATTLEBUMPER_EXSHELLC2", + + "S_BATTLEBUMPER_EXDEBRIS1", + "S_BATTLEBUMPER_EXDEBRIS2", + + "S_BATTLEBUMPER_EXBLAST1", + "S_BATTLEBUMPER_EXBLAST2", + "S_BATTLEBUMPER_EXBLAST3", + "S_BATTLEBUMPER_EXBLAST4", + "S_BATTLEBUMPER_EXBLAST5", + "S_BATTLEBUMPER_EXBLAST6", + "S_BATTLEBUMPER_EXBLAST7", + "S_BATTLEBUMPER_EXBLAST8", + "S_BATTLEBUMPER_EXBLAST9", + "S_BATTLEBUMPER_EXBLAST10", + // DEZ respawn laser "S_DEZLASER", "S_DEZLASER_TRAIL1", @@ -9291,9 +9364,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_TIREGREASE", - "S_OVERTIMEFOG", - "S_OVERTIMEORB", - "S_OVERTIMEBEAM", + "S_OVERTIME_BULB1", + "S_OVERTIME_BULB2", + "S_OVERTIME_LASER", + "S_OVERTIME_CENTER", "S_BATTLECAPSULE_SIDE1", "S_BATTLECAPSULE_SIDE2", @@ -9472,16 +9546,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_REDFLAG", // Red CTF Flag "MT_BLUEFLAG", // Blue CTF Flag "MT_EMBLEM", - "MT_EMERALD1", - "MT_EMERALD2", - "MT_EMERALD3", - "MT_EMERALD4", - "MT_EMERALD5", - "MT_EMERALD6", - "MT_EMERALD7", + "MT_EMERALD", + "MT_EMERALDSPARK", "MT_EMERHUNT", // Emerald Hunt "MT_EMERALDSPAWN", // Emerald spawner w/ delay - "MT_FLINGEMERALD", // Lost emerald // Springs and others "MT_FAN", @@ -10178,6 +10246,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SINKTRAIL", "MT_BATTLEBUMPER", // Battle Mode bumper + "MT_BATTLEBUMPER_DEBRIS", + "MT_BATTLEBUMPER_BLAST", "MT_DEZLASER", @@ -10392,9 +10462,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SPBDUST", "MT_TIREGREASE", - "MT_OVERTIMEFOG", - "MT_OVERTIMEORB", - "MT_OVERTIMEBEAM", + "MT_OVERTIME_PARTICLE", + "MT_OVERTIME_CENTER", "MT_BATTLECAPSULE", "MT_BATTLECAPSULE_PIECE", @@ -10409,6 +10478,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SPINDASHDUST", "MT_SPINDASHWIND", + "MT_PAPERITEMSPOT", + #ifdef SEENAMES "MT_NAMECHECK", #endif @@ -10729,67 +10800,67 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. // Special super colors // Super Sonic Yellow - "SUPER1", // SKINCOLOR_SUPER1 - "SUPER2", // SKINCOLOR_SUPER2, - "SUPER3", // SKINCOLOR_SUPER3, - "SUPER4", // SKINCOLOR_SUPER4, - "SUPER5", // SKINCOLOR_SUPER5, + "SUPERSILVER1", + "SUPERSILVER2", + "SUPERSILVER3", + "SUPERSILVER4", + "SUPERSILVER5", - // Super Tails Orange - "TSUPER1", // SKINCOLOR_TSUPER1, - "TSUPER2", // SKINCOLOR_TSUPER2, - "TSUPER3", // SKINCOLOR_TSUPER3, - "TSUPER4", // SKINCOLOR_TSUPER4, - "TSUPER5", // SKINCOLOR_TSUPER5, + "SUPERRED1", + "SUPERRED2", + "SUPERRED3", + "SUPERRED4", + "SUPERRED5", - // Super Knuckles Red - "KSUPER1", // SKINCOLOR_KSUPER1, - "KSUPER2", // SKINCOLOR_KSUPER2, - "KSUPER3", // SKINCOLOR_KSUPER3, - "KSUPER4", // SKINCOLOR_KSUPER4, - "KSUPER5", // SKINCOLOR_KSUPER5, + "SUPERORANGE1", + "SUPERORANGE2", + "SUPERORANGE3", + "SUPERORANGE4", + "SUPERORANGE5", - // Hyper Sonic Pink - "PSUPER1", // SKINCOLOR_PSUPER1, - "PSUPER2", // SKINCOLOR_PSUPER2, - "PSUPER3", // SKINCOLOR_PSUPER3, - "PSUPER4", // SKINCOLOR_PSUPER4, - "PSUPER5", // SKINCOLOR_PSUPER5, + "SUPERGOLD1", + "SUPERGOLD2", + "SUPERGOLD3", + "SUPERGOLD4", + "SUPERGOLD5", - // Hyper Sonic Blue - "BSUPER1", // SKINCOLOR_BSUPER1, - "BSUPER2", // SKINCOLOR_BSUPER2, - "BSUPER3", // SKINCOLOR_BSUPER3, - "BSUPER4", // SKINCOLOR_BSUPER4, - "BSUPER5", // SKINCOLOR_BSUPER5, + "SUPERPERIDOT1", + "SUPERPERIDOT2", + "SUPERPERIDOT3", + "SUPERPERIDOT4", + "SUPERPERIDOT5", - // Aqua Super - "ASUPER1", // SKINCOLOR_ASUPER1, - "ASUPER2", // SKINCOLOR_ASUPER2, - "ASUPER3", // SKINCOLOR_ASUPER3, - "ASUPER4", // SKINCOLOR_ASUPER4, - "ASUPER5", // SKINCOLOR_ASUPER5, + "SUPERSKY1", + "SUPERSKY2", + "SUPERSKY3", + "SUPERSKY4", + "SUPERSKY5", - // Hyper Sonic Green - "GSUPER1", // SKINCOLOR_GSUPER1, - "GSUPER2", // SKINCOLOR_GSUPER2, - "GSUPER3", // SKINCOLOR_GSUPER3, - "GSUPER4", // SKINCOLOR_GSUPER4, - "GSUPER5", // SKINCOLOR_GSUPER5, + "SUPERPURPLE1", + "SUPERPURPLE2", + "SUPERPURPLE3", + "SUPERPURPLE4", + "SUPERPURPLE5", - // Hyper Sonic White - "WSUPER1", // SKINCOLOR_WSUPER1, - "WSUPER2", // SKINCOLOR_WSUPER2, - "WSUPER3", // SKINCOLOR_WSUPER3, - "WSUPER4", // SKINCOLOR_WSUPER4, - "WSUPER5", // SKINCOLOR_WSUPER5, + "SUPERRUST1", + "SUPERRUST2", + "SUPERRUST3", + "SUPERRUST4", + "SUPERRUST5", - // Creamy Super (Shadow?) - "CSUPER1", // SKINCOLOR_CSUPER1, - "CSUPER2", // SKINCOLOR_CSUPER2, - "CSUPER3", // SKINCOLOR_CSUPER3, - "CSUPER4", // SKINCOLOR_CSUPER4, - "CSUPER5" // SKINCOLOR_CSUPER5, + "SUPERTAN1", + "SUPERTAN2", + "SUPERTAN3", + "SUPERTAN4", + "SUPERTAN5", + + "CHAOSEMERALD1", + "CHAOSEMERALD2", + "CHAOSEMERALD3", + "CHAOSEMERALD4", + "CHAOSEMERALD5", + "CHAOSEMERALD6", + "CHAOSEMERALD7" }; static const char *const POWERS_LIST[] = { @@ -10863,7 +10934,7 @@ static const char *const KARTSTUFF_LIST[] = { "SPARKLEANIM", "JMP", "OFFROAD", - "POGOSPRING", + "BRAKESTOP", "SPINDASH", "SPINDASHSPEED", "SPINDASHBOOST", @@ -11181,13 +11252,23 @@ struct { {"LF2_VISITNEEDED",LF2_VISITNEEDED}, // Emeralds - {"EMERALD1",EMERALD1}, - {"EMERALD2",EMERALD2}, - {"EMERALD3",EMERALD3}, - {"EMERALD4",EMERALD4}, - {"EMERALD5",EMERALD5}, - {"EMERALD6",EMERALD6}, - {"EMERALD7",EMERALD7}, + {"EMERALD_CHAOS1",EMERALD_CHAOS1}, + {"EMERALD_CHAOS2",EMERALD_CHAOS2}, + {"EMERALD_CHAOS3",EMERALD_CHAOS3}, + {"EMERALD_CHAOS4",EMERALD_CHAOS4}, + {"EMERALD_CHAOS5",EMERALD_CHAOS5}, + {"EMERALD_CHAOS6",EMERALD_CHAOS6}, + {"EMERALD_CHAOS7",EMERALD_CHAOS7}, + {"EMERALD_ALLCHAOS",EMERALD_ALLCHAOS}, + {"EMERALD_SUPER1",EMERALD_SUPER1}, + {"EMERALD_SUPER2",EMERALD_SUPER2}, + {"EMERALD_SUPER3",EMERALD_SUPER3}, + {"EMERALD_SUPER4",EMERALD_SUPER4}, + {"EMERALD_SUPER5",EMERALD_SUPER5}, + {"EMERALD_SUPER6",EMERALD_SUPER6}, + {"EMERALD_SUPER7",EMERALD_SUPER7}, + {"EMERALD_ALLSUPER",EMERALD_ALLSUPER}, + {"EMERALD_ALL",EMERALD_ALL}, // SKINCOLOR_ doesn't include these..! {"MAXSKINCOLORS",MAXSKINCOLORS}, @@ -11281,6 +11362,7 @@ struct { {"DMG_EXPLODE",DMG_EXPLODE}, {"DMG_TUMBLE",DMG_TUMBLE}, {"DMG_STING",DMG_STING}, + {"DMG_KARMA",DMG_KARMA}, //// Death types {"DMG_INSTAKILL",DMG_INSTAKILL}, {"DMG_DEATHPIT",DMG_DEATHPIT}, @@ -11492,11 +11574,6 @@ struct { {"DI_SOUTHEAST",DI_SOUTHEAST}, {"NUMDIRS",NUMDIRS}, - // Sprite rotation axis (rotaxis_t) - {"ROTAXIS_X",ROTAXIS_X}, - {"ROTAXIS_Y",ROTAXIS_Y}, - {"ROTAXIS_Z",ROTAXIS_Z}, - // Buttons (ticcmd_t) // SRB2kart {"BT_ACCELERATE",BT_ACCELERATE}, {"BT_DRIFT",BT_DRIFT}, diff --git a/src/doomdef.h b/src/doomdef.h index 9c4664135..c51cf4a5f 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -386,6 +386,14 @@ typedef enum SKINCOLOR_SUPERTAN4, SKINCOLOR_SUPERTAN5, + SKINCOLOR_CHAOSEMERALD1, + SKINCOLOR_CHAOSEMERALD2, + SKINCOLOR_CHAOSEMERALD3, + SKINCOLOR_CHAOSEMERALD4, + SKINCOLOR_CHAOSEMERALD5, + SKINCOLOR_CHAOSEMERALD6, + SKINCOLOR_CHAOSEMERALD7, + SKINCOLOR_FIRSTFREESLOT, SKINCOLOR_LASTFREESLOT = SKINCOLOR_FIRSTFREESLOT + NUMCOLORFREESLOTS - 1, @@ -661,10 +669,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Render flats on walls #define WALLFLATS -/// - SRB2Kart options - -/// Camera always has noclip. -#define NOCLIPCAM - /// Divide volume of music and sounds by this much (loudest sounds on earth) #define VOLUME_DIVIDER 4 #define USER_VOLUME_SCALE 2 @@ -682,4 +686,11 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; #undef UPDATE_ALERT #endif +/// - SRB2Kart options - +/// Camera always has noclip. +#define NOCLIPCAM + +/// Other karma comeback modes +//#define OTHERKARMAMODES + #endif // __DOOMDEF__ diff --git a/src/doomstat.h b/src/doomstat.h index 629e5cead..2df6caeb5 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -456,30 +456,31 @@ enum GameTypeRules { // Race rules GTR_CIRCUIT = 1, // Enables the finish line, laps, and the waypoint system. - GTR_RINGS = 1<<1, // Rings will be spawned in this mode. (Don't get too cheeky, ring sting is still enabled :]) GTR_BOTS = 1<<2, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype. // Battle gametype rules GTR_BUMPERS = 1<<3, // Enables the bumper health system - GTR_WANTED = 1<<4, // Enables the wanted anti-camping system - GTR_KARMA = 1<<5, // Enables the Karma system if you're out of bumpers - GTR_ITEMARROWS = 1<<6, // Show item box arrows above players - GTR_CAPSULES = 1<<7, // Enables the wanted anti-camping system - GTR_BATTLESTARTS = 1<<8, // Use Battle Mode start positions. + GTR_SPHERES = 1<<4, // Replaces rings with blue spheres + GTR_PAPERITEMS = 1<<5, // Replaces item boxes with paper item spawners + GTR_WANTED = 1<<6, // Enables the wanted anti-camping system + GTR_KARMA = 1<<7, // Enables the Karma system if you're out of bumpers + GTR_ITEMARROWS = 1<<8, // Show item box arrows above players + GTR_CAPSULES = 1<<9, // Enables the wanted anti-camping system + GTR_BATTLESTARTS = 1<<10, // Use Battle Mode start positions. - GTR_POINTLIMIT = 1<<9, // Reaching point limit ends the round - GTR_TIMELIMIT = 1<<10, // Reaching time limit ends the round - GTR_OVERTIME = 1<<11, // Allow overtime behavior + GTR_POINTLIMIT = 1<<11, // Reaching point limit ends the round + GTR_TIMELIMIT = 1<<12, // Reaching time limit ends the round + GTR_OVERTIME = 1<<13, // Allow overtime behavior // Custom gametype rules - GTR_TEAMS = 1<<12, // Teams are forced on - GTR_NOTEAMS = 1<<13, // Teams are forced off - GTR_TEAMSTARTS = 1<<14, // Use team-based start positions + GTR_TEAMS = 1<<14, // Teams are forced on + GTR_NOTEAMS = 1<<15, // Teams are forced off + GTR_TEAMSTARTS = 1<<16, // Use team-based start positions // Grand Prix rules - GTR_CAMPAIGN = 1<<15, // Handles cup-based progression - GTR_LIVES = 1<<16, // Lives system, players are forced to spectate during Game Over. - GTR_SPECIALBOTS = 1<<17, // Bot difficulty gets stronger between rounds, and the rival system is enabled. + GTR_CAMPAIGN = 1<<17, // Handles cup-based progression + GTR_LIVES = 1<<18, // Lives system, players are forced to spectate during Game Over. + GTR_SPECIALBOTS = 1<<19, // Bot difficulty gets stronger between rounds, and the rival system is enabled. // free: to and including 1<<31 }; @@ -521,15 +522,34 @@ extern UINT32 matchesplayed; extern UINT8 stagefailed; // Emeralds stored as bits to throw savegame hackers off. +typedef enum +{ + EMERALD_CHAOS1 = 1, + EMERALD_CHAOS2 = 1<<1, + EMERALD_CHAOS3 = 1<<2, + EMERALD_CHAOS4 = 1<<3, + EMERALD_CHAOS5 = 1<<4, + EMERALD_CHAOS6 = 1<<5, + EMERALD_CHAOS7 = 1<<6, + EMERALD_ALLCHAOS = EMERALD_CHAOS1|EMERALD_CHAOS2|EMERALD_CHAOS3|EMERALD_CHAOS4|EMERALD_CHAOS5|EMERALD_CHAOS6|EMERALD_CHAOS7, + + EMERALD_SUPER1 = 1<<7, + EMERALD_SUPER2 = 1<<8, + EMERALD_SUPER3 = 1<<9, + EMERALD_SUPER4 = 1<<10, + EMERALD_SUPER5 = 1<<11, + EMERALD_SUPER6 = 1<<12, + EMERALD_SUPER7 = 1<<13, + EMERALD_ALLSUPER = EMERALD_SUPER1|EMERALD_SUPER2|EMERALD_SUPER3|EMERALD_SUPER4|EMERALD_SUPER5|EMERALD_SUPER6|EMERALD_SUPER7, + + EMERALD_ALL = EMERALD_ALLCHAOS|EMERALD_ALLSUPER +} emeraldflags_t; + extern UINT16 emeralds; -#define EMERALD1 1 -#define EMERALD2 2 -#define EMERALD3 4 -#define EMERALD4 8 -#define EMERALD5 16 -#define EMERALD6 32 -#define EMERALD7 64 -#define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) + +#define ALLCHAOSEMERALDS(v) ((v & EMERALD_ALLCHAOS) == EMERALD_ALLCHAOS) +#define ALLSUPEREMERALDS(v) ((v & EMERALD_ALLSUPER) == EMERALD_ALLSUPER) +#define ALLEMERALDS(v) ((v & EMERALD_ALL) == EMERALD_ALL) #define NUM_LUABANKS 16 // please only make this number go up between versions, never down. you'll break saves otherwise. also, must fit in UINT8 extern INT32 luabanks[NUM_LUABANKS]; diff --git a/src/f_finale.c b/src/f_finale.c index 4355cf231..0d290330c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -889,7 +889,7 @@ void F_StartGameEvaluation(void) // Just in case they're open ... somehow M_ClearMenus(true); - goodending = (ALL7EMERALDS(emeralds)); + goodending = (ALLCHAOSEMERALDS(emeralds)); gameaction = ga_nothing; paused = false; @@ -1154,7 +1154,7 @@ static void F_CacheEnding(void) endescp[4] = W_CachePatchName("ENDESCP4", PU_PATCH); // so we only need to check once - if ((goodending = ALL7EMERALDS(emeralds))) + if ((goodending = ALLCHAOSEMERALDS(emeralds))) { endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_PATCH); endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_PATCH); diff --git a/src/g_demo.c b/src/g_demo.c index 7c2f9f25c..693a4f095 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -104,7 +104,7 @@ demoghost *ghosts = NULL; // DEMO RECORDING // -#define DEMOVERSION 0x0004 +#define DEMOVERSION 0x0007 #define DEMOHEADER "\xF0" "KartReplay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -112,7 +112,7 @@ demoghost *ghosts = NULL; #define DF_BREAKTHECAPSULES 0x04 // This demo is from Break the Capsules and contains its final completion time! #define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? -#define DF_LUAVARS 0x20 // this demo contains extra lua vars; this is mostly used for backwards compability +#define DF_LUAVARS 0x20 // this demo contains extra lua vars #define DF_ATTACKSHIFT 1 #define DF_ENCORE 0x40 @@ -419,7 +419,10 @@ void G_WriteDemoExtraData(void) { // write follower memset(name, 0, 16); - strncpy(name, followers[players[i].followerskin].skinname, 16); + if (players[i].followerskin == -1) + strncpy(name, "None", 16); + else + strncpy(name, followers[players[i].followerskin].skinname, 16); M_Memcpy(demo_p, name, 16); demo_p += 16; @@ -619,13 +622,21 @@ void G_WriteAllGhostTics(void) counter++; - if (counter % cv_netdemosyncquality.value != 0) // Only write 1 in this many ghost datas per tic to cut down on multiplayer replay size. + if (multiplayer && ((counter % cv_netdemosyncquality.value) != 0)) // Only write 1 in this many ghost datas per tic to cut down on multiplayer replay size. continue; WRITEUINT8(demo_p, i); G_WriteGhostTic(players[i].mo, i); } WRITEUINT8(demo_p, 0xFF); + + // attention here for the ticcmd size! + // latest demos with mouse aiming byte in ticcmd + if (demo_p >= demoend - (13 + 9 + 9)) + { + G_CheckDemoStatus(); // no more space + return; + } } void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) @@ -722,26 +733,22 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) ghostext[playernum].flags |= EZT_SPRITE; } + if (ghost->player && ( + ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] || + ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] || + ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper] + )) + { + ghostext[playernum].flags |= EZT_KART; + ghostext[playernum].kartitem = ghost->player->kartstuff[k_itemtype]; + ghostext[playernum].kartamount = ghost->player->kartstuff[k_itemamount]; + ghostext[playernum].kartbumpers = ghost->player->kartstuff[k_bumper]; + } + if (ghostext[playernum].flags) { ziptic |= GZT_EXTRA; - if (ghost->player) - { - if ( - ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] || - ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] || - ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper] - ) - { - ghostext[playernum].flags |= EZT_KART; - ghostext[playernum].kartitem = ghost->player->kartstuff[k_itemtype]; - ghostext[playernum].kartamount = ghost->player->kartstuff[k_itemamount]; - ghostext[playernum].kartbumpers = ghost->player->kartstuff[k_bumper]; - - } - } - if (ghostext[playernum].color == ghostext[playernum].lastcolor) ghostext[playernum].flags &= ~EZT_COLOR; if (ghostext[playernum].scale == ghostext[playernum].lastscale) @@ -836,14 +843,6 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) oldghost[playernum].flags2 &= ~MF2_AMBUSH; *ziptic_p = ziptic; - - // attention here for the ticcmd size! - // latest demos with mouse aiming byte in ticcmd - if (demo_p >= demoend - (13 + 9 + 9)) - { - G_CheckDemoStatus(); // no more space - return; - } } void G_ConsAllGhostTics(void) @@ -1067,16 +1066,18 @@ void G_GhostTicker(void) if (ziptic & DXD_FOLLOWER) g->p += 32; // ok (32 because there's both the skin and the colour) if (ziptic & DXD_PLAYSTATE && READUINT8(g->p) != DXD_PST_PLAYING) - I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this + I_Error("Ghost is not a record attack ghost PLAYSTATE"); //@TODO lmao don't blow up like this } else if (ziptic == DW_RNG) g->p += 4; // RNG seed else - I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this + I_Error("Ghost is not a record attack ghost DXD"); //@TODO lmao don't blow up like this ziptic = READUINT8(g->p); } + ziptic = READUINT8(g->p); + if (ziptic & ZT_FWD) g->p++; if (ziptic & ZT_TURNING) @@ -1086,9 +1087,9 @@ void G_GhostTicker(void) if (ziptic & ZT_AIMING) g->p += 2; if (ziptic & ZT_LATENCY) - g->p += 1; + g->p++; if (ziptic & ZT_FLAGS) - g->p += 1; + g->p++; // Grab ghost data. ziptic = READUINT8(g->p); @@ -1096,7 +1097,7 @@ void G_GhostTicker(void) if (ziptic == 0xFF) goto skippedghosttic; // Didn't write ghost info this frame else if (ziptic != 0) - I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this + I_Error("Ghost is not a record attack ghost ZIPTIC"); //@TODO lmao don't blow up like this ziptic = READUINT8(g->p); if (ziptic & GZT_XYZ) @@ -1109,17 +1110,17 @@ void G_GhostTicker(void) { if (ziptic & GZT_MOMXY) { - g->oldmo.momx = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p); - g->oldmo.momy = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p); + g->oldmo.momx = READFIXED(g->p); + g->oldmo.momy = READFIXED(g->p); } if (ziptic & GZT_MOMZ) - g->oldmo.momz = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p); + g->oldmo.momz = READFIXED(g->p); g->oldmo.x += g->oldmo.momx; g->oldmo.y += g->oldmo.momy; g->oldmo.z += g->oldmo.momz; } if (ziptic & GZT_ANGLE) - g->mo->angle = READUINT8(g->p)<<24; + g->oldmo.angle = READUINT8(g->p)<<24; if (ziptic & GZT_FRAME) g->oldmo.frame = READUINT8(g->p); if (ziptic & GZT_SPR2) @@ -1205,30 +1206,6 @@ void G_GhostTicker(void) g->p += 12; // kartitem, kartamount, kartbumpers } - if (READUINT8(g->p) != 0xFF) // Make sure there isn't other ghost data here. - I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this - -skippedghosttic: - // Tick ghost colors (Super and Mario Invincibility flashing) - switch(g->color) - { - case GHC_SUPER: // Super (P_DoSuperStuff) - if (g->mo->skin) - { - skin_t *skin = (skin_t *)g->mo->skin; - g->mo->color = skin->supercolor; - } - else - g->mo->color = SKINCOLOR_SUPERGOLD1; - g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4); - break; - case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer) - g->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (FIRSTSUPERCOLOR - SKINCOLOR_RUBY))); // Passes through all saturated colours - break; - default: - break; - } - #define follow g->mo->tracer if (ziptic & GZT_FOLLOW) { // Even more... @@ -1294,6 +1271,31 @@ skippedghosttic: P_RemoveMobj(follow); P_SetTarget(&follow, NULL); } + +skippedghosttic: + // Tick ghost colors (Super and Mario Invincibility flashing) + switch(g->color) + { + case GHC_SUPER: // Super (P_DoSuperStuff) + if (g->mo->skin) + { + skin_t *skin = (skin_t *)g->mo->skin; + g->mo->color = skin->supercolor; + } + else + g->mo->color = SKINCOLOR_SUPERGOLD1; + g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4); + break; + case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer) + g->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (FIRSTSUPERCOLOR - SKINCOLOR_RUBY))); // Passes through all saturated colours + break; + default: + break; + } + + if (READUINT8(g->p) != 0xFF) // Make sure there isn't other ghost data here. + I_Error("Ghost is not a record attack ghost GHOSTEND"); //@TODO lmao don't blow up like this + // Demo ends after ghost data. if (*g->p == DEMOMARKER) { @@ -1314,6 +1316,7 @@ skippedghosttic: Z_Free(g); continue; } + p = g; #undef follow } @@ -1436,8 +1439,11 @@ void G_PreviewRewind(tic_t previewtime) players[i].drawangle = info->playerinfo[i].player.drawangle + FixedMul((INT32) (next_info->playerinfo[i].player.drawangle - info->playerinfo[i].player.drawangle), tweenvalue); players[i].mo->sprite = info->playerinfo[i].mobj.sprite; + players[i].mo->sprite2 = info->playerinfo[i].mobj.sprite2; players[i].mo->frame = info->playerinfo[i].mobj.frame; + players[i].mo->hitlag = info->playerinfo[i].mobj.hitlag; + players[i].realtime = info->playerinfo[i].player.realtime; for (j = 0; j < NUMKARTSTUFF; j++) players[i].kartstuff[j] = info->playerinfo[i].player.kartstuff[j]; @@ -1462,7 +1468,7 @@ void G_ConfirmRewind(tic_t rewindtime) if (rewindtime <= starttime) { - demo.rewinding = false; + demo.rewinding = true; // this doesn't APPEAR to cause any misery, and it allows us to prevent running all the wipes again G_DoPlayDemo(NULL); // Restart the current demo } else @@ -1899,7 +1905,8 @@ void G_BeginRecording(void) if (encoremode) demoflags |= DF_ENCORE; - demoflags |= DF_LUAVARS; + if (multiplayer) + demoflags |= DF_LUAVARS; // Setup header. M_Memcpy(demo_p, DEMOHEADER, 12); demo_p += 12; @@ -2033,9 +2040,8 @@ void G_BeginRecording(void) WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing // player lua vars, always saved even if empty - LUA_Archive(&demo_p); - - WRITEUINT32(demo_p,P_GetInitSeed()); + if (demoflags & DF_LUAVARS) + LUA_Archive(&demo_p); memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); @@ -2712,7 +2718,6 @@ void G_DoPlayDemo(char *defdemoname) demo.version = READUINT16(demo_p); switch(demo.version) { - case 0x000d: case DEMOVERSION: // latest always supported break; // too old, cannot support. @@ -3101,7 +3106,6 @@ void G_AddGhost(char *defdemoname) ghostversion = READUINT16(p); switch(ghostversion) { - case 0x000d: case DEMOVERSION: // latest always supported break; // too old, cannot support. @@ -3145,6 +3149,14 @@ void G_AddGhost(char *defdemoname) return; } + if (flags & DF_LUAVARS) // can't be arsed to add support for grinding away ported lua material + { + CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data contains luavars, cannot continue.\n"), pdemoname); + Z_Free(pdemoname); + Z_Free(buffer); + return; + } + p++; // gametype G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts. @@ -3211,6 +3223,8 @@ void G_AddGhost(char *defdemoname) kartspeed = READUINT8(p); kartweight = READUINT8(p); + p += 4; // followitem (maybe change later) + if (READUINT8(p) != 0xFF) { CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname); diff --git a/src/g_game.c b/src/g_game.c index 0151783e9..b0fcf7bf3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1252,7 +1252,7 @@ void G_StartTitleCard(void) { // The title card has been disabled for this map. // Oh well. - if (!G_IsTitleCardAvailable()) + if (!G_IsTitleCardAvailable() || demo.rewinding) { WipeStageTitle = false; return; @@ -1575,7 +1575,7 @@ boolean G_CouldView(INT32 playernum) // I don't know if we want this actually, but I'll humor the suggestion anyway if ((gametyperules & GTR_BUMPERS) && !demo.playback) { - if (player->kartstuff[k_bumper] <= 0) + if (player->bumpers <= 0) return false; } @@ -2056,6 +2056,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) UINT8 botdifficulty; INT16 rings; + INT16 spheres; angle_t playerangleturn; UINT8 botdiffincrease; @@ -2071,9 +2072,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT32 roulettetype; INT32 growshrinktimer; INT32 bumper; - INT32 comebackpoints; INT32 wanted; boolean songcredit = false; + boolean eliminated; score = players[player].score; marescore = players[player].marescore; @@ -2139,8 +2140,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) itemamount = 0; growshrinktimer = 0; bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0); - rings = ((gametyperules & GTR_RINGS) ? 5 : 0); - comebackpoints = 0; + rings = ((gametyperules & GTR_SPHERES) ? 0 : 5); + spheres = 0; + eliminated = false; wanted = 0; } else @@ -2165,9 +2167,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) else growshrinktimer = 0; - bumper = players[player].kartstuff[k_bumper]; + bumper = players[player].bumpers; rings = players[player].rings; - comebackpoints = players[player].kartstuff[k_comebackpoints]; + spheres = players[player].spheres; + eliminated = players[player].eliminated; wanted = players[player].kartstuff[k_wanted]; } @@ -2215,6 +2218,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->bot = bot; p->botvars.difficulty = botdifficulty; p->rings = rings; + p->spheres = spheres; p->botvars.diffincrease = botdiffincrease; p->botvars.rival = botrival; p->xtralife = xtralife; @@ -2225,9 +2229,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->kartstuff[k_itemtype] = itemtype; p->kartstuff[k_itemamount] = itemamount; p->kartstuff[k_growshrinktimer] = growshrinktimer; - p->kartstuff[k_bumper] = bumper; - p->kartstuff[k_comebackpoints] = comebackpoints; - p->kartstuff[k_comebacktimer] = comebacktime; + p->bumpers = bumper; + p->karmadelay = comebacktime; + p->eliminated = eliminated; p->kartstuff[k_wanted] = wanted; p->kartstuff[k_eggmanblame] = -1; p->kartstuff[k_lastdraft] = -1; @@ -2787,9 +2791,9 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Race - GTR_CIRCUIT|GTR_RINGS|GTR_BOTS, + GTR_CIRCUIT|GTR_BOTS, // Battle - GTR_BUMPERS|GTR_WANTED|GTR_KARMA|GTR_ITEMARROWS|GTR_CAPSULES|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME + GTR_SPHERES|GTR_BUMPERS|GTR_PAPERITEMS|GTR_WANTED|GTR_KARMA|GTR_ITEMARROWS|GTR_CAPSULES|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME }; // diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index f9e6f0c11..9cb48620e 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -101,21 +101,13 @@ typedef struct //Hurdler: Transform (coords + angles) //BP: transform order : scale(rotation_x(rotation_y(translation(v)))) -// Kart features -//#define USE_FTRANSFORM_ANGLEZ -//#define USE_FTRANSFORM_MIRROR - // Vanilla features #define USE_MODEL_NEXTFRAME typedef struct { FLOAT x,y,z; // position -#ifdef USE_FTRANSFORM_ANGLEZ FLOAT anglex,angley,anglez; // aimingangle / viewangle -#else - FLOAT anglex,angley; // aimingangle / viewangle -#endif FLOAT scalex,scaley,scalez; FLOAT fovxangle, fovyangle; UINT8 splitscreen; @@ -123,13 +115,10 @@ typedef struct boolean shearing; // 14042019 angle_t viewaiming; // 17052019 boolean roll; - SINT8 rollflip; FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ - UINT8 rotaxis; FLOAT centerx, centery; -#ifdef USE_FTRANSFORM_MIRROR + FLOAT rollx, rollz; boolean mirror; // SRB2Kart: Encore Mode -#endif } FTransform; // Transformed vector, as passed to HWR API diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 1480ee839..613005421 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -50,7 +50,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); //Hurdler: added for new development -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface, FBITFIELD blendmode); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(SetTransform) (FTransform *stransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index fd131fa26..e44ac6bc6 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4905,6 +4905,7 @@ static void HWR_ProjectSprite(mobj_t *thing) #ifdef ROTSPRITE patch_t *rotsprite = NULL; INT32 rollangle = 0; + angle_t spriterotangle = 0; #endif if (!thing) @@ -5043,9 +5044,11 @@ static void HWR_ProjectSprite(mobj_t *thing) spr_topoffset = spritecachedinfo[lumpoff].topoffset; #ifdef ROTSPRITE - if (thing->rollangle) + spriterotangle = R_SpriteRotationAngle(thing); + + if (spriterotangle != 0) { - rollangle = R_GetRollAngle(thing->rollangle); + rollangle = R_GetRollAngle(spriterotangle); if (!(sprframe->rotsprite.cached & (1<sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip); rotsprite = sprframe->rotsprite.patch[rot][rollangle]; @@ -5526,6 +5529,8 @@ static void HWR_DrawSkyBackground(player_t *player) fixed_t rol = AngleFixed(player->viewrollangle); dometransform.rollangle = FIXED_TO_FLOAT(rol); dometransform.roll = true; + dometransform.rollx = 1.0f; + dometransform.rollz = 0.0f; } dometransform.splitscreen = r_splitscreen; @@ -5804,6 +5809,8 @@ void HWR_RenderSkyboxView(player_t *player) fixed_t rol = AngleFixed(player->viewrollangle); atransform.rollangle = FIXED_TO_FLOAT(rol); atransform.roll = true; + atransform.rollx = 1.0f; + atransform.rollz = 0.0f; } atransform.splitscreen = r_splitscreen; @@ -6005,6 +6012,8 @@ void HWR_RenderPlayerView(void) fixed_t rol = AngleFixed(player->viewrollangle); atransform.rollangle = FIXED_TO_FLOAT(rol); atransform.roll = true; + atransform.rollx = 1.0f; + atransform.rollz = 0.0f; } atransform.splitscreen = r_splitscreen; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index f68771a1b..54c74d44c 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1353,10 +1353,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !(spr->mobj->frame & FF_HORIZONTALFLIP)); spritedef_t *sprdef; spriteframe_t *sprframe; - spriteinfo_t *sprinfo; - angle_t ang; INT32 mod; float finalscale; + FBITFIELD blendmode = PF_Masked; // hitlag vibrating if (spr->mobj->hitlag > 0) @@ -1378,12 +1377,17 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) //durs = tics; if (spr->mobj->drawflags & MFD_TRANSMASK) - HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf); + blendmode = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf); else if (spr->mobj->frame & FF_TRANSMASK) - HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + blendmode = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else Surf.PolyColor.s.alpha = 0xFF; + if (blendmode == PF_Masked) + { + blendmode |= PF_Occlude; + } + // dont forget to enabled the depth test because we can't do this like // before: polygons models are not sorted @@ -1393,12 +1397,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins]; md2->skin = (skin_t*)spr->mobj->skin-skins; - sprinfo = &((skin_t *)spr->mobj->skin)->sprinfo[spr->mobj->sprite2]; } else { md2 = &md2_models[spr->mobj->sprite]; - sprinfo = &spriteinfo[spr->mobj->sprite]; } // texture loading before model init, so it knows if sprite graphics are used, which @@ -1593,60 +1595,35 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } p.rollangle = 0.0f; - p.rollflip = 1; - p.rotaxis = 0; + if (spr->mobj->rollangle) { + fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know fixed_t anglef = AngleFixed(spr->mobj->rollangle); + p.rollangle = FIXED_TO_FLOAT(anglef); p.roll = true; // rotation pivot - p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2); - p.centery = FIXED_TO_FLOAT(spr->mobj->height/(flip ? -2 : 2)); + p.centerx = FIXED_TO_FLOAT(spr->mobj->radius / 2); + p.centery = FIXED_TO_FLOAT(spr->mobj->height / 2); - // rotation axis - if (sprinfo->available) - p.rotaxis = (UINT8)(sprinfo->pivot[(spr->mobj->frame & FF_FRAMEMASK)].rotaxis); - - // for NiGHTS specifically but should work everywhere else - ang = R_PointToAngle (spr->mobj->x, spr->mobj->y) - (spr->mobj->player ? spr->mobj->player->drawangle : spr->mobj->angle); - if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right - p.rollflip = 1; - else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left - p.rollflip = -1; - - if (flip) - p.rollflip *= -1; + // rotation axes relative to camera + p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT)); + p.rollz = FIXED_TO_FLOAT(FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT)); } - p.anglex = 0.0f; - -#ifdef USE_FTRANSFORM_ANGLEZ - // Slope rotation from Kart - p.anglez = 0.0f; - if (spr->mobj->standingslope) - { - fixed_t tempz = spr->mobj->standingslope->normal.z; - fixed_t tempy = spr->mobj->standingslope->normal.y; - fixed_t tempx = spr->mobj->standingslope->normal.x; - fixed_t tempangle = AngleFixed(R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx)); - p.anglez = FIXED_TO_FLOAT(tempangle); - tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy)); - p.anglex = FIXED_TO_FLOAT(tempangle); - } -#endif + p.anglez = FIXED_TO_FLOAT(AngleFixed(spr->mobj->pitch)); + p.anglex = FIXED_TO_FLOAT(AngleFixed(spr->mobj->roll)); // SRB2CBTODO: MD2 scaling support finalscale *= FIXED_TO_FLOAT(spr->mobj->scale); p.flip = atransform.flip; -#ifdef USE_FTRANSFORM_MIRROR - p.mirror = atransform.mirror; // from Kart -#endif + p.mirror = atransform.mirror; HWD.pfnSetShader(SHADER_MODEL); // model shader - HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf); + HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf, blendmode); } return true; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 942d3d3de..1ded58204 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2513,7 +2513,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model) #define BUFFER_OFFSET(i) ((void*)(i)) -static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) +static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface, FBITFIELD blendmode) { static GLRGBAFloat poly = {0,0,0,0}; static GLRGBAFloat tint = {0,0,0,0}; @@ -2593,7 +2593,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 else pglColor4ubv((GLubyte*)&Surface->PolyColor.s); - SetBlend((poly.alpha < 1 ? PF_Translucent : (PF_Masked|PF_Occlude))|PF_Modulated); + SetBlend(blendmode|PF_Modulated); tint.red = byte2float[Surface->TintColor.s.red]; tint.green = byte2float[Surface->TintColor.s.green]; @@ -2610,7 +2610,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); -#ifdef USE_FTRANSFORM_MIRROR // flipped is if the object is vertically flipped // hflipped is if the object is horizontally flipped // pos->flip is if the screen is flipped vertically @@ -2623,17 +2622,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 else pglCullFace(GL_BACK); } -#else - // pos->flip is if the screen is flipped too - if (flipped ^ hflipped ^ pos->flip) // If one or three of these are active, but not two, invert the model's culling - { - pglCullFace(GL_FRONT); - } - else - { - pglCullFace(GL_BACK); - } -#endif pglPushMatrix(); // should be the same as glLoadIdentity //Hurdler: now it seems to work @@ -2643,22 +2631,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 if (hflipped) scalez = -scalez; -#ifdef USE_FTRANSFORM_ANGLEZ - pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart -#endif - pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); + pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f); + pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); if (pos->roll) { - float roll = (1.0f * pos->rollflip); pglTranslatef(pos->centerx, pos->centery, 0); - if (pos->rotaxis == 2) // Z - pglRotatef(pos->rollangle, 0.0f, 0.0f, roll); - else if (pos->rotaxis == 1) // Y - pglRotatef(pos->rollangle, 0.0f, roll, 0.0f); - else // X - pglRotatef(pos->rollangle, roll, 0.0f, 0.0f); + pglRotatef(pos->rollangle, pos->rollx, 0.0f, pos->rollz); pglTranslatef(-pos->centerx, -pos->centery, 0); } @@ -2812,9 +2792,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 // -----------------+ // HWRAPI DrawModel : Draw a model // -----------------+ -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface, FBITFIELD blendmode) { - DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface); + DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface, blendmode); } // -----------------+ @@ -2831,13 +2811,9 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) if (stransform) { used_fov = stransform->fovxangle; -#ifdef USE_FTRANSFORM_MIRROR - // mirroring from Kart if (stransform->mirror) pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez); - else -#endif - if (stransform->flip) + else if (stransform->flip) pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez); else pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez); diff --git a/src/info.c b/src/info.c index 9fda6292a..c6f082a5c 100644 --- a/src/info.c +++ b/src/info.c @@ -135,11 +135,12 @@ char sprnames[NUMSPRITES + 1][5] = "TOKE", // Special Stage Token "RFLG", // Red CTF Flag "BFLG", // Blue CTF Flag - //"SPHR", // Sphere + "BSPH", // Sphere "NCHP", // NiGHTS chip "NSTR", // NiGHTS star "EMBM", // Emblem - "CEMG", // Chaos Emeralds + "EMRC", // Chaos Emeralds + "ESPK", "SHRD", // Emerald Hunt // Interactive Objects @@ -558,6 +559,10 @@ char sprnames[NUMSPRITES + 1][5] = "SINK", // Kitchen Sink "SITR", // Kitchen Sink Trail "KBLN", // Battle Mode Bumper + "BEXC", // Battle Bumper Explosion: Crystal + "BEXS", // Battle Bumper Explosion: Shell + "BDEB", // Battle Bumper Explosion: Debris + "BEXB", // Battle Bumper Explosion: Blast "DEZL", // DEZ Laser respawn @@ -714,7 +719,9 @@ char sprnames[NUMSPRITES + 1][5] = "DRAF", "GRES", - "OTFG", + "OTBU", + "OTLS", + "OTCP", "DBOS", // Drift boost flame @@ -1803,20 +1810,49 @@ state_t states[NUMSTATES] = {SPR_RING, 20, 1, {NULL}, 0, 0, S_FASTRING12}, // S_FASTRING11 {SPR_RING, 22, 1, {NULL}, 0, 0, S_FASTRING1}, // S_FASTRING12 - // Blue Sphere for special stages - {SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE - {SPR_SPHR, FF_FULLBRIGHT -#ifdef MANIASPHERES - |FF_ANIMATE|FF_RANDOMANIM -#endif - , -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS - {SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK + // Blue Sphere + {SPR_BSPH, FF_SEMIBRIGHT|2, TICRATE, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE1}, // S_BLUESPHERE + {SPR_BSPH, FF_SEMIBRIGHT|2, TICRATE, {A_SetRandomTics}, 1, TICRATE, S_BLUESPHERE_BOUNCE1}, // S_BLUESPHERE_SPAWN + + {SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE2}, // S_BLUESPHERE_BOUNCE1 + {SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE3}, // S_BLUESPHERE_BOUNCE2 + + {SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE4}, // S_BLUESPHERE_BOUNCE3 + {SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE5}, // S_BLUESPHERE_BOUNCE4 + + {SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE6}, // S_BLUESPHERE_BOUNCE5 + {SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE7}, // S_BLUESPHERE_BOUNCE6 + {SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE8}, // S_BLUESPHERE_BOUNCE7 + {SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE9}, // S_BLUESPHERE_BOUNCE8 + + {SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE10}, // S_BLUESPHERE_BOUNCE9 + {SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE11}, // S_BLUESPHERE_BOUNCE10 + {SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE12}, // S_BLUESPHERE_BOUNCE11 + {SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE13}, // S_BLUESPHERE_BOUNCE12 + + {SPR_BSPH, FF_SEMIBRIGHT, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE14}, // S_BLUESPHERE_BOUNCE13 + {SPR_BSPH, FF_SEMIBRIGHT|1, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE15}, // S_BLUESPHERE_BOUNCE14 + {SPR_BSPH, FF_SEMIBRIGHT|2, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE16}, // S_BLUESPHERE_BOUNCE15 + {SPR_BSPH, FF_SEMIBRIGHT|3, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE17}, // S_BLUESPHERE_BOUNCE16 + {SPR_BSPH, FF_SEMIBRIGHT|4, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE18}, // S_BLUESPHERE_BOUNCE17 + {SPR_BSPH, FF_SEMIBRIGHT|3, 4, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE19}, // S_BLUESPHERE_BOUNCE18 + {SPR_BSPH, FF_SEMIBRIGHT|2, 4, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE20}, // S_BLUESPHERE_BOUNCE19 + {SPR_BSPH, FF_SEMIBRIGHT|1, 4, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE21}, // S_BLUESPHERE_BOUNCE20 + + {SPR_BSPH, FF_SEMIBRIGHT, 6, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE22}, // S_BLUESPHERE_BOUNCE21 + {SPR_BSPH, FF_SEMIBRIGHT|1, 6, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE23}, // S_BLUESPHERE_BOUNCE22 + {SPR_BSPH, FF_SEMIBRIGHT|2, 6, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE24}, // S_BLUESPHERE_BOUNCE23 + {SPR_BSPH, FF_SEMIBRIGHT|3, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE25}, // S_BLUESPHERE_BOUNCE24 + {SPR_BSPH, FF_SEMIBRIGHT|4, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE26}, // S_BLUESPHERE_BOUNCE25 + {SPR_BSPH, FF_SEMIBRIGHT|3, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE27}, // S_BLUESPHERE_BOUNCE26 + {SPR_BSPH, FF_SEMIBRIGHT|2, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE28}, // S_BLUESPHERE_BOUNCE27 + {SPR_BSPH, FF_SEMIBRIGHT|1, 9, {NULL}, 0, 0, S_BLUESPHERE}, // S_BLUESPHERE_BOUNCE28 // Bomb Sphere - {SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2}, // S_BOMBSPHERE1 - {SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3}, // S_BOMBSPHERE2 - {SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4}, // S_BOMBSPHERE3 - {SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1}, // S_BOMBSPHERE4 + {SPR_BSPH, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2}, // S_BOMBSPHERE1 + {SPR_BSPH, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3}, // S_BOMBSPHERE2 + {SPR_BSPH, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4}, // S_BOMBSPHERE3 + {SPR_BSPH, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1}, // S_BOMBSPHERE4 // NiGHTS Chip {SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIP @@ -1869,13 +1905,17 @@ state_t states[NUMSTATES] = {SPR_EMBM, 25, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM26 // Chaos Emeralds - {SPR_CEMG, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG1 - {SPR_CEMG, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG2 - {SPR_CEMG, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG3 - {SPR_CEMG, FF_FULLBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG4 - {SPR_CEMG, FF_FULLBRIGHT|4, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG5 - {SPR_CEMG, FF_FULLBRIGHT|5, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG6 - {SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG7 + {SPR_EMRC, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_CHAOSEMERALD2}, // S_CHAOSEMERALD1 + {SPR_EMRC, FF_FULLBRIGHT|FF_TRANSADD, 1, {NULL}, 0, 0, S_CHAOSEMERALD1}, // S_CHAOSEMERALD2 + {SPR_EMRC, FF_FULLBRIGHT|1, -1, {NULL}, 1, 0, S_NULL}, // S_CHAOSEMERALD_UNDER + + {SPR_ESPK, FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EMERALDSPARK2}, // S_EMERALDSPARK1 + {SPR_ESPK, FF_FULLBRIGHT|1, 3, {NULL}, 0, 0, S_EMERALDSPARK3}, // S_EMERALDSPARK2 + {SPR_ESPK, FF_FULLBRIGHT|2, 3, {NULL}, 0, 0, S_EMERALDSPARK4}, // S_EMERALDSPARK3 + {SPR_ESPK, FF_FULLBRIGHT|3, 3, {NULL}, 0, 0, S_EMERALDSPARK5}, // S_EMERALDSPARK4 + {SPR_ESPK, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_EMERALDSPARK6}, // S_EMERALDSPARK5 + {SPR_ESPK, FF_FULLBRIGHT|5, 3, {NULL}, 0, 0, S_EMERALDSPARK7}, // S_EMERALDSPARK6 + {SPR_ESPK, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL}, // S_EMERALDSPARK7 // Emerald hunt shards {SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1 @@ -3719,14 +3759,14 @@ state_t states[NUMSTATES] = {SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGCAPSULE // Orbiting Chaos Emeralds/Ideya for NiGHTS - {SPR_CEMG, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1}, // S_ORBITEM1 - {SPR_CEMG, FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2 - {SPR_CEMG, FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3 - {SPR_CEMG, FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4}, // S_ORBITEM4 - {SPR_CEMG, FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5}, // S_ORBITEM5 - {SPR_CEMG, FF_FULLBRIGHT|5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6 - {SPR_CEMG, FF_FULLBRIGHT|6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7 - {SPR_CEMG, FF_FULLBRIGHT|7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1}, // S_ORBITEM1 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4}, // S_ORBITEM4 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5}, // S_ORBITEM5 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7 + {SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8 {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA1}, // S_ORBIDYA1 {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA2}, // S_ORBIDYA2 {SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA3}, // S_ORBIDYA3 @@ -4369,9 +4409,47 @@ state_t states[NUMSTATES] = {SPR_SITR, 1, 5, {NULL}, 0, 0, S_SINKTRAIL3}, // S_SINKTRAIL2 {SPR_SITR, 2, 3, {NULL}, 0, 0, S_NULL}, // S_SINKTRAIL3 - {SPR_KBLN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_BATTLEBUMPER1}, // S_BATTLEBUMPER1 - {SPR_KBLN, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_BATTLEBUMPER2}, // S_BATTLEBUMPER2 - {SPR_KBLN, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_BATTLEBUMPER3}, // S_BATTLEBUMPER3 + {SPR_KBLN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER1 + {SPR_KBLN, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER2 + {SPR_KBLN, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER3 + + {SPR_BEXC, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA2}, // S_BATTLEBUMPER_EXCRYSTALA1 + {SPR_BEXC, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA3}, // S_BATTLEBUMPER_EXCRYSTALA2 + {SPR_BEXC, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA4}, // S_BATTLEBUMPER_EXCRYSTALA3 + {SPR_BEXC, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA1}, // S_BATTLEBUMPER_EXCRYSTALA4 + + {SPR_BEXC, FF_SEMIBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB2}, // S_BATTLEBUMPER_EXCRYSTALB1 + {SPR_BEXC, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB3}, // S_BATTLEBUMPER_EXCRYSTALB2 + {SPR_BEXC, FF_SEMIBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB4}, // S_BATTLEBUMPER_EXCRYSTALB3 + {SPR_BEXC, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB1}, // S_BATTLEBUMPER_EXCRYSTALB4 + + {SPR_BEXC, FF_SEMIBRIGHT|6, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC2}, // S_BATTLEBUMPER_EXCRYSTALC1 + {SPR_BEXC, FF_FULLBRIGHT|7, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC3}, // S_BATTLEBUMPER_EXCRYSTALC2 + {SPR_BEXC, FF_SEMIBRIGHT|6, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC4}, // S_BATTLEBUMPER_EXCRYSTALC3 + {SPR_BEXC, FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC1}, // S_BATTLEBUMPER_EXCRYSTALC4 + + {SPR_BEXS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLA2}, // S_BATTLEBUMPER_EXSHELLA1 + {SPR_BEXS, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLA1}, // S_BATTLEBUMPER_EXSHELLA2 + + {SPR_BEXS, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLB2}, // S_BATTLEBUMPER_EXSHELLB1 + {SPR_BEXS, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLB1}, // S_BATTLEBUMPER_EXSHELLB2 + + {SPR_BEXS, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLC2}, // S_BATTLEBUMPER_EXSHELLC1 + {SPR_BEXS, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLC1}, // S_BATTLEBUMPER_EXSHELLC2 + + {SPR_BDEB, FF_FULLBRIGHT|FF_ANIMATE, 84, {NULL}, 13, 6, S_BATTLEBUMPER_EXDEBRIS2}, // S_BATTLEBUMPER_EXDEBRIS1 + {SPR_BDEB, FF_FULLBRIGHT|13, 20, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER_EXDEBRIS2 + + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST2}, // S_BATTLEBUMPER_EXBLAST1 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS10, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST3}, // S_BATTLEBUMPER_EXBLAST2 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS20, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST4}, // S_BATTLEBUMPER_EXBLAST3 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS30, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST5}, // S_BATTLEBUMPER_EXBLAST4 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS40, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST6}, // S_BATTLEBUMPER_EXBLAST5 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS50, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST7}, // S_BATTLEBUMPER_EXBLAST6 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS60, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST8}, // S_BATTLEBUMPER_EXBLAST7 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS70, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST9}, // S_BATTLEBUMPER_EXBLAST8 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS80, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST10}, // S_BATTLEBUMPER_EXBLAST9 + {SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS90, 2, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER_EXBLAST10 {SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER {SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL2}, // S_DEZLASER_TRAIL1 @@ -5002,9 +5080,10 @@ state_t states[NUMSTATES] = {SPR_GRES, FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 2, 4, S_NULL}, // S_TIREGREASE - {SPR_OTFG, FF_FULLBRIGHT|FF_TRANS50, TICRATE, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEFOG - {SPR_OTFG, 2|FF_FULLBRIGHT|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEORB - {SPR_OTFG, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEBEAM + {SPR_OTBU, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_BULB1 + {SPR_OTBU, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_BULB2 + {SPR_OTLS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_LASER + {SPR_OTCP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_CENTER {SPR_CAPS, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE1 {SPR_CAPS, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE2 @@ -7933,35 +8012,35 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BLUESPHERE - 1706, // doomednum - S_BLUESPHERE, // spawnstate + -1, // doomednum + S_BLUESPHERE_SPAWN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound - MT_FLINGBLUESPHERE, // reactiontime + MT_FLINGBLUESPHERE, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_BLUESPHERESPARK, // deathstate + S_NULL, // deathstate S_NULL, // xdeathstate sfx_s3k65, // deathsound 38*FRACUNIT, // speed - 16*FRACUNIT, // radius - 24*FRACUNIT, // height + 48*FRACUNIT, // radius + 48*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags - S_BLUESPHEREBONUS // raisestate + MF_RUNSPAWNFUNC|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate }, { // MT_FLINGBLUESPHERE -1, // doomednum - S_BLUESPHERE, // spawnstate + S_BLUESPHERE_SPAWN, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -7972,7 +8051,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_BLUESPHERESPARK, // deathstate + S_NULL, // deathstate S_NULL, // xdeathstate sfx_s3k65, // deathsound 38*FRACUNIT, // speed @@ -7983,7 +8062,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // damage sfx_None, // activesound MF_SLIDEME|MF_SPECIAL, // flags - S_BLUESPHEREBONUS // raisestate + S_NULL // raisestate }, { // MT_BOMBSPHERE @@ -8175,9 +8254,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_EMERALD1 - 313, // doomednum - S_CEMG1, // spawnstate + { // MT_EMERALD + -1, // doomednum + S_CHAOSEMERALD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8188,22 +8267,23 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_SPRK1, // deathstate + S_NULL, // deathstate S_NULL, // xdeathstate - sfx_cgot, // deathsound - EMERALD1, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + sfx_s3k9c, // deathsound + 0, // speed + 72*FRACUNIT, // radius + 72*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_SPECIAL|MF_PICKUPFROMBELOW|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, - { // MT_EMERALD2 - 314, // doomednum - S_CEMG2, // spawnstate + + { // MT_EMERALDSPARK + -1, // doomednum + S_EMERALDSPARK1,// spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -8214,147 +8294,17 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_SPRK1, // deathstate + S_NULL, // deathstate S_NULL, // xdeathstate - sfx_cgot, // deathsound - EMERALD2, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags - S_NULL // raisestate - }, - { // MT_EMERALD3 - 315, // doomednum - S_CEMG3, // 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_SPRK1, // deathstate - S_NULL, // xdeathstate - sfx_cgot, // deathsound - EMERALD3, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags - S_NULL // raisestate - }, - { // MT_EMERALD4 - 316, // doomednum - S_CEMG4, // 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_SPRK1, // deathstate - S_NULL, // xdeathstate - sfx_cgot, // deathsound - EMERALD4, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags - S_NULL // raisestate - }, - { // MT_EMERALD5 - 317, // doomednum - S_CEMG5, // 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_SPRK1, // deathstate - S_NULL, // xdeathstate - sfx_cgot, // deathsound - EMERALD5, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags - S_NULL // raisestate - }, - { // MT_EMERALD6 - 318, // doomednum - S_CEMG6, // 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_SPRK1, // deathstate - S_NULL, // xdeathstate - sfx_cgot, // deathsound - EMERALD6, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags - S_NULL // raisestate - }, - { // MT_EMERALD7 - 319, // doomednum - S_CEMG7, // 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_SPRK1, // deathstate - S_NULL, // xdeathstate - sfx_cgot, // deathsound - EMERALD7, // speed - 16*FRACUNIT, // radius - 32*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOGRAVITY|MF_SPECIAL, // flags + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -8412,33 +8362,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_FLINGEMERALD - -1, // doomednum - S_CEMG1, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 0, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_SPRK1, // deathstate - S_NULL, // xdeathstate - sfx_cgot, // deathsound - 60*FRACUNIT, // speed - 16*FRACUNIT, // radius - 48*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL, // flags - S_NULL // raisestate - }, - { // MT_FAN 540, // doomednum S_FAN, // spawnstate @@ -18654,22 +18577,22 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_RAIN1, // spawnstate 1000, // spawnhealth S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime + sfx_rainin, // seesound + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_NULL, // deathstate + S_SPLASH1, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound -72*FRACUNIT, // speed 1*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset - 4, // mass + 80, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags @@ -18682,7 +18605,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound - 8, // reactiontime + 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 0, // painchance @@ -18696,8 +18619,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 4*FRACUNIT, // radius 4*FRACUNIT, // height 0, // display offset - 4, // mass - 0, // damage + 0, // mass + 2, // damage sfx_None, // activesound MF_NOBLOCKMAP, // flags S_NULL // raisestate @@ -19083,7 +19006,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_GOTEMERALD -1, // doomednum - S_CEMG1, // spawnstate + S_CHAOSEMERALD1, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -22918,13 +22841,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_itpick, // deathsound 0, // speed - 32*FRACUNIT, // radius - 32*FRACUNIT, // height + 48*FRACUNIT, // radius + 64*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_DONTENCOREMAP, // flags + MF_SLIDEME|MF_SPECIAL|MF_PICKUPFROMBELOW|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -24237,7 +24160,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_NULL, // deathstate + S_BATTLEBUMPER1, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound 4*FRACUNIT, // speed @@ -24251,6 +24174,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BATTLEBUMPER_DEBRIS + -1, // doomednum + S_BATTLEBUMPER_EXDEBRIS1,// spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_BATTLEBUMPER_BLAST + -1, // doomednum + S_BATTLEBUMPER_EXBLAST1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_DEZLASER -1, // doomednum S_DEZLASER, // spawnstate @@ -28439,9 +28416,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_OVERTIMEFOG + { // MT_OVERTIME_PARTICLE -1, // doomednum - S_OVERTIMEFOG, // spawnstate + S_NULL, // spawnstate 1000, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -28457,8 +28434,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 0, // speed 16<kartstuff[k_position] == 1); +#else UINT8 i; if (!(gametyperules & GTR_WANTED)) @@ -54,28 +57,26 @@ boolean K_IsPlayerWanted(player_t *player) return true; } return false; +#endif } void K_CalculateBattleWanted(void) { - UINT8 numingame = 0, numplaying = 0, numwanted = 0; - SINT8 bestbumperplayer = -1, bestbumper = -1; + UINT8 numingame = 0, numwanted = 0; SINT8 camppos[MAXPLAYERS]; // who is the biggest camper UINT8 ties = 0, nextcamppos = 0; - boolean setbumper = false; UINT8 i, j; +#if 0 if (!(gametyperules & GTR_WANTED)) +#endif { - for (i = 0; i < 4; i++) - battlewanted[i] = -1; + memset(battlewanted, -1, sizeof (battlewanted)); return; } wantedcalcdelay = wantedfrequency; - - for (i = 0; i < MAXPLAYERS; i++) - camppos[i] = -1; // initialize + memset(camppos, -1, sizeof (camppos)); // initialize for (i = 0; i < MAXPLAYERS; i++) { @@ -87,33 +88,38 @@ void K_CalculateBattleWanted(void) if (players[i].exiting) // We're done, don't calculate. return; - numplaying++; - - if (players[i].kartstuff[k_bumper] <= 0) // Not alive, so don't do anything else + if (players[i].bumpers <= 0) // Not alive, so don't do anything else continue; numingame++; - if (bestbumper == -1 || players[i].kartstuff[k_bumper] > bestbumper) - { - bestbumper = players[i].kartstuff[k_bumper]; - bestbumperplayer = i; - } - else if (players[i].kartstuff[k_bumper] == bestbumper) - bestbumperplayer = -1; // Tie, no one has best bumper. - for (j = 0; j < MAXPLAYERS; j++) { if (!playeringame[j] || players[j].spectator) continue; - if (players[j].kartstuff[k_bumper] <= 0) + + if (players[j].bumpers <= 0) continue; + if (j == i) continue; - if (players[j].kartstuff[k_wanted] == players[i].kartstuff[k_wanted] && players[j].marescore > players[i].marescore) + + if (K_NumEmeralds(&players[j]) > K_NumEmeralds(&players[i])) + { position++; + } + else if (players[j].bumpers > players[i].bumpers) + { + position++; + } + else if (players[j].marescore > players[i].marescore) + { + position++; + } else if (players[j].kartstuff[k_wanted] > players[i].kartstuff[k_wanted]) + { position++; + } } position--; // Make zero based @@ -124,7 +130,7 @@ void K_CalculateBattleWanted(void) camppos[position] = i; } - if (numplaying <= 2 || (numingame <= 2 && bestbumper == 1)) // In 1v1s then there's no need for WANTED. In bigger netgames, don't show anyone as WANTED when they're equally matched. + if (numingame <= 2) // In 1v1s then there's no need for WANTED. numwanted = 0; else numwanted = min(4, 1 + ((numingame-2) / 4)); @@ -132,19 +138,11 @@ void K_CalculateBattleWanted(void) for (i = 0; i < 4; i++) { if (i+1 > numwanted) // Not enough players for this slot to be wanted! - battlewanted[i] = -1; - else if (bestbumperplayer != -1 && !setbumper) // If there's a player who has an untied bumper lead over everyone else, they are the first to be wanted. { - battlewanted[i] = bestbumperplayer; - setbumper = true; // Don't set twice + battlewanted[i] = -1; } else { - // Don't accidentally set the same player, if the bestbumperplayer is also a huge camper. - while (bestbumperplayer != -1 && camppos[nextcamppos] != -1 - && bestbumperplayer == camppos[nextcamppos]) - nextcamppos++; - // Do not add *any* more people if there's too many times that are tied with others. // This could theoretically happen very easily if people don't hit each other for a while after the start of a match. // (I will be sincerely impressed if more than 2 people tie after people start hitting each other though) @@ -230,7 +228,7 @@ void K_CheckBumpers(void) numingame++; winnerscoreadd += players[i].marescore; - if (players[i].kartstuff[k_bumper] <= 0) // if you don't have any bumpers, you're probably not a winner + if (players[i].bumpers <= 0) // if you don't have any bumpers, you're probably not a winner { nobumpers = true; continue; @@ -277,125 +275,411 @@ void K_CheckBumpers(void) P_DoPlayerExit(&players[i]); } -#define MAXPLANESPERSECTOR (MAXFFLOORS+1)*2 - -static void K_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjtype_t type, boolean ceiling) +void K_CheckEmeralds(player_t *player) { UINT8 i; - fixed_t flatz[MAXPLANESPERSECTOR]; - boolean flip[MAXPLANESPERSECTOR]; - UINT8 numflats = 0; - mobj_t *mo; - subsector_t *ss = R_PointInSubsectorOrNull(x, y); - sector_t *sec; - if (!ss) + if (!ALLCHAOSEMERALDS(player->powers[pw_emeralds])) + { return; - sec = ss->sector; - - // convoluted stuff JUST to get all of the planes we need to draw orbs on :V - - for (i = 0; i < MAXPLANESPERSECTOR; i++) - flip[i] = false; - - if (sec->floorpic != skyflatnum) - { - flatz[numflats] = P_GetZAt(sec->f_slope, x, y, sec->floorheight); - numflats++; - } - if (sec->ceilingpic != skyflatnum && ceiling) - { - flatz[numflats] = P_GetZAt(sec->c_slope, x, y, sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale); - flip[numflats] = true; - numflats++; } - if (sec->ffloors) + player->marescore++; // lol + + for (i = 0; i < MAXPLAYERS; i++) { - ffloor_t *rover; - for (rover = sec->ffloors; rover; rover = rover->next) + if (!playeringame[i] || players[i].spectator) { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) - continue; - if (*rover->toppic != skyflatnum) - { - flatz[numflats] = P_GetZAt(*rover->t_slope, x, y, *rover->topheight); - numflats++; - } - if (*rover->bottompic != skyflatnum && ceiling) - { - flatz[numflats] = P_GetZAt(*rover->b_slope, x, y, *rover->bottomheight); - flip[numflats] = true; - numflats++; - } + continue; } + + if (&players[i] == player) + { + continue; + } + + players[i].bumpers = 0; } - if (numflats <= 0) // no flats - return; + K_CheckBumpers(); +} - for (i = 0; i < numflats; i++) +mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT32 emeraldType) +{ + boolean validEmerald = true; + mobj_t *emerald = P_SpawnMobj(x, y, z, MT_EMERALD); + mobj_t *overlay; + + P_Thrust(emerald, + FixedAngle(P_RandomFixed() * 180) + angle, + 32 * mapobjectscale); + + emerald->momz = flip * 24 * mapobjectscale; + if (emerald->eflags & MFE_UNDERWATER) + emerald->momz = (117 * emerald->momz) / 200; + + emerald->threshold = 10; + + switch (emeraldType) { - mo = P_SpawnMobj(x, y, flatz[i], type); + case EMERALD_CHAOS1: + emerald->color = SKINCOLOR_CHAOSEMERALD1; + break; + case EMERALD_CHAOS2: + emerald->color = SKINCOLOR_CHAOSEMERALD2; + break; + case EMERALD_CHAOS3: + emerald->color = SKINCOLOR_CHAOSEMERALD3; + break; + case EMERALD_CHAOS4: + emerald->color = SKINCOLOR_CHAOSEMERALD4; + break; + case EMERALD_CHAOS5: + emerald->color = SKINCOLOR_CHAOSEMERALD5; + break; + case EMERALD_CHAOS6: + emerald->color = SKINCOLOR_CHAOSEMERALD6; + break; + case EMERALD_CHAOS7: + emerald->color = SKINCOLOR_CHAOSEMERALD7; + break; + default: + CONS_Printf("Invalid emerald type %d\n", emeraldType); + validEmerald = false; + break; + } - // Lastly, if this can see the skybox mobj, then... we just wasted our time :V - if (skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0])) + if (validEmerald == true) + { + emerald->extravalue1 = emeraldType; + } + + overlay = P_SpawnMobjFromMobj(emerald, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, emerald); + P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER); + overlay->color = emerald->color; + + return emerald; +} + +void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType) +{ + UINT8 i; + SINT8 flip = P_MobjFlip(player->mo); + + for (i = 0; i < 14; i++) + { + UINT32 emeraldFlag = (1 << i); + + if ((player->powers[pw_emeralds] & emeraldFlag) && (emeraldFlag & emeraldType)) { - const fixed_t sbz = skyboxmo[0]->z; - fixed_t checkz = sec->floorheight; + mobj_t *emerald = K_SpawnChaosEmerald(player->mo->x, player->mo->y, player->mo->z, player->mo->angle - ANGLE_90, flip, emeraldFlag); + P_SetTarget(&emerald->target, player->mo); - while (checkz < sec->ceilingheight) - { - P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, checkz); - if (P_CheckSight(skyboxmo[0], mo)) - { - P_RemoveMobj(mo); - break; - } - else - checkz += 32*mapobjectscale; - } - - P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, sbz); - - if (P_MobjWasRemoved(mo)) - continue; - } - - P_SetScale(mo, scale); - - if (flip[i]) - { - mo->flags2 |= MF2_OBJECTFLIP; - mo->eflags |= MFE_VERTICALFLIP; - } - - switch(type) - { - case MT_OVERTIMEFOG: - mo->destscale = 8*mo->scale; - mo->momz = P_RandomRange(1,8)*mo->scale; - break; - case MT_OVERTIMEORB: - //mo->destscale = mo->scale/4; - mo->frame += ((leveltime/4) % 8); - /*if (battleovertime.enabled < 10*TICRATE) - mo->drawflags |= MFD_SHADOW;*/ - mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90; - mo->z += P_RandomRange(0,48) * mo->scale; - break; - default: - break; + player->powers[pw_emeralds] &= ~emeraldFlag; } } } -#undef MAXPLANESPERSECTOR +UINT8 K_NumEmeralds(player_t *player) +{ + UINT8 i; + UINT8 num = 0; + + for (i = 0; i < 14; i++) + { + UINT32 emeraldFlag = (1 << i); + + if (player->powers[pw_emeralds] & emeraldFlag) + { + num++; + } + } + + return num; +} + +void K_RunPaperItemSpawners(void) +{ + const boolean overtime = (battleovertime.enabled >= 10*TICRATE); + tic_t interval = 8*TICRATE; + + UINT32 emeraldsSpawned = 0; + UINT32 firstUnspawnedEmerald = 0; + + thinker_t *th; + mobj_t *mo; + + UINT8 pcount = 0; + INT16 i; + + if (leveltime < starttime) + { + // Round hasn't started yet! + return; + } + + if (overtime == true) + { + if (battleovertime.radius < 512*mapobjectscale) + { + // Barrier has closed in too much + return; + } + + // Double frequency of items + interval /= 2; + } + + if (((leveltime - starttime) % interval) != 0) + { + return; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + { + continue; + } + + emeraldsSpawned |= players[i].powers[pw_emeralds]; + + if ((players[i].exiting > 0 || players[i].eliminated) + || ((gametyperules & GTR_BUMPERS) && players[i].bumpers <= 0)) + { + continue; + } + + pcount++; + } + + if (overtime == true) + { + SINT8 flip = 1; + + // Just find emeralds, no paper spots + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo = (mobj_t *)th; + + if (mo->type == MT_EMERALD) + { + emeraldsSpawned |= mo->extravalue1; + } + } + + for (i = 0; i < 7; i++) + { + UINT32 emeraldFlag = (1 << i); + + if (!(emeraldsSpawned & emeraldFlag)) + { + firstUnspawnedEmerald = emeraldFlag; + break; + } + } + + if (firstUnspawnedEmerald != 0) + { + K_SpawnChaosEmerald( + battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip), + FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip, + firstUnspawnedEmerald + ); + } + else + { + K_CreatePaperItem( + battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip), + FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip, + 0, 0 + ); + } + } + else + { + if (pcount > 0) + { +#define MAXITEM 64 + UINT8 item = 0; + mobj_t *spotList[MAXITEM]; + boolean spotUsed[MAXITEM]; + + INT16 starti = 0; + + memset(spotUsed, false, sizeof(spotUsed)); + + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo = (mobj_t *)th; + + if (mo->type == MT_PAPERITEMSPOT) + { + if (item >= MAXITEM) + continue; + + spotList[item] = mo; + item++; + } + else if (mo->type == MT_EMERALD) + { + emeraldsSpawned |= mo->extravalue1; + } + } + + if (item <= 0) + { + return; + } + + for (i = 0; i < 7; i++) + { + UINT32 emeraldFlag = (1 << i); + + if (!(emeraldsSpawned & emeraldFlag)) + { + firstUnspawnedEmerald = emeraldFlag; + starti = -1; + break; + } + } + + for (i = starti; i < min(item + starti, pcount); i++) + { + UINT8 r = P_RandomKey(item); + UINT8 recursion = 0; + mobj_t *drop = NULL; + SINT8 flip = 1; + + while (spotUsed[r] == true) + { + r = P_RandomKey(item); + + if ((recursion++) > MAXITEM) + { + // roll with it anyway I guess + break; + } + } + + flip = P_MobjFlip(spotList[r]); + + // When -1, we're spawning a Chaos Emerald. + if (i == -1) + { + drop = K_SpawnChaosEmerald( + spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip), + FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip, + firstUnspawnedEmerald + ); + } + else + { + drop = K_CreatePaperItem( + spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip), + FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip, + 0, 0 + ); + } + + K_FlipFromObject(drop, spotList[r]); + spotUsed[r] = true; + } + } + } +} + +static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale) +{ + UINT8 i, j; + + for (i = 0; i <= r_splitscreen; i++) + { + player_t *player = &players[displayplayers[i]]; + fixed_t zpos; + SINT8 flip; + + if (player == NULL || player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + continue; + } + + if (player->mo->eflags & MFE_VERTICALFLIP) + { + zpos = player->mo->z + player->mo->height; + } + else + { + zpos = player->mo->z; + } + + flip = P_MobjFlip(player->mo); + + for (j = 0; j < 3; j++) + { + mobj_t *mo = P_SpawnMobj(x, y, zpos, MT_OVERTIME_PARTICLE); + + if (player->mo->eflags & MFE_VERTICALFLIP) + { + mo->flags2 |= MF2_OBJECTFLIP; + mo->eflags |= MFE_VERTICALFLIP; + } + + mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90; + mo->drawflags |= (MFD_DONTDRAW & ~(K_GetPlayerDontDrawFlag(player))); + + P_SetScale(mo, scale); + + switch (j) + { + case 0: + P_SetMobjState(mo, S_OVERTIME_BULB1); + + if (leveltime & 1) + mo->frame += 1; + + //P_SetScale(mo, mapobjectscale); + zpos += 35 * mo->scale * flip; + break; + case 1: + P_SetMobjState(mo, S_OVERTIME_LASER); + + if (leveltime & 1) + mo->frame += 3; + else + mo->frame += (leveltime / 2) % 3; + + //P_SetScale(mo, scale); + zpos += 346 * mo->scale * flip; + + if (battleovertime.enabled < 10*TICRATE) + mo->drawflags |= MFD_TRANS50; + break; + case 2: + P_SetMobjState(mo, S_OVERTIME_BULB2); + + if (leveltime & 1) + mo->frame += 1; + + //P_SetScale(mo, mapobjectscale); + break; + default: + I_Error("Bruh moment has occured\n"); + return; + } + } + } +} void K_RunBattleOvertime(void) { - UINT16 i, j; - if (battleovertime.enabled < 10*TICRATE) { battleovertime.enabled++; @@ -404,70 +688,37 @@ void K_RunBattleOvertime(void) if (battleovertime.enabled == 10*TICRATE) S_StartSound(NULL, sfx_kc40); } - else + else if (battleovertime.radius > 0) { - if (battleovertime.radius > battleovertime.minradius) - battleovertime.radius -= mapobjectscale; + if (battleovertime.radius > 2*mapobjectscale) + battleovertime.radius -= 2*mapobjectscale; else - battleovertime.radius = battleovertime.minradius; + battleovertime.radius = 0; } - if (leveltime & 1) + if (battleovertime.radius > 0) { - UINT8 transparency = tr_trans50; + const fixed_t pi = (22 * FRACUNIT) / 7; // loose approximation, this doesn't need to be incredibly precise + const INT32 orbs = 32; + const angle_t angoff = ANGLE_MAX / orbs; + const UINT8 spriteSpacing = 128; - if (!splitscreen && players[displayplayers[0]].mo) - { - INT32 dist = P_AproxDistance(battleovertime.x-players[displayplayers[0]].mo->x, battleovertime.y-players[displayplayers[0]].mo->y); - transparency = max(0, NUMTRANSMAPS - ((256 + (dist>>FRACBITS)) / 256)); - } + fixed_t circumference = FixedMul(pi, battleovertime.radius * 2); + fixed_t scale = max(circumference / spriteSpacing / orbs, mapobjectscale); - if (transparency < NUMTRANSMAPS) - { - mobj_t *beam = P_SpawnMobj(battleovertime.x, battleovertime.y, battleovertime.z + (mobjinfo[MT_RANDOMITEM].height/2), MT_OVERTIMEBEAM); - P_SetScale(beam, beam->scale*2); - if (transparency > 0) - beam->frame |= transparency<>FRACBITS / 2));*/ - - for (i = 0; i < 16; i++) - { - j = 0; - while (j < 32) // max attempts - { - fixed_t x = battleovertime.x + ((P_RandomRange(-64,64) * 128)<player, 2)) return true; - if ((gametyperules & GTR_BUMPERS) && t2->player->kartstuff[k_bumper] <= 0) + if ((gametyperules & GTR_BUMPERS) && t2->player->bumpers <= 0) { - if (t2->player->kartstuff[k_comebackmode] || t2->player->kartstuff[k_comebacktimer]) +#ifdef OTHERKARMAMODES + if (t2->player->kartstuff[k_comebackmode] || t2->player->karmadelay) return true; t2->player->kartstuff[k_comebackmode] = 2; +#else + return true; +#endif } else { @@ -238,7 +242,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) if (t1->target && t1->target->player) { - if ((gametyperules & GTR_CIRCUIT) || t1->target->player->kartstuff[k_bumper] > 0) + if ((gametyperules & GTR_CIRCUIT) || t1->target->player->bumpers > 0) t2->player->kartstuff[k_eggmanblame] = t1->target->player-players; else t2->player->kartstuff[k_eggmanblame] = t2->player-players; diff --git a/src/k_hud.c b/src/k_hud.c index 63ecce767..55f84ca4c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -50,6 +50,7 @@ static patch_t *kp_bumperstickerwide; static patch_t *kp_capsulesticker; static patch_t *kp_capsulestickerwide; static patch_t *kp_karmasticker; +static patch_t *kp_spheresticker; static patch_t *kp_splitkarmabomb; static patch_t *kp_timeoutsticker; @@ -87,6 +88,9 @@ static patch_t *kp_rankbumper; static patch_t *kp_tinybumper[2]; static patch_t *kp_ranknobumpers; static patch_t *kp_rankcapsule; +static patch_t *kp_rankemerald; +static patch_t *kp_rankemeraldflash; +static patch_t *kp_rankemeraldback; static patch_t *kp_battlewin; static patch_t *kp_battlecool; @@ -175,6 +179,7 @@ void K_LoadKartHUDGraphics(void) kp_capsulesticker = W_CachePatchName("K_STCAPN", PU_HUDGFX); kp_capsulestickerwide = W_CachePatchName("K_STCAPW", PU_HUDGFX); kp_karmasticker = W_CachePatchName("K_STKARM", PU_HUDGFX); + kp_spheresticker = W_CachePatchName("K_STBSMT", PU_HUDGFX); kp_splitkarmabomb = W_CachePatchName("K_SPTKRM", PU_HUDGFX); kp_timeoutsticker = W_CachePatchName("K_STTOUT", PU_HUDGFX); @@ -349,6 +354,9 @@ void K_LoadKartHUDGraphics(void) kp_tinybumper[1] = W_CachePatchName("K_BLNB", PU_HUDGFX); kp_ranknobumpers = W_CachePatchName("K_NOBLNS", PU_HUDGFX); kp_rankcapsule = W_CachePatchName("K_CAPICO", PU_HUDGFX); + kp_rankemerald = W_CachePatchName("K_EMERC", PU_HUDGFX); + kp_rankemeraldflash = W_CachePatchName("K_EMERW", PU_HUDGFX); + kp_rankemeraldback = W_CachePatchName("K_EMERBK", PU_HUDGFX); // Battle graphics kp_battlewin = W_CachePatchName("K_BWIN", PU_HUDGFX); @@ -734,11 +742,12 @@ void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du if (options & V_SLIDEIN) { - tic_t length = TICRATE/2; + const tic_t length = TICRATE/2; + const tic_t end = (lt_endtime + length); - if (leveltime < introtime + length) + if (lt_ticker < end) { - INT32 offset = screenwidth - (((leveltime - introtime) * screenwidth) / length); + INT32 offset = screenwidth - ((lt_exitticker * screenwidth) / length); boolean slidefromright = false; if (r_splitscreen > 1) @@ -1525,7 +1534,7 @@ static boolean K_drawKartPositionFaces(void) INT32 i, j, ranklines, strank = -1; boolean completed[MAXPLAYERS]; INT32 rankplayer[MAXPLAYERS]; - INT32 bumperx, numplayersingame = 0; + INT32 bumperx, emeraldx, numplayersingame = 0; UINT8 *colormap; ranklines = 0; @@ -1606,6 +1615,7 @@ static boolean K_drawKartPositionFaces(void) if (!players[rankplayer[i]].mo) continue; bumperx = FACE_X+19; + emeraldx = FACE_X+16; if (players[rankplayer[i]].mo->color) { @@ -1619,22 +1629,35 @@ static boolean K_drawKartPositionFaces(void) if (LUA_HudEnabled(hud_battlebumpers)) { - if (gametype == GT_BATTLE && players[rankplayer[i]].kartstuff[k_bumper] > 0) + if ((gametyperules & GTR_BUMPERS) && players[rankplayer[i]].bumpers > 0) { V_DrawMappedPatch(bumperx-2, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_tinybumper[0], colormap); - for (j = 1; j < players[rankplayer[i]].kartstuff[k_bumper]; j++) + for (j = 1; j < players[rankplayer[i]].bumpers; j++) { bumperx += 5; V_DrawMappedPatch(bumperx, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_tinybumper[1], colormap); } } - } // A new level of stupidity: checking if lua is enabled to close a bracket. :Fascinating: + } + } + + for (j = 0; j < 7; j++) + { + UINT32 emeraldFlag = (1 << j); + UINT16 emeraldColor = SKINCOLOR_CHAOSEMERALD1 + j; + + if (players[rankplayer[i]].powers[pw_emeralds] & emeraldFlag) + { + colormap = R_GetTranslationColormap(TC_DEFAULT, emeraldColor, GTC_CACHE); + V_DrawMappedPatch(emeraldx, Y+7, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_rankemerald, colormap); + emeraldx += 7; + } } if (i == strank) V_DrawScaledPatch(FACE_X, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_facehighlight[(leveltime / 4) % 8]); - if (gametype == GT_BATTLE && players[rankplayer[i]].kartstuff[k_bumper] <= 0) + if (gametype == GT_BATTLE && players[rankplayer[i]].bumpers <= 0) V_DrawScaledPatch(FACE_X-4, Y-3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_ranknobumpers); else { @@ -1651,6 +1674,59 @@ static boolean K_drawKartPositionFaces(void) return false; } +static void K_drawKartEmeralds(void) +{ + static const INT32 emeraldOffsets[7][2] = { + {34, 0}, + {25, 8}, + {43, 8}, + {16, 0}, + {52, 0}, + {7, 8}, + {61, 8} + }; + + const INT32 startx = BASEVIDWIDTH - 77 - 8; + const INT32 starty = BASEVIDHEIGHT - 29 - 8; + + INT32 i; + + V_DrawScaledPatch(startx, starty, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT, kp_rankemeraldback); + + for (i = 0; i < 7; i++) + { + UINT32 emeraldFlag = (1 << i); + UINT16 emeraldColor = SKINCOLOR_CHAOSEMERALD1 + i; + + if (stplyr->powers[pw_emeralds] & emeraldFlag) + { + boolean whiteFlash = (leveltime & 1); + UINT8 *colormap; + + if (i & 1) + { + whiteFlash = !whiteFlash; + } + + colormap = R_GetTranslationColormap(TC_DEFAULT, emeraldColor, GTC_CACHE); + V_DrawMappedPatch( + startx + emeraldOffsets[i][0], starty + emeraldOffsets[i][1], + V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT, + kp_rankemerald, colormap + ); + + if (whiteFlash == true) + { + V_DrawScaledPatch( + startx + emeraldOffsets[i][0], starty + emeraldOffsets[i][1], + V_HUDTRANSHALF|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT, + kp_rankemeraldflash + ); + } + } + } +} + // // HU_DrawTabRankings -- moved here to take advantage of kart stuff! // @@ -1732,11 +1808,11 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); V_DrawMappedPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin][FACE_RANK], colormap); - /*if (gametype == GT_BATTLE && players[tab[i].num].kartstuff[k_bumper] > 0) -- not enough space for this + /*if (gametype == GT_BATTLE && players[tab[i].num].bumpers > 0) -- not enough space for this { INT32 bumperx = x+19; V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumper[0], colormap); - for (j = 1; j < players[tab[i].num].kartstuff[k_bumper]; j++) + for (j = 1; j < players[tab[i].num].bumpers; j++) { bumperx += 5; V_DrawMappedPatch(bumperx, y-4, 0, kp_tinybumper[1], colormap); @@ -1747,7 +1823,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN if (tab[i].num == whiteplayer) V_DrawScaledPatch(x, y-4, 0, kp_facehighlight[(leveltime / 4) % 8]); - if (gametype == GT_BATTLE && players[tab[i].num].kartstuff[k_bumper] <= 0) + if (gametype == GT_BATTLE && players[tab[i].num].bumpers <= 0) V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers); else { @@ -1915,11 +1991,7 @@ static void K_drawKartLapsAndRings(void) { // Laps V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_lapsticker); - - if (stplyr->exiting) - V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, "FIN"); - else - V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->laps, cv_numlaps.value)); + V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, cv_numlaps.value), cv_numlaps.value)); // Rings if (!uselives) @@ -1963,7 +2035,7 @@ static void K_drawKartSpeedometer(void) UINT8 labeln = 0; UINT8 numbers[3]; INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN; - UINT8 battleoffset = 0; + INT32 battleoffset = 0; if (!stplyr->exiting) // Keep the same speed value as when you crossed the finish line! { @@ -1998,7 +2070,7 @@ static void K_drawKartSpeedometer(void) numbers[2] = (convSpeed % 10); if (gametype == GT_BATTLE) - battleoffset = 8; + battleoffset = -4; V_DrawScaledPatch(LAPS_X, LAPS_Y-25 + battleoffset, V_HUDTRANS|V_SLIDEIN|splitflags, kp_speedometersticker); V_DrawScaledPatch(LAPS_X+7, LAPS_Y-25 + battleoffset, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[numbers[0]]); @@ -2007,6 +2079,36 @@ static void K_drawKartSpeedometer(void) V_DrawScaledPatch(LAPS_X+29, LAPS_Y-25 + battleoffset, V_HUDTRANS|V_SLIDEIN|splitflags, kp_speedometerlabel[labeln]); } +static void K_drawBlueSphereMeter(void) +{ + const UINT8 maxBars = 4; + const UINT8 segColors[] = {73, 64, 52, 54, 55, 35, 34, 33, 202, 180, 181, 182, 164, 165, 166, 153, 152}; + const UINT8 sphere = max(min(stplyr->spheres, 40), 0); + + UINT8 numBars = min((sphere / 10), maxBars); + UINT8 colorIndex = (sphere * sizeof(segColors)) / (40 + 1); + INT32 x = LAPS_X + 25; + UINT8 i; + + V_DrawScaledPatch(LAPS_X, LAPS_Y - 22, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN, kp_spheresticker); + + for (i = 0; i <= numBars; i++) + { + UINT8 segLen = 10; + + if (i == numBars) + { + segLen = (sphere % 10); + } + + V_DrawFill(x, LAPS_Y - 16, segLen, 3, segColors[max(colorIndex-1, 0)] | V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN); + V_DrawFill(x, LAPS_Y - 15, segLen, 1, segColors[max(colorIndex-2, 0)] | V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN); + V_DrawFill(x, LAPS_Y - 13, segLen, 3, segColors[colorIndex] | V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN); + + x += 15; + } +} + static void K_drawKartBumpersOrKarma(void) { UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, GTC_CACHE); @@ -2070,37 +2172,28 @@ static void K_drawKartBumpersOrKarma(void) } else { - if (stplyr->kartstuff[k_bumper] <= 0) + INT32 maxbumper = K_StartingBumperCount(); + V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap); + + if (stplyr->bumpers > 9 || maxbumper > 9) { - V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_splitkarmabomb, colormap); - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->kartstuff[k_comebackpoints]) % 10]); - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[2]); + UINT8 ln[2]; + ln[0] = (stplyr->bumpers / 10 % 10); + ln[1] = (stplyr->bumpers % 10); + + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); + V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); + + ln[0] = ((abs(maxbumper) / 10) % 10); + ln[1] = (abs(maxbumper) % 10); + + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); + V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); } else { - INT32 maxbumper = K_StartingBumperCount(); - V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap); - - if (stplyr->kartstuff[k_bumper] > 9 || maxbumper > 9) - { - UINT8 ln[2]; - ln[0] = ((abs(stplyr->kartstuff[k_bumper]) / 10) % 10); - ln[1] = (abs(stplyr->kartstuff[k_bumper]) % 10); - - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); - V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); - - ln[0] = ((abs(maxbumper) / 10) % 10); - ln[1] = (abs(maxbumper) % 10); - - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]); - V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]); - } - else - { - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->kartstuff[k_bumper]) % 10]); - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(maxbumper) % 10]); - } + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->bumpers) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(maxbumper) % 10]); } } } @@ -2116,22 +2209,14 @@ static void K_drawKartBumpersOrKarma(void) } else { - if (stplyr->kartstuff[k_bumper] <= 0) - { - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_karmasticker, colormap); - V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints])); - } + INT32 maxbumper = K_StartingBumperCount(); + + if (stplyr->bumpers > 9 && maxbumper > 9) + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap); else - { - INT32 maxbumper = K_StartingBumperCount(); + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap); - if (stplyr->kartstuff[k_bumper] > 9 && maxbumper > 9) - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap); - else - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap); - - V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], maxbumper)); - } + V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->bumpers, maxbumper)); } } } @@ -2142,6 +2227,9 @@ static void K_drawKartWanted(void) UINT8 *colormap = NULL; INT32 basex = 0, basey = 0; + if (!splitscreen) + return; + if (stplyr != &players[displayplayers[0]]) return; @@ -2554,6 +2642,18 @@ static void K_drawKartNameTags(void) continue; } + if (ntplayer->mo->drawflags & K_GetPlayerDontDrawFlag(stplyr)) + { + // Invisible on this screen + continue; + } + + if ((gametyperules & GTR_BUMPERS) && (ntplayer->bumpers <= 0)) + { + // Dead in Battle + continue; + } + if (!P_CheckSight(stplyr->mo, ntplayer->mo)) { // Can't see @@ -2876,7 +2976,7 @@ static void K_drawKartMinimap(void) if (i != displayplayers[0] || r_splitscreen) { - if (gametype == GT_BATTLE && players[i].kartstuff[k_bumper] <= 0) + if (gametype == GT_BATTLE && players[i].bumpers <= 0) continue; if (players[i].kartstuff[k_hyudorotimer] > 0) @@ -3312,9 +3412,9 @@ static void K_drawBattleFullscreen(void) else K_drawKartFinish(); } - else if (stplyr->kartstuff[k_bumper] <= 0 && stplyr->kartstuff[k_comebacktimer] && comeback && !stplyr->spectator && drawcomebacktimer) + else if (stplyr->bumpers <= 0 && stplyr->karmadelay && comeback && !stplyr->spectator && drawcomebacktimer) { - UINT16 t = stplyr->kartstuff[k_comebacktimer]/(10*TICRATE); + UINT16 t = stplyr->karmadelay/(10*TICRATE); INT32 txoff, adjust = (r_splitscreen > 1) ? 4 : 6; // normal string is 8, kart string is 12, half of that for ease INT32 ty = (BASEVIDHEIGHT/2)+66; @@ -3344,11 +3444,11 @@ static void K_drawBattleFullscreen(void) V_DrawFixedPatch(x< 1) - V_DrawString(x-txoff, ty, 0, va("%d", stplyr->kartstuff[k_comebacktimer]/TICRATE)); + V_DrawString(x-txoff, ty, 0, va("%d", stplyr->karmadelay/TICRATE)); else { V_DrawFixedPatch(x<kartstuff[k_comebacktimer]/TICRATE)); + V_DrawKartString(x-txoff, ty, 0, va("%d", stplyr->karmadelay/TICRATE)); } } @@ -3535,7 +3635,7 @@ static void K_drawInput(void) #define BUTTH 11 #define drawbutt(xoffs, butt, symb)\ - if (stplyr->cmd.buttons & butt)\ + if (!stplyr->exiting && (cmd->buttons & butt))\ {\ offs = 2;\ col = accent1;\ @@ -3561,7 +3661,7 @@ static void K_drawInput(void) y -= 1; - if (!cmd->turning) // no turn + if (stplyr->exiting || !cmd->turning) // no turn target = 0; else // turning of multiple strengths! { @@ -3770,8 +3870,8 @@ static void K_drawDistributionDebugger(void) if (!playeringame[i] || players[i].spectator) continue; pingame++; - if (players[i].kartstuff[k_bumper] > bestbumper) - bestbumper = players[i].kartstuff[k_bumper]; + if (players[i].bumpers > bestbumper) + bestbumper = players[i].bumpers; } // lovely double loop...... @@ -3892,11 +3992,12 @@ void K_drawKartHUD(void) return; } - battlefullscreen = ((gametype == GT_BATTLE) + battlefullscreen = ((gametyperules & (GTR_BUMPERS|GTR_KARMA)) == (GTR_BUMPERS|GTR_KARMA) && (stplyr->exiting - || (stplyr->kartstuff[k_bumper] <= 0 - && stplyr->kartstuff[k_comebacktimer] - && comeback + || (stplyr->bumpers <= 0 + && stplyr->karmadelay > 0 + && stplyr->eliminated == false + && comeback == true && stplyr->playerstate == PST_LIVE))); if (!demo.title && (!battlefullscreen || r_splitscreen)) @@ -4008,6 +4109,11 @@ void K_drawKartHUD(void) if (LUA_HudEnabled(hud_gametypeinfo)) K_drawKartBumpersOrKarma(); } + + if (gametyperules & GTR_SPHERES) + { + K_drawBlueSphereMeter(); + } } // Draw the countdowns after everything else. @@ -4097,4 +4203,9 @@ void K_drawKartHUD(void) } K_DrawWaypointDebugger(); + + if (gametype == GT_BATTLE) + { + K_drawKartEmeralds(); + } } diff --git a/src/k_kart.c b/src/k_kart.c index cb9f564c9..691832200 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -208,7 +208,7 @@ boolean K_IsPlayerLosing(player_t *player) INT32 winningpos = 1; UINT8 i, pcount = 0; - if (battlecapsules && player->kartstuff[k_bumper] <= 0) + if (battlecapsules && player->bumpers <= 0) return true; // DNF in break the capsules if (player->kartstuff[k_position] == 1) @@ -319,23 +319,23 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] = /*Eggman Monitor*/ { 1, 0 }, // Eggman Monitor /*Orbinaut*/ { 8, 0 }, // Orbinaut /*Jawz*/ { 8, 1 }, // Jawz - /*Mine*/ { 4, 1 }, // Mine + /*Mine*/ { 6, 1 }, // Mine /*Land Mine*/ { 0, 0 }, // Land Mine /*Ballhog*/ { 2, 1 }, // Ballhog /*Self-Propelled Bomb*/ { 0, 0 }, // Self-Propelled Bomb /*Grow*/ { 2, 1 }, // Grow /*Shrink*/ { 0, 0 }, // Shrink - /*Thunder Shield*/ { 0, 0 }, // Thunder Shield - /*Bubble Shield*/ { 0, 0 }, // Bubble Shield + /*Thunder Shield*/ { 4, 0 }, // Thunder Shield + /*Bubble Shield*/ { 1, 0 }, // Bubble Shield /*Flame Shield*/ { 0, 0 }, // Flame Shield /*Hyudoro*/ { 2, 0 }, // Hyudoro /*Pogo Spring*/ { 2, 0 }, // Pogo Spring /*Super Ring*/ { 0, 0 }, // Super Ring /*Kitchen Sink*/ { 0, 0 }, // Kitchen Sink /*Sneaker x2*/ { 0, 0 }, // Sneaker x2 - /*Sneaker x3*/ { 0, 1 }, // Sneaker x3 + /*Sneaker x3*/ { 1, 1 }, // Sneaker x3 /*Banana x3*/ { 1, 0 }, // Banana x3 - /*Banana x10*/ { 0, 1 }, // Banana x10 + /*Banana x10*/ { 1, 1 }, // Banana x10 /*Orbinaut x3*/ { 2, 0 }, // Orbinaut x3 /*Orbinaut x4*/ { 1, 1 }, // Orbinaut x4 /*Jawz x2*/ { 2, 1 } // Jawz x2 @@ -460,7 +460,7 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush, if (!playeringame[i] || players[i].spectator) continue; - if (!(gametyperules & GTR_BUMPERS) || players[i].kartstuff[k_bumper]) + if (!(gametyperules & GTR_BUMPERS) || players[i].bumpers) pingame++; if (players[i].exiting) @@ -741,8 +741,8 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) pingame++; if (players[i].exiting) dontforcespb = true; - if (players[i].kartstuff[k_bumper] > bestbumper) - bestbumper = players[i].kartstuff[k_bumper]; + if (players[i].bumpers > bestbumper) + bestbumper = players[i].bumpers; } // No forced SPB in 1v1s, it has to be randomly rolled @@ -903,7 +903,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // SPECIAL CASE No. 4: // Being in ring debt occasionally forces Super Ring on you if you mashed - if ((gametyperules & GTR_RINGS) && mashed && player->rings < 0 && cv_superring.value) + if (!(gametyperules & GTR_SPHERES) && mashed && player->rings < 0 && cv_superring.value) { INT32 debtamount = min(20, abs(player->rings)); if (P_RandomChance((debtamount*FRACUNIT)/20)) @@ -1042,7 +1042,7 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) return FixedMul(weight, mobj->scale); } -void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) { mobj_t *fx; fixed_t momdifx, momdify; @@ -1051,45 +1051,48 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) fixed_t mass1, mass2; if (!mobj1 || !mobj2) - return; + return false; // Don't bump when you're being reborn if ((mobj1->player && mobj1->player->playerstate != PST_LIVE) || (mobj2->player && mobj2->player->playerstate != PST_LIVE)) - return; + return false; if ((mobj1->player && mobj1->player->respawn.state != RESPAWNST_NONE) || (mobj2->player && mobj2->player->respawn.state != RESPAWNST_NONE)) - return; + return false; - // Don't bump if you're flashing - if (mobj1->player && mobj1->player->powers[pw_flashing] > 0 && !P_PlayerInPain(mobj1->player)) - { - INT32 flash = K_GetKartFlashing(mobj1->player); - if (mobj1->player->powers[pw_flashing] < flash) - mobj1->player->powers[pw_flashing]++; - return; - } + { // Don't bump if you're flashing + INT32 flash; - if (mobj2->player && mobj2->player->powers[pw_flashing] > 0 && !P_PlayerInPain(mobj2->player)) - { - INT32 flash = K_GetKartFlashing(mobj2->player); - if (mobj2->player->powers[pw_flashing] < flash) - mobj2->player->powers[pw_flashing]++; - return; + flash = K_GetKartFlashing(mobj1->player); + if (mobj1->player && mobj1->player->powers[pw_flashing] > 0 && mobj1->player->powers[pw_flashing] < flash) + { + if (mobj1->player->powers[pw_flashing] < flash-1) + mobj1->player->powers[pw_flashing]++; + return false; + } + + flash = K_GetKartFlashing(mobj2->player); + if (mobj2->player && mobj2->player->powers[pw_flashing] > 0 && mobj2->player->powers[pw_flashing] < flash) + { + if (mobj2->player->powers[pw_flashing] < flash-1) + mobj2->player->powers[pw_flashing]++; + return false; + } } // Don't bump if you've recently bumped if (mobj1->player && mobj1->player->kartstuff[k_justbumped]) { mobj1->player->kartstuff[k_justbumped] = bumptime; - return; + return false; } if (mobj2->player && mobj2->player->kartstuff[k_justbumped]) { mobj2->player->kartstuff[k_justbumped] = bumptime; - return; + return false; } mass1 = K_GetMobjWeight(mobj1, mobj2); @@ -1107,8 +1110,10 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) disty = (mobj1->y + mobj2->momy*3) - (mobj2->y + mobj1->momy*3); if (distx == 0 && disty == 0) + { // if there's no distance between the 2, they're directly on top of each other, don't run this - return; + return false; + } { // Normalize distance to the sum of the two objects' radii, since in a perfect world that would be the distance at the point of collision... fixed_t dist = P_AproxDistance(distx, disty); @@ -1145,7 +1150,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) if (dot >= 0) { // They're moving away from each other - return; + return false; } force = FixedDiv(dot, FixedMul(distx, distx)+FixedMul(disty, disty)); @@ -1218,6 +1223,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) //mobj2->player->kartstuff[k_spinouttype] = KSPIN_WIPEOUT; // Enforce type } } + + return true; } /** \brief Checks that the player is on an offroad subsector for realsies. Also accounts for line riding to prevent cheese. @@ -2033,7 +2040,7 @@ INT16 K_GetSpindashChargeTime(player_t *player) { // more charge time for higher speed // Tails = 2s, Mighty = 3s, Fang = 4s, Metal = 4s - return (player->kartspeed + 4) * (TICRATE/3); + return (player->kartspeed + 4) * (TICRATE/3); } fixed_t K_GetSpindashChargeSpeed(player_t *player) @@ -2044,20 +2051,17 @@ fixed_t K_GetSpindashChargeSpeed(player_t *player) return (player->kartspeed + player->kartweight) * (FRACUNIT/64); } -// Light weights have stronger boost stacking -- aka, better metabolism than heavies XD -#define METABOLISM -// sets k_boostpower, k_speedboost, k_accelboost, and k_handleboost to whatever we need it to be +// sets boostpower, speedboost, accelboost, and handleboost to whatever we need it to be static void K_GetKartBoostPower(player_t *player) { -#ifdef METABOLISM + // Light weights have stronger boost stacking -- aka, better metabolism than heavies XD const fixed_t maxmetabolismincrease = FRACUNIT/2; const fixed_t metabolism = FRACUNIT - ((9-player->kartweight) * maxmetabolismincrease / 8); -#endif // METABOLISM // v2 almost broke sliptiding when it fixed turning bugs! // This value is fine-tuned to feel like v1 again without reverting any of those changes. - const fixed_t sliptidehandling = 7*FRACUNIT/10; + const fixed_t sliptidehandling = FRACUNIT/2; fixed_t boostpower = FRACUNIT; fixed_t speedboost = 0, accelboost = 0, handleboost = 0; @@ -2076,43 +2080,35 @@ static void K_GetKartBoostPower(player_t *player) if (player->kartstuff[k_bananadrag] > TICRATE) boostpower = (4*boostpower)/5; -#ifdef METABOLISM - + // Note: Handling will ONLY stack when sliptiding! + // When you're not, it just uses the best instead of adding together, like the old behavior. #define ADDBOOST(s,a,h) { \ numboosts++; \ speedboost += FixedDiv(s, FRACUNIT + (metabolism * (numboosts-1))); \ accelboost += FixedDiv(a, FRACUNIT + (metabolism * (numboosts-1))); \ - handleboost = max(h, handleboost); \ + if (player->kartstuff[k_aizdriftstrat]) \ + handleboost += FixedDiv(h, FRACUNIT + (metabolism * (numboosts-1))); \ + else \ + handleboost = max(h, handleboost); \ } -#else - -#define ADDBOOST(s,a,h) { \ - numboosts++; \ - speedboost += s / numboosts; \ - accelboost += a / numboosts; \ - handleboost = max(h, handleboost); \ -} - -#endif // METABOLISM - if (player->kartstuff[k_sneakertimer]) // Sneaker { UINT8 i; for (i = 0; i < player->kartstuff[k_numsneakers]; i++) { - ADDBOOST(FRACUNIT/2, 8*FRACUNIT, sliptidehandling); // + 50% top speed, + 800% acceleration, +70% handling + ADDBOOST(FRACUNIT/2, 8*FRACUNIT, sliptidehandling); // + 50% top speed, + 800% acceleration, +50% handling } } if (player->kartstuff[k_invincibilitytimer]) // Invincibility { - ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT, sliptidehandling/3); // + 37.5% top speed, + 300% acceleration, +23% handling + ADDBOOST(3*FRACUNIT/8, 3*FRACUNIT, sliptidehandling/2); // + 37.5% top speed, + 300% acceleration, +25% handling } if (player->kartstuff[k_growshrinktimer] > 0) // Grow { - ADDBOOST(0, 0, sliptidehandling/3); // + 0% top speed, + 0% acceleration, +23% handling + ADDBOOST(0, 0, sliptidehandling/2); // + 0% top speed, + 0% acceleration, +25% handling } if (player->kartstuff[k_flamedash]) // Flame Shield dash @@ -2121,7 +2117,7 @@ static void K_GetKartBoostPower(player_t *player) ADDBOOST( dash, // + infinite top speed 3*FRACUNIT, // + 300% acceleration - FixedMul(FixedDiv(dash, FRACUNIT/2), sliptidehandling/3) // + infinite handling + FixedMul(FixedDiv(dash, FRACUNIT/2), sliptidehandling/2) // + infinite handling ); } @@ -2199,17 +2195,19 @@ fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed) fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower) { fixed_t finalspeed; - UINT8 kartspeed = player->kartspeed; - if ((gametyperules & (GTR_BUMPERS|GTR_KARMA)) == (GTR_BUMPERS|GTR_KARMA) && player->kartstuff[k_bumper] <= 0) - kartspeed = 1; + finalspeed = K_GetKartSpeedFromStat(player->kartspeed); - finalspeed = K_GetKartSpeedFromStat(kartspeed); + if (player->spheres > 0) + { + fixed_t sphereAdd = (FRACUNIT/80); // 50% at max + finalspeed = FixedMul(finalspeed, FRACUNIT + (sphereAdd * player->spheres)); + } if (K_PlayerUsesBotMovement(player)) { // Give top speed a buff for bots, since it's a fairly weak stat without drifting - fixed_t speedmul = ((kartspeed-1) * FRACUNIT / 8) / 10; // +10% for speed 9 + fixed_t speedmul = ((player->kartspeed-1) * FRACUNIT / 8) / 10; // +10% for speed 9 if (player->botvars.rival == true) { @@ -2238,14 +2236,15 @@ fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower) fixed_t K_GetKartAccel(player_t *player) { fixed_t k_accel = 32; // 36; - UINT8 kartspeed = player->kartspeed; - if ((gametyperules & (GTR_BUMPERS|GTR_KARMA)) == (GTR_BUMPERS|GTR_KARMA) && player->kartstuff[k_bumper] <= 0) - kartspeed = 1; - - //k_accel += 3 * (9 - kartspeed); // 36 - 60 - k_accel += 4 * (9 - kartspeed); // 32 - 64 + //k_accel += 3 * (9 - player->kartspeed); // 36 - 60 + k_accel += 4 * (9 - player->kartspeed); // 32 - 64 + if (player->spheres > 0) + { + fixed_t sphereAdd = (FRACUNIT/10); // 500% at max + k_accel = FixedMul(k_accel, FRACUNIT + (sphereAdd * player->spheres)); + } if (K_PlayerUsesBotMovement(player)) { @@ -2266,9 +2265,6 @@ UINT16 K_GetKartFlashing(player_t *player) tics += (tics/8) * (player->kartspeed); - if (gametype == GT_BATTLE) - tics *= 2; - return tics; } @@ -2316,18 +2312,6 @@ fixed_t K_3dKartMovement(player_t *player) oldspeed = p_speed; newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), orig); - if (player->kartstuff[k_pogospring]) // Pogo Spring minimum/maximum thrust - { - const fixed_t hscale = mapobjectscale /*+ (mapobjectscale - player->mo->scale)*/; - const fixed_t minspeed = 24*hscale; - const fixed_t maxspeed = 28*hscale; - - if (newspeed > maxspeed && player->kartstuff[k_pogospring] == 2) - newspeed = maxspeed; - if (newspeed < minspeed) - newspeed = minspeed; - } - finalspeed = newspeed - oldspeed; movemul = abs(forwardmove * FRACUNIT) / 50; @@ -2367,10 +2351,15 @@ void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics) INT32 tics1 = tics; INT32 tics2 = tics; + if (tics <= 0) + { + return; + } + if (mo1valid == true && mo2valid == true) { + const INT32 mintics = 1; const fixed_t ticaddfactor = mapobjectscale * 8; - const INT32 mintics = tics; const fixed_t mo1speed = FixedHypot(FixedHypot(mo1->momx, mo1->momy), mo1->momz); const fixed_t mo2speed = FixedHypot(FixedHypot(mo2->momx, mo2->momy), mo2->momz); @@ -2415,12 +2404,12 @@ void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics) if (mo1valid == true) { - mo1->hitlag += tics1; + mo1->hitlag = max(tics1, mo1->hitlag); } if (mo2valid == true) { - mo2->hitlag += tics2; + mo2->hitlag = max(tics2, mo2->hitlag); } } @@ -2442,88 +2431,51 @@ void K_DoInstashield(player_t *player) P_SetTarget(&layerb->target, player->mo); } -void K_BattleHitPlayer(player_t *player, player_t *victim, UINT8 points, boolean reducewanted) +void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved) { - if (reducewanted == false) - points = 1; // Force to 1 + UINT8 points = 1; + boolean trapItem = false; + + if (player == NULL || victim == NULL) + { + // Invalid player or victim + return; + } + + if (player == victim) + { + // You cannot give yourself points + return; + } + + if ((inflictor && !P_MobjWasRemoved(inflictor)) && (inflictor->type == MT_BANANA && inflictor->health > 1)) + { + trapItem = true; + } + + // Only apply score bonuses to non-bananas + if (trapItem == false) + { + if (K_IsPlayerWanted(victim)) + { + // +3 points for hitting a wanted player + points = 3; + } + else if (gametyperules & GTR_BUMPERS) + { + if ((victim->bumpers > 0) && (victim->bumpers <= bumpersRemoved)) + { + // +2 points for finishing off a player + points = 2; + } + } + } if (gametyperules & GTR_POINTLIMIT) { P_AddPlayerScore(player, points); K_SpawnBattlePoints(player, victim, points); } - - if ((gametyperules & GTR_WANTED) && (reducewanted == true)) - { - // Seems a little backwards, but the WANTED system is meant to prevent camping. - // If you don't want people to go after you, then be proactive! - player->kartstuff[k_wanted] -= wantedreduce; - victim->kartstuff[k_wanted] -= (wantedreduce/2); - } -} - -void K_RemoveBumper(player_t *player, mobj_t *inflictor, mobj_t *source) -{ - UINT8 score = 1; - boolean trapitem = false; - - if (!(gametyperules & GTR_BUMPERS)) - return; - - if (player->powers[pw_flashing] || P_PlayerInPain(player)) - return; - - if (inflictor && !P_MobjWasRemoved(inflictor)) - { - if (inflictor->type == MT_BANANA && inflictor->health <= 1) - { - trapitem = true; - } - } - - if (gametyperules & GTR_POINTLIMIT) - { - if (K_IsPlayerWanted(player)) - score = 3; - else if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] == 1) - score = 2; - } - - if (source && source->player && player != source->player) - { - K_BattleHitPlayer(source->player, player, score, trapitem); - } - - if (player->kartstuff[k_bumper] > 0) - { - if (player->kartstuff[k_bumper] == 1) - { - mobj_t *karmahitbox = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_KARMAHITBOX); // Player hitbox is too small!! - P_SetTarget(&karmahitbox->target, player->mo); - karmahitbox->destscale = player->mo->scale; - P_SetScale(karmahitbox, player->mo->scale); - CONS_Printf(M_GetText("%s lost all of their bumpers!\n"), player_names[player-players]); - } - - player->kartstuff[k_bumper]--; - - if (K_IsPlayerWanted(player)) - K_CalculateBattleWanted(); - } - - if (player->kartstuff[k_bumper] == 0) - { - player->kartstuff[k_comebacktimer] = comebacktime; - - if (player->kartstuff[k_comebackmode] == 2) - { - mobj_t *poof = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EXPLODE); - S_StartSound(poof, mobjinfo[MT_KARMAHITBOX].seesound); - player->kartstuff[k_comebackmode] = 0; - } - } - - K_CheckBumpers(); } void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type) @@ -2673,59 +2625,149 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source) P_SetPlayerMobjState(player->mo, S_KART_SPINOUT); } -void K_StealBumper(player_t *player, player_t *victim) +void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers) { - INT32 newbumper; - angle_t newangle, diff; - fixed_t newx, newy; - mobj_t *newmo; + if (!(gametyperules & GTR_BUMPERS)) + { + // Bumpers aren't being used + return; + } + + // TODO: replace all console text print-outs with a real visual + + if (player->bumpers > 0 && prevBumpers == 0) + { + if (player->kartstuff[k_comebackmode] == 2) + { + mobj_t *poof = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EXPLODE); + S_StartSound(poof, mobjinfo[MT_KARMAHITBOX].seesound); + } + + player->kartstuff[k_comebackmode] = 0; + + if (netgame) + { + CONS_Printf(M_GetText("%s is back in the game!\n"), player_names[player-players]); + } + } + else if (player->bumpers == 0 && prevBumpers > 0) + { + mobj_t *karmahitbox = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_KARMAHITBOX); + P_SetTarget(&karmahitbox->target, player->mo); + + karmahitbox->destscale = player->mo->destscale; + P_SetScale(karmahitbox, player->mo->scale); + + if (netgame) + { + CONS_Printf(M_GetText("%s lost all of their bumpers!\n"), player_names[player-players]); + } + } + + player->karmadelay = comebacktime; + K_CalculateBattleWanted(); + K_CheckBumpers(); +} + +void K_DestroyBumpers(player_t *player, UINT8 amount) +{ + UINT8 oldBumpers = player->bumpers; if (!(gametyperules & GTR_BUMPERS)) + { return; + } - if (netgame && player->kartstuff[k_bumper] <= 0) - CONS_Printf(M_GetText("%s is back in the game!\n"), player_names[player-players]); + amount = min(amount, player->bumpers); - newbumper = player->kartstuff[k_bumper]; - if (newbumper <= 1) - diff = 0; - else - diff = FixedAngle(360*FRACUNIT/newbumper); + if (amount == 0) + { + return; + } - newangle = player->mo->angle; - newx = player->mo->x + P_ReturnThrustX(player->mo, newangle + ANGLE_180, 64*FRACUNIT); - newy = player->mo->y + P_ReturnThrustY(player->mo, newangle + ANGLE_180, 64*FRACUNIT); + player->bumpers -= amount; + K_HandleBumperChanges(player, oldBumpers); +} - newmo = P_SpawnMobj(newx, newy, player->mo->z, MT_BATTLEBUMPER); - newmo->threshold = newbumper; - P_SetTarget(&newmo->tracer, victim->mo); - P_SetTarget(&newmo->target, player->mo); - newmo->angle = (diff * (newbumper-1)); - newmo->color = victim->skincolor; +void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) +{ + UINT8 oldPlayerBumpers = player->bumpers; + UINT8 oldVictimBumpers = victim->bumpers; - if (newbumper+1 < 2) - P_SetMobjState(newmo, S_BATTLEBUMPER3); - else if (newbumper+1 < 3) - P_SetMobjState(newmo, S_BATTLEBUMPER2); - else - P_SetMobjState(newmo, S_BATTLEBUMPER1); + UINT8 tookBumpers = 0; + if (!(gametyperules & GTR_BUMPERS)) + { + return; + } + + amount = min(amount, victim->bumpers); + + if (amount == 0) + { + return; + } + + while ((tookBumpers < amount) && (victim->bumpers > 0)) + { + UINT8 newbumper = player->bumpers; + + angle_t newangle, diff; + fixed_t newx, newy; + + mobj_t *newmo; + + if (newbumper <= 1) + { + diff = 0; + } + else + { + diff = FixedAngle(360*FRACUNIT/newbumper); + } + + newangle = player->mo->angle; + newx = player->mo->x + P_ReturnThrustX(player->mo, newangle + ANGLE_180, 64*FRACUNIT); + newy = player->mo->y + P_ReturnThrustY(player->mo, newangle + ANGLE_180, 64*FRACUNIT); + + newmo = P_SpawnMobj(newx, newy, player->mo->z, MT_BATTLEBUMPER); + newmo->threshold = newbumper; + + P_SetTarget(&newmo->tracer, victim->mo); + P_SetTarget(&newmo->target, player->mo); + + newmo->angle = (diff * (newbumper-1)); + newmo->color = victim->skincolor; + + if (newbumper+1 < 2) + { + P_SetMobjState(newmo, S_BATTLEBUMPER3); + } + else if (newbumper+1 < 3) + { + P_SetMobjState(newmo, S_BATTLEBUMPER2); + } + else + { + P_SetMobjState(newmo, S_BATTLEBUMPER1); + } + + player->bumpers++; + victim->bumpers--; + tookBumpers++; + } + + if (tookBumpers == 0) + { + // No change occured. + return; + } + + // Play steal sound S_StartSound(player->mo, sfx_3db06); - player->kartstuff[k_bumper]++; - player->kartstuff[k_comebackpoints] = 0; - player->powers[pw_flashing] = K_GetKartFlashing(player); - player->kartstuff[k_comebacktimer] = comebacktime; - - /*victim->powers[pw_flashing] = K_GetKartFlashing(victim); - victim->kartstuff[k_comebacktimer] = comebacktime;*/ - - victim->kartstuff[k_instashield] = 15; - if (cv_kartdebughuddrop.value && !modeattacking) - K_DropItems(victim); - else - K_DropHnextList(victim, false); - return; + K_HandleBumperChanges(player, oldPlayerBumpers); + K_HandleBumperChanges(victim, oldVictimBumpers); } // source is the mobj that originally threw the bomb that exploded etc. @@ -2969,8 +3011,10 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I } th->angle = an; + th->momx = FixedMul(finalspeed, FINECOSINE(an>>ANGLETOFINESHIFT)); th->momy = FixedMul(finalspeed, FINESINE(an>>ANGLETOFINESHIFT)); + th->momz = source->momz; switch (type) { @@ -3263,7 +3307,7 @@ void K_SpawnBoostTrail(player_t *player) if (!P_IsObjectOnGround(player->mo) || player->kartstuff[k_hyudorotimer] != 0 - || ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer])) + || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0 && player->karmadelay)) return; if (player->mo->eflags & MFE_VERTICALFLIP) @@ -3590,10 +3634,11 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map else { // Use pre-determined speed for tossing - PROJSPEED = FixedMul(82 << FRACBITS, K_GetKartGameSpeedScalar(gamespeed)); + PROJSPEED = FixedMul(82 * FRACUNIT, K_GetKartGameSpeedScalar(gamespeed)); } - // Scale to map size + // Scale to map scale + // Intentionally NOT player scale, that doesn't work. PROJSPEED = FixedMul(PROJSPEED, mapobjectscale); if (altthrow) @@ -3694,7 +3739,7 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map if (mo) { angle_t fa = player->mo->angle>>ANGLETOFINESHIFT; - fixed_t HEIGHT = (20 + (dir*10))*FRACUNIT + (player->mo->momz*P_MobjFlip(player->mo)); + fixed_t HEIGHT = ((20 + (dir*10)) * FRACUNIT) + (player->mo->momz*P_MobjFlip(player->mo)); // Also intentionally not player scale P_SetObjectMomZ(mo, HEIGHT, false); mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), PROJSPEED*dir); @@ -3799,41 +3844,48 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map return mo; } -void K_PuntMine(mobj_t *thismine, mobj_t *punter) +void K_PuntMine(mobj_t *origMine, mobj_t *punter) { - angle_t fa = K_MomentumAngle(punter) >> ANGLETOFINESHIFT; - fixed_t z = 30*mapobjectscale + punter->momz; + angle_t fa = K_MomentumAngle(punter); + fixed_t z = (punter->momz * P_MobjFlip(punter)) + (30 * FRACUNIT); fixed_t spd; mobj_t *mine; - if (!thismine || P_MobjWasRemoved(thismine)) + if (!origMine || P_MobjWasRemoved(origMine)) return; - //This guarantees you hit a mine being dragged - if (thismine->type == MT_SSMINE_SHIELD) // Create a new mine, and clean up the old one + if (punter->hitlag > 0) + return; + + // This guarantees you hit a mine being dragged + if (origMine->type == MT_SSMINE_SHIELD) // Create a new mine, and clean up the old one { - mine = P_SpawnMobj(thismine->x, thismine->y, thismine->z, MT_SSMINE); - P_SetTarget(&mine->target, thismine->target); - mine->angle = thismine->angle; - mine->flags2 = thismine->flags2; - mine->floorz = thismine->floorz; - mine->ceilingz = thismine->ceilingz; + mobj_t *mineOwner = origMine->target; - //Since we aren't using P_KillMobj, we need to clean up the hnext reference + mine = P_SpawnMobj(origMine->x, origMine->y, origMine->z, MT_SSMINE); + + P_SetTarget(&mine->target, mineOwner); + mine->angle = origMine->angle; + mine->flags2 = origMine->flags2; + mine->floorz = origMine->floorz; + mine->ceilingz = origMine->ceilingz; + + // Since we aren't using P_KillMobj, we need to clean up the hnext reference + P_SetTarget(&mineOwner->hnext, NULL); + mineOwner->player->kartstuff[k_bananadrag] = 0; + mineOwner->player->kartstuff[k_itemheld] = 0; + + if (--mineOwner->player->kartstuff[k_itemamount] <= 0) { - P_SetTarget(&thismine->target->hnext, NULL); //target is the player who owns the mine - thismine->target->player->kartstuff[k_bananadrag] = 0; - thismine->target->player->kartstuff[k_itemheld] = 0; - - if (--thismine->target->player->kartstuff[k_itemamount] <= 0) - thismine->target->player->kartstuff[k_itemtype] = KITEM_NONE; + mineOwner->player->kartstuff[k_itemtype] = KITEM_NONE; } - P_RemoveMobj(thismine); - + P_RemoveMobj(origMine); } else - mine = thismine; + { + mine = origMine; + } if (!mine || P_MobjWasRemoved(mine)) return; @@ -3841,20 +3893,19 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter) if (mine->threshold > 0 || mine->hitlag > 0) return; - spd = (82 + ((gamespeed-1) * 14))*mapobjectscale; // Avg Speed is 41 in Normal + spd = FixedMul(82 * punter->scale, K_GetKartGameSpeedScalar(gamespeed)); // Avg Speed is 41 in Normal mine->flags |= MF_NOCLIPTHING; P_SetMobjState(mine, S_SSMINE_AIR1); mine->threshold = 10; - mine->extravalue1 = 0; mine->reactiontime = mine->info->reactiontime; - K_SetHitLagForObjects(punter, mine, 5); + mine->momx = punter->momx + FixedMul(FINECOSINE(fa >> ANGLETOFINESHIFT), spd); + mine->momy = punter->momy + FixedMul(FINESINE(fa >> ANGLETOFINESHIFT), spd); + P_SetObjectMomZ(mine, z, false); - mine->momx = punter->momx + FixedMul(FINECOSINE(fa), spd); - mine->momy = punter->momy + FixedMul(FINESINE(fa), spd); - mine->momz = P_MobjFlip(mine) * z; + //K_SetHitLagForObjects(punter, mine, 5); mine->flags &= ~MF_NOCLIPTHING; } @@ -3952,7 +4003,7 @@ static void K_DoHyudoroSteal(player_t *player) // Can steal from this player && (gametype == GT_RACE //&& players[i].kartstuff[k_position] < player->kartstuff[k_position]) - || ((gametyperules & GTR_BUMPERS) && players[i].kartstuff[k_bumper] > 0)) + || ((gametyperules & GTR_BUMPERS) && players[i].bumpers > 0)) // Has an item && (players[i].kartstuff[k_itemtype] @@ -4149,10 +4200,10 @@ static void K_DoShrink(player_t *user) } } - void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) { const fixed_t vscale = mapobjectscale + (mo->scale - mapobjectscale); + fixed_t thrust = 0; if (mo->player && mo->player->spectator) return; @@ -4164,47 +4215,41 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) mo->eflags |= MFE_SPRUNG; - if (mo->eflags & MFE_VERTICALFLIP) - vertispeed *= -1; - if (vertispeed == 0) { - fixed_t thrust; - - if (mo->player) - { - thrust = 3*mo->player->speed/2; - if (thrust < 48< 72<player->kartstuff[k_pogospring] != 2) - { - if (mo->player->kartstuff[k_sneakertimer]) - thrust = FixedMul(thrust, (5*FRACUNIT)/4); - else if (mo->player->kartstuff[k_invincibilitytimer]) - thrust = FixedMul(thrust, (9*FRACUNIT)/8); - } - } - else - { - thrust = FixedDiv(3*P_AproxDistance(mo->momx, mo->momy)/2, 5*FRACUNIT/2); - if (thrust < 16< 32<momz = P_MobjFlip(mo)*FixedMul(FINESINE(ANGLE_22h>>ANGLETOFINESHIFT), FixedMul(thrust, vscale)); + thrust = P_AproxDistance(mo->momx, mo->momy) * P_MobjFlip(mo); + thrust = FixedMul(thrust, FINESINE(ANGLE_22h >> ANGLETOFINESHIFT)); } else - mo->momz = FixedMul(vertispeed, vscale); + { + thrust = vertispeed * P_MobjFlip(mo); + } + + if (mo->player) + { + if (mo->player->kartstuff[k_sneakertimer]) + { + thrust = FixedMul(thrust, 5*FRACUNIT/4); + } + else if (mo->player->kartstuff[k_invincibilitytimer]) + { + thrust = FixedMul(thrust, 9*FRACUNIT/8); + } + + mo->player->trickmomx = mo->player->trickmomy = mo->player->trickmomz = 0; // Reset post-hitlag momentums. + } + + mo->momz = FixedMul(thrust, vscale); if (mo->eflags & MFE_UNDERWATER) - mo->momz = (117 * mo->momz) / 200; + { + mo->momz = FixedDiv(mo->momz, FixedSqrt(3*FRACUNIT)); + } if (sound) + { S_StartSound(mo, (sound == 1 ? sfx_kc2f : sfx_kpogos)); + } } static void K_ThrowLandMine(player_t *player) @@ -4459,6 +4504,118 @@ void K_DropHnextList(player_t *player, boolean keepshields) } } +mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount) +{ + mobj_t *drop = P_SpawnMobj(x, y, z, MT_FLOATINGITEM); + P_SetScale(drop, drop->scale>>4); + drop->destscale = (3*drop->destscale)/2; + + drop->angle = angle; + P_Thrust(drop, + FixedAngle(P_RandomFixed() * 180) + angle, + 16*mapobjectscale); + + drop->momz = flip * 3 * mapobjectscale; + if (drop->eflags & MFE_UNDERWATER) + drop->momz = (117 * drop->momz) / 200; + + if (type == 0) + { + UINT8 useodds = 0; + INT32 spawnchance[NUMKARTRESULTS]; + INT32 totalspawnchance = 0; + INT32 i; + + memset(spawnchance, 0, sizeof (spawnchance)); + + useodds = amount; + + for (i = 1; i < NUMKARTRESULTS; i++) + spawnchance[i] = (totalspawnchance += K_KartGetItemOdds(useodds, i, 0, false, false, false)); + + if (totalspawnchance > 0) + { + UINT8 newType; + UINT8 newAmount; + + totalspawnchance = P_RandomKey(totalspawnchance); + for (i = 0; i < NUMKARTRESULTS && spawnchance[i] <= totalspawnchance; i++); + + // TODO: this is bad! + // K_KartGetItemResult requires a player + // but item roulette will need rewritten to change this + + switch (i) + { + // Special roulettes first, then the generic ones are handled by default + case KRITEM_DUALSNEAKER: // Sneaker x2 + newType = KITEM_SNEAKER; + newAmount = 2; + break; + case KRITEM_TRIPLESNEAKER: // Sneaker x3 + newType = KITEM_SNEAKER; + newAmount = 3; + break; + case KRITEM_TRIPLEBANANA: // Banana x3 + newType = KITEM_BANANA; + newAmount = 3; + break; + case KRITEM_TENFOLDBANANA: // Banana x10 + newType = KITEM_BANANA; + newAmount = 10; + break; + case KRITEM_TRIPLEORBINAUT: // Orbinaut x3 + newType = KITEM_ORBINAUT; + newAmount = 3; + break; + case KRITEM_QUADORBINAUT: // Orbinaut x4 + newType = KITEM_ORBINAUT; + newAmount = 4; + break; + case KRITEM_DUALJAWZ: // Jawz x2 + newType = KITEM_JAWZ; + newAmount = 2; + break; + default: + newType = i; + newAmount = 1; + break; + } + + if (newAmount > 1) + { + UINT8 j; + + for (j = 0; j < newAmount-1; j++) + { + K_CreatePaperItem( + x, y, z, + angle, flip, + newType, 1 + ); + } + } + + drop->threshold = newType; + drop->movecount = 1; + } + else + { + drop->threshold = 1; + drop->movecount = 1; + } + } + else + { + drop->threshold = type; + drop->movecount = amount; + } + + drop->flags |= MF_NOCLIPTHING; + + return drop; +} + // For getting EXTRA hit! void K_DropItems(player_t *player) { @@ -4466,24 +4623,13 @@ void K_DropItems(player_t *player) if (player->mo && !P_MobjWasRemoved(player->mo) && player->kartstuff[k_itemamount] > 0) { - mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM); - P_SetScale(drop, drop->scale>>4); - drop->destscale = (3*drop->destscale)/2; - - drop->angle = player->mo->angle + ANGLE_90; - P_Thrust(drop, - FixedAngle(P_RandomFixed()*180) + player->mo->angle + ANGLE_90, - 16*mapobjectscale); - drop->momz = P_MobjFlip(player->mo)*3*mapobjectscale; - if (drop->eflags & MFE_UNDERWATER) - drop->momz = (117 * drop->momz) / 200; - - drop->threshold = player->kartstuff[k_itemtype]; - drop->movecount = player->kartstuff[k_itemamount]; + mobj_t *drop = K_CreatePaperItem( + player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, + player->mo->angle + ANGLE_90, P_MobjFlip(player->mo), + player->kartstuff[k_itemtype], player->kartstuff[k_itemamount] + ); K_FlipFromObject(drop, player->mo); - - drop->flags |= MF_NOCLIPTHING; } K_StripItems(player); @@ -4714,10 +4860,7 @@ static void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z } //mobj->standingslope = slope; - -#ifdef HWRENDER - mobj->modeltilt = slope; -#endif + P_SetPitchRollFromSlope(mobj, slope); } // Move the hnext chain! @@ -5010,9 +5153,10 @@ static void K_MoveHeldObjects(player_t *player) P_TeleportMove(cur, targx, targy, targz); K_FlipFromObject(cur, player->mo); // Update graviflip in real time thanks. -#ifdef HWRENDER - cur->modeltilt = player->mo->modeltilt; -#endif + + cur->roll = player->mo->roll; + cur->pitch = player->mo->pitch; + num = (num+1) % 2; cur = cur->hnext; } @@ -5066,7 +5210,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) thisang = InvAngle(thisang); // Jawz only go after the person directly ahead of you in race... sort of literally now! - if (gametype == GT_RACE) + if (gametyperules & GTR_CIRCUIT) { // Don't go for people who are behind you if (thisang > ANGLE_67h) @@ -5090,7 +5234,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source) continue; // Don't pay attention to dead players - if (player->kartstuff[k_bumper] <= 0) + if (player->bumpers <= 0) continue; // Z pos too high/low @@ -5367,7 +5511,7 @@ void K_KartPlayerHUDUpdate(player_t *player) player->karthud[khud_ringspblock] = (leveltime % 14); // reset to normal anim next time } - if ((gametyperules & GTR_BUMPERS) && (player->exiting || player->kartstuff[k_comebacktimer])) + if ((gametyperules & GTR_BUMPERS) && (player->exiting || player->karmadelay)) { if (player->exiting) { @@ -5380,9 +5524,9 @@ void K_KartPlayerHUDUpdate(player_t *player) } else { - if (player->kartstuff[k_comebacktimer] < 6*TICRATE) + if (player->karmadelay < 6*TICRATE) player->karthud[khud_cardanimation] -= ((164-player->karthud[khud_cardanimation])/8)+1; - else if (player->kartstuff[k_comebacktimer] < 9*TICRATE) + else if (player->karmadelay < 9*TICRATE) player->karthud[khud_cardanimation] += ((164-player->karthud[khud_cardanimation])/8)+1; } @@ -5726,14 +5870,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_wipeoutslow] >= 1) player->mo->friction = ORIG_FRICTION; player->kartstuff[k_wipeoutslow] = 0; - if (!comeback) - player->kartstuff[k_comebacktimer] = comebacktime; - else if (player->kartstuff[k_comebacktimer]) - { - player->kartstuff[k_comebacktimer]--; - if (P_IsDisplayPlayer(player) && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer] <= 0) - comebackshowninfo = true; // client has already seen the message - } } if (player->rings > 20) @@ -5741,6 +5877,34 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) else if (player->rings < -20) player->rings = -20; + if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0)) + { + // Deplete 1 every tic when removed from the game. + player->spheres--; + } + else + { + // Deplete 1 every second when playing. + if ((leveltime % TICRATE) == 0) + player->spheres--; + } + + if (player->spheres > 40) + player->spheres = 40; + else if (player->spheres < 0) + player->spheres = 0; + + if (comeback == false || !(gametyperules & GTR_KARMA) || player->eliminated == true) + { + player->karmadelay = comebacktime; + } + else if (player->karmadelay > 0 && !P_PlayerInPain(player)) + { + player->karmadelay--; + if (P_IsDisplayPlayer(player) && player->bumpers <= 0 && player->karmadelay <= 0) + comebackshowninfo = true; // client has already seen the message + } + if (player->kartstuff[k_ringdelay]) player->kartstuff[k_ringdelay]--; @@ -5851,26 +6015,25 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_KartPlayerHUDUpdate(player); - if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] > 0 && !P_PlayerInPain(player) && !player->powers[pw_flashing]) + if ((gametyperules & GTR_WANTED) && player->bumpers > 0 && !P_PlayerInPain(player) && !player->powers[pw_flashing]) { player->kartstuff[k_wanted]++; - if (battleovertime.enabled >= 10*TICRATE) + } + + if ((battleovertime.enabled >= 10*TICRATE) && (player->eliminated == false)) + { + fixed_t distanceToBarrier = 0; + + if (battleovertime.radius > 0) { - if (P_AproxDistance(player->mo->x - battleovertime.x, player->mo->y - battleovertime.y) > battleovertime.radius) - { - player->kartstuff[k_killfield]++; - if (player->kartstuff[k_killfield] > 4*TICRATE) - { - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); - //player->kartstuff[k_killfield] = 1; - } - } - else if (player->kartstuff[k_killfield] > 0) - player->kartstuff[k_killfield]--; + distanceToBarrier = R_PointToDist2(player->mo->x, player->mo->y, battleovertime.x, battleovertime.y) - (player->mo->radius * 2); + } + + if (distanceToBarrier > battleovertime.radius) + { + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_TIMEOVER); } } - else if (player->kartstuff[k_killfield] > 0) - player->kartstuff[k_killfield]--; if (P_IsObjectOnGround(player->mo)) player->kartstuff[k_waterskip] = 0; @@ -5880,7 +6043,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_eggmanexplode]) { - if (player->spectator || (gametype == GT_BATTLE && !player->kartstuff[k_bumper])) + if (player->spectator || (gametype == GT_BATTLE && !player->bumpers)) player->kartstuff[k_eggmanexplode] = 0; else { @@ -5923,13 +6086,15 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_FlameDashLeftoverSmoke(player->mo); } - if (player->kartstuff[k_comebacktimer]) + if (player->karmadelay) player->kartstuff[k_comebackmode] = 0; - if (P_IsObjectOnGround(player->mo) && player->kartstuff[k_pogospring]) + if (P_IsObjectOnGround(player->mo) && player->trickpanel != 0) { - if (P_MobjFlip(player->mo)*player->mo->momz <= 0) - player->kartstuff[k_pogospring] = 0; + if (P_MobjFlip(player->mo) * player->mo->momz <= 0) + { + player->trickpanel = 0; + } } if (cmd->buttons & BT_DRIFT) @@ -6440,6 +6605,11 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) return 0; } + if (player->trickpanel != 0) + { + return 0; + } + currentSpeed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy); if ((currentSpeed <= 0) // Not moving @@ -6491,10 +6661,7 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) INT32 K_GetKartDriftSparkValue(player_t *player) { - UINT8 kartspeed = (gametype == GT_BATTLE && player->kartstuff[k_bumper] <= 0) - ? 1 - : player->kartspeed; - return (26*4 + kartspeed*2 + (9 - player->kartweight))*8; + return (26*4 + player->kartspeed*2 + (9 - player->kartweight))*8; } /* @@ -6781,7 +6948,7 @@ void K_KartUpdatePosition(player_t *player) if (!playeringame[i] || players[i].spectator || !players[i].mo) continue; - if (gametype == GT_RACE) + if (gametyperules & GTR_CIRCUIT) { if (player->exiting) // End of match standings { @@ -6800,7 +6967,7 @@ void K_KartUpdatePosition(player_t *player) } } } - else if (gametype == GT_BATTLE) + else { if (player->exiting) // End of match standings { @@ -6810,11 +6977,30 @@ void K_KartUpdatePosition(player_t *player) } else { - // I have less points than but the same bumpers as this player OR - // I have less bumpers than this player - if ((players[i].kartstuff[k_bumper] == player->kartstuff[k_bumper] && players[i].marescore > player->marescore) - || (players[i].kartstuff[k_bumper] > player->kartstuff[k_bumper])) + UINT8 myEmeralds = K_NumEmeralds(player); + UINT8 yourEmeralds = K_NumEmeralds(&players[i]); + + if (yourEmeralds > myEmeralds) + { + // Emeralds matter above all position++; + } + else if (yourEmeralds == myEmeralds) + { + // Bumpers are a tie breaker + if (players[i].bumpers > player->bumpers) + { + position++; + } + else if (players[i].bumpers == player->bumpers) + { + // Score is the second tier tie breaker + if (players[i].marescore > player->marescore) + { + position++; + } + } + } } } } @@ -7094,12 +7280,6 @@ void K_AdjustPlayerFriction(player_t *player) } */ - // Karma ice physics - if (gametype == GT_BATTLE && player->kartstuff[k_bumper] <= 0) - { - player->mo->friction += 1228; - } - // Water gets ice physics too if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) { @@ -7219,7 +7399,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) newitem->fuse = 15*TICRATE; // selected randomly. player->kartstuff[k_comebackmode] = 0; - player->kartstuff[k_comebacktimer] = comebacktime; + player->karmadelay = comebacktime; S_StartSound(player->mo, sfx_s254); } } @@ -7709,12 +7889,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_POGOSPRING: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO - && !player->kartstuff[k_pogospring]) + if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO && player->trickpanel == 0) { K_PlayBoostTaunt(player->mo); K_DoPogoSpring(player->mo, 32<kartstuff[k_pogospring] = 1; + player->trickpanel = 1; + player->trickdelay = 1; player->kartstuff[k_itemamount]--; } break; @@ -7816,17 +7996,123 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->mo->drawflags &= ~MFD_DONTDRAW; } - if (gametype == GT_BATTLE && player->kartstuff[k_bumper] <= 0) // dead in match? you da bomb + if (gametype == GT_BATTLE && player->bumpers <= 0) // dead in match? you da bomb { K_DropItems(player); //K_StripItems(player); K_StripOther(player); player->mo->drawflags |= MFD_SHADOW; - player->powers[pw_flashing] = player->kartstuff[k_comebacktimer]; + player->powers[pw_flashing] = player->karmadelay; } - else if (gametype == GT_RACE || player->kartstuff[k_bumper] > 0) + else if (gametype == GT_RACE || player->bumpers > 0) { player->mo->drawflags &= ~(MFD_TRANSMASK|MFD_BRIGHTMASK); } + + if (player->trickpanel == 1) + { + const angle_t lr = ANGLE_45; + fixed_t momz = FixedDiv(player->mo->momz, mapobjectscale); // bring momz back to scale... + fixed_t speedmult = max(0, FRACUNIT - abs(momz)/TRICKMOMZRAMP); // TRICKMOMZRAMP momz is minimum speed (Should be 20) + fixed_t basespeed = P_AproxDistance(player->mo->momx, player->mo->momy); // at WORSE, keep your normal speed when tricking. + fixed_t speed = FixedMul(speedmult, P_AproxDistance(player->mo->momx, player->mo->momy)); + + // debug shit + //CONS_Printf("%d\n", player->mo->momz / mapobjectscale); + + if (player->trickdelay <= 0) + { + + if (cmd->turning > 0) + { + P_InstaThrust(player->mo, player->mo->angle + lr, max(basespeed, speed*5/2)); + + player->trickmomx = player->mo->momx; + player->trickmomy = player->mo->momy; + player->trickmomz = player->mo->momz; + P_InstaThrust(player->mo, 0, 0); // Sike, you have no speed :) + player->mo->momz = 0; + + player->trickpanel = 2; + player->mo->hitlag = TRICKLAG; + } + else if (cmd->turning < 0) + { + P_InstaThrust(player->mo, player->mo->angle - lr, max(basespeed, speed*5/2)); + + player->trickmomx = player->mo->momx; + player->trickmomy = player->mo->momy; + player->trickmomz = player->mo->momz; + P_InstaThrust(player->mo, 0, 0); // Sike, you have no speed :) + player->mo->momz = 0; + + player->trickpanel = 3; + player->mo->hitlag = TRICKLAG; + } + else if (player->kartstuff[k_throwdir] == 1) + { + if (player->mo->momz * P_MobjFlip(player->mo) > 0) + { + player->mo->momz = 0; + } + + P_InstaThrust(player->mo, player->mo->angle, max(basespeed, speed*3)); + + player->trickmomx = player->mo->momx; + player->trickmomy = player->mo->momy; + player->trickmomz = player->mo->momz; + P_InstaThrust(player->mo, 0, 0); // Sike, you have no speed :) + player->mo->momz = 0; + + player->trickpanel = 2; + player->mo->hitlag = TRICKLAG; + } + else if (player->kartstuff[k_throwdir] == -1) + { + boolean relative = true; + + player->mo->momx /= 3; + player->mo->momy /= 3; + + if (player->mo->momz * P_MobjFlip(player->mo) <= 0) + { + relative = false; + } + + P_SetObjectMomZ(player->mo, 48*FRACUNIT, relative); + + player->trickmomx = player->mo->momx; + player->trickmomy = player->mo->momy; + player->trickmomz = player->mo->momz; + P_InstaThrust(player->mo, 0, 0); // Sike, you have no speed :) + player->mo->momz = 0; + + player->trickpanel = 3; + player->mo->hitlag = TRICKLAG; + } + } + } + // After hitlag, we will get here and will be able to apply the desired momentums! + else if (player->trickmomx || player->trickmomy || player->trickmomz) + { + player->mo->momx = player->trickmomx; + player->mo->momy = player->trickmomy; + player->mo->momz = player->trickmomz; + + player->trickmomx = player->trickmomy = player->trickmomz = 0; + + } + + // Wait until we let go off the control stick to remove the delay + if (player->trickdelay > 0) + { + player->trickdelay--; + + if ((player->kartstuff[k_throwdir] != 0 || cmd->turning != 0) && player->trickdelay <= 0) + { + // Don't allow a trick until you go back to neutral + player->trickdelay = 1; + } + } } K_KartDrift(player, P_IsObjectOnGround(player->mo)); // Not using onground, since we don't want this affected by spring pads diff --git a/src/k_kart.h b/src/k_kart.h index e26e3de86..37a31e27b 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -27,7 +27,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush, boolean bot, boolean rival); INT32 K_GetShieldFromItem(INT32 item); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); -void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); void K_KartPainEnergyFling(player_t *player); void K_FlipFromObject(mobj_t *mo, mobj_t *master); void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); @@ -42,13 +42,14 @@ void K_KartPlayerAfterThink(player_t *player); angle_t K_MomentumAngle(mobj_t *mo); void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics); void K_DoInstashield(player_t *player); -void K_BattleHitPlayer(player_t *player, player_t *victim, UINT8 points, boolean reducewanted); -void K_RemoveBumper(player_t *player, mobj_t *inflictor, mobj_t *source); +void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved); void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type); void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_DebtStingPlayer(player_t *player, mobj_t *source); -void K_StealBumper(player_t *player, player_t *victim); +void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers); +void K_DestroyBumpers(player_t *player, UINT8 amount); +void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount); void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source); void K_SpawnMineExplosion(mobj_t *source, UINT8 color); UINT16 K_DriftSparkColor(player_t *player, INT32 charge); @@ -72,6 +73,7 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue); INT32 K_GetKartDriftSparkValue(player_t *player); void K_SpawnDriftBoostExplosion(player_t *player, int stage); void K_KartUpdatePosition(player_t *player); +mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount); void K_DropItems(player_t *player); void K_DropRocketSneaker(player_t *player); void K_DropKitchenSink(player_t *player); diff --git a/src/k_waypoint.c b/src/k_waypoint.c index b9581e871..db8289aaa 100644 --- a/src/k_waypoint.c +++ b/src/k_waypoint.c @@ -314,7 +314,7 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj) } else if (checkdist < closestdist && bestfindist == INT32_MAX) { - if (!P_CheckSight(mobj, checkwaypoint->mobj)) + if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj)) { // Save sight checks for the end, so we only do it if we have to continue; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 81978546d..eff2264c1 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1410,6 +1410,18 @@ static int lib_pCheckSight(lua_State *L) return 1; } +static int lib_pTraceBlockingLines(lua_State *L) +{ + mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + //HUDSAFE? + INLEVEL + if (!t1 || !t2) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_TraceBlockingLines(t1, t2)); + return 1; +} + static int lib_pCheckHoopPosition(lua_State *L) { mobj_t *hoopthing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -3432,16 +3444,17 @@ static int lib_kExplodePlayer(lua_State *L) return 0; } -static int lib_kStealBumper(lua_State *L) +static int lib_kTakeBumpersFromPlayer(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); player_t *victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + UINT8 amount = (UINT8)luaL_optinteger(L, 3, 1); NOHUD if (!player) return LUA_ErrInvalid(L, "player_t"); if (!victim) return LUA_ErrInvalid(L, "player_t"); - K_StealBumper(player, victim); + K_TakeBumpersFromPlayer(player, victim, amount); return 0; } @@ -3782,6 +3795,7 @@ static luaL_Reg lib[] = { {"P_SlideMove",lib_pSlideMove}, {"P_BounceMove",lib_pBounceMove}, {"P_CheckSight", lib_pCheckSight}, + {"P_TraceBlockingLines", lib_pTraceBlockingLines}, {"P_CheckHoopPosition",lib_pCheckHoopPosition}, {"P_RadiusAttack",lib_pRadiusAttack}, {"P_FloorzAtPos",lib_pFloorzAtPos}, @@ -3918,7 +3932,7 @@ static luaL_Reg lib[] = { {"K_SpinPlayer",lib_kSpinPlayer}, {"K_TumblePlayer",lib_kTumblePlayer}, {"K_ExplodePlayer",lib_kExplodePlayer}, - {"K_StealBumper",lib_kStealBumper}, + {"K_TakeBumpersFromPlayer",lib_kTakeBumpersFromPlayer}, {"K_SpawnKartExplosion",lib_kSpawnKartExplosion}, {"K_SpawnMineExplosion",lib_kSpawnMineExplosion}, {"K_SpawnBoostTrail",lib_kSpawnBoostTrail}, diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 5e5a1dbc4..7e2445b0c 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -313,8 +313,6 @@ static int PopPivotSubTable(spriteframepivot_t *pivot, lua_State *L, int stk, in pivot[idx].x = (INT32)value; else if (ikey == 2 || (key && fastcmp(key, "y"))) pivot[idx].y = (INT32)value; - else if (ikey == 3 || (key && fastcmp(key, "rotaxis"))) - pivot[idx].rotaxis = (UINT8)value; else if (ikey == -1 && (key != NULL)) FIELDERROR("pivot key", va("invalid option %s", key)); okcool = 1; @@ -579,8 +577,6 @@ static int framepivot_get(lua_State *L) lua_pushinteger(L, framepivot->x); else if (fastcmp("y", field)) lua_pushinteger(L, framepivot->y); - else if (fastcmp("rotaxis", field)) - lua_pushinteger(L, (UINT8)framepivot->rotaxis); else return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field)); @@ -605,8 +601,6 @@ static int framepivot_set(lua_State *L) framepivot->x = luaL_checkinteger(L, 3); else if (fastcmp("y", field)) framepivot->y = luaL_checkinteger(L, 3); - else if (fastcmp("rotaxis", field)) - framepivot->rotaxis = luaL_checkinteger(L, 3); else return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field)); diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c index c6c07fc7e..621f421ea 100644 --- a/src/lua_mathlib.c +++ b/src/lua_mathlib.c @@ -14,7 +14,7 @@ //#include "fastcmp.h" #include "tables.h" #include "p_local.h" -#include "doomstat.h" // for ALL7EMERALDS +#include "doomstat.h" // for ALLCHAOSEMERALDS #include "lua_script.h" #include "lua_libs.h" @@ -162,7 +162,7 @@ static int lib_getsecspecial(lua_State *L) static int lib_all7emeralds(lua_State *L) { - lua_pushboolean(L, ALL7EMERALDS(luaL_checkinteger(L, 1))); + lua_pushboolean(L, ALLCHAOSEMERALDS(luaL_checkinteger(L, 1))); return 1; } diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 812135f17..63eeaa47b 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -206,6 +206,8 @@ static int player_get(lua_State *L) lua_pushangle(L, plr->drawangle); else if (fastcmp(field,"rings")) lua_pushinteger(L, plr->rings); + else if (fastcmp(field,"spheres")) + lua_pushinteger(L, plr->spheres); else if (fastcmp(field,"powers")) LUA_PushUserdata(L, plr->powers, META_POWERS); else if (fastcmp(field,"kartstuff")) @@ -218,6 +220,16 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->tumbleHeight); else if (fastcmp(field,"tumbleLastBounce")) lua_pushboolean(L, plr->tumbleLastBounce); + else if (fastcmp(field,"trickpanel")) + lua_pushinteger(L, plr->trickpanel); + else if (fastcmp(field,"trickdelay")) + lua_pushinteger(L, plr->trickdelay); + else if (fastcmp(field,"trickmomx")) + lua_pushfixed(L, plr->trickmomx); + else if (fastcmp(field,"trickmomy")) + lua_pushfixed(L, plr->trickmomy); + else if (fastcmp(field,"trickmomz")) + lua_pushfixed(L, plr->trickmomz); else if (fastcmp(field,"pflags")) lua_pushinteger(L, plr->pflags); else if (fastcmp(field,"panim")) @@ -481,6 +493,8 @@ static int player_set(lua_State *L) plr->drawangle = luaL_checkangle(L, 3); else if (fastcmp(field,"rings")) plr->rings = (INT32)luaL_checkinteger(L, 3); + else if (fastcmp(field,"spheres")) + plr->spheres = (INT32)luaL_checkinteger(L, 3); else if (fastcmp(field,"powers")) return NOSET; else if (fastcmp(field,"pflags")) @@ -511,6 +525,16 @@ static int player_set(lua_State *L) plr->tumbleHeight = (UINT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"tumbleLastBounce")) plr->tumbleLastBounce = luaL_checkboolean(L, 3); + else if (fastcmp(field,"trickpanel")) + plr->trickpanel = luaL_checkinteger(L, 3); + else if (fastcmp(field,"trickdelay")) + plr->trickdelay = (tic_t)luaL_checkinteger(L, 3); + else if (fastcmp(field,"trickmomx")) + plr->trickmomx = (fixed_t)luaL_checkfixed(L, 3); + else if (fastcmp(field,"trickmomy")) + plr->trickmomy = (fixed_t)luaL_checkfixed(L, 3); + else if (fastcmp(field,"trickmomz")) + plr->trickmomz = (fixed_t)luaL_checkfixed(L, 3); else if (fastcmp(field,"kartspeed")) plr->kartspeed = (UINT8)luaL_checkinteger(L, 3); else if (fastcmp(field,"kartweight")) diff --git a/src/m_cheat.c b/src/m_cheat.c index ff5f86968..0f39bb643 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -771,12 +771,13 @@ void Command_Savecheckpoint_f(void) } // Like M_GetAllEmeralds() but for console devmode junkies. -/*void Command_Getallemeralds_f(void) +/* +void Command_Getallemeralds_f(void) { REQUIRE_SINGLEPLAYER; REQUIRE_PANDORA; - emeralds = ((EMERALD7)*2)-1; + emeralds = EMERALD_ALL; CONS_Printf(M_GetText("You now have all 7 emeralds.\n")); } @@ -788,7 +789,8 @@ void Command_Resetemeralds_f(void) emeralds = 0; CONS_Printf(M_GetText("Emeralds reset to zero.\n")); -}*/ +} +*/ void Command_Devmode_f(void) { diff --git a/src/m_cond.c b/src/m_cond.c index 8ffe3c378..bfd463a7c 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -341,6 +341,12 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa UINT8 M_AnySecretUnlocked(void) { INT32 i; + +#ifdef DEVELOP + if (1) + return true; +#endif + for (i = 0; i < MAXUNLOCKABLES; ++i) { if (!unlockables[i].nocecho && unlockables[i].unlocked) @@ -376,6 +382,12 @@ UINT8 M_SecretUnlocked(INT32 type) UINT8 M_MapLocked(INT32 mapnum) { + +#ifdef DEVELOP + if (1) + return false; +#endif + if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0) return false; if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked) diff --git a/src/m_menu.c b/src/m_menu.c index 7f6f542c6..28570c699 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6374,7 +6374,7 @@ static void M_GetAllEmeralds(INT32 choice) { (void)choice; - emeralds = ((EMERALD7)*2)-1; + emeralds = EMERALD_ALL; M_StartMessage(M_GetText("You now have all 7 emeralds.\nUse them wisely.\nWith great power comes great ring drain.\n"),NULL,MM_NOTHING); G_SetGameModified(multiplayer, true); @@ -8139,11 +8139,11 @@ static void M_ReplayTimeAttack(INT32 choice) break; case 3: // guest // srb2/replay/main/map01-guest.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); + G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); return; } // srb2/replay/main/map01-sonic-time-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which)); + G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which)); } /*else if (currentMenu == &SP_NightsReplayDef) { @@ -8165,13 +8165,13 @@ static void M_ReplayTimeAttack(INT32 choice) break; } // srb2/replay/main/map01-score-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which)); + G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which)); }*/ } static void M_EraseGuest(INT32 choice) { - const char *rguest = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); + const char *rguest = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); (void)choice; if (FIL_FileExists(rguest)) remove(rguest); @@ -8186,10 +8186,10 @@ static void M_EraseGuest(INT32 choice) static void M_OverwriteGuest(const char *which) { - char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); + char *rguest = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))); UINT8 *buf; size_t len; - len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf); + len = FIL_ReadFile(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf); if (!len) { return; } @@ -8258,7 +8258,7 @@ static void M_SetGuestReplay(INT32 choice) M_StartMessage(M_GetText("Are you sure you want to\ndelete the guest replay data?\n\n(Press 'Y' to confirm)\n"),M_EraseGuest,MM_YESNO); return; } - if (FIL_FileExists(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)))) + if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)))) M_StartMessage(M_GetText("Are you sure you want to\noverwrite the guest replay data?\n\n(Press 'Y' to confirm)\n"),which,MM_YESNO); else which(0); diff --git a/src/p_enemy.c b/src/p_enemy.c index bc925d4aa..01f8f6bb7 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4428,7 +4428,7 @@ static inline boolean PIT_GrenadeRing(mobj_t *thing) return true; if (thing->player && (thing->player->kartstuff[k_hyudorotimer] - || ((gametyperules & GTR_BUMPERS) && thing->player && thing->player->kartstuff[k_bumper] <= 0 && thing->player->kartstuff[k_comebacktimer]))) + || ((gametyperules & GTR_BUMPERS) && thing->player && thing->player->bumpers <= 0 && thing->player->karmadelay))) return true; // see if it went over / under @@ -4457,9 +4457,6 @@ void A_GrenadeRing(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; - if (actor->hitlag > 0) - return; - if (actor->state == &states[S_SSMINE_DEPLOY8]) explodedist = (3*explodedist)/2; @@ -4484,7 +4481,7 @@ static inline boolean PIT_MineExplode(mobj_t *thing) if (!grenade || P_MobjWasRemoved(grenade)) return false; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot - if (grenade->flags2 & MF2_DEBRIS) // don't explode twice + if (grenade->flags2 & MF2_DEBRIS) // don't explode twice return false; if (thing == grenade || thing->type == MT_MINEEXPLOSIONSOUND) // Don't explode yourself! Endless loop! @@ -4496,7 +4493,7 @@ static inline boolean PIT_MineExplode(mobj_t *thing) if (netgame && thing->player && thing->player->spectator) return true; - if ((gametyperules & GTR_BUMPERS) && grenade->target && grenade->target->player && grenade->target->player->kartstuff[k_bumper] <= 0 && thing == grenade->target) + if ((gametyperules & GTR_BUMPERS) && grenade->target && grenade->target->player && grenade->target->player->bumpers <= 0 && thing == grenade->target) return true; // see if it went over / under @@ -4527,9 +4524,6 @@ void A_SSMineExplode(mobj_t *actor) if (actor->flags2 & MF2_DEBRIS) return; - if (actor->hitlag > 0) - return; - type = (mobjtype_t)locvar1; // Use blockmap to check for nearby shootables @@ -8648,7 +8642,7 @@ void A_ItemPop(mobj_t *actor) if (actor->info->deathsound) S_StartSound(remains, actor->info->deathsound); - if (!((gametyperules & GTR_BUMPERS) && actor->target->player->kartstuff[k_bumper] <= 0)) + if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumpers <= 0)) actor->target->player->kartstuff[k_itemroulette] = 1; remains->flags2 &= ~MF2_AMBUSH; @@ -8682,7 +8676,7 @@ void A_JawzChase(mobj_t *actor) angle_t angledelta = actor->angle - targetangle; boolean turnclockwise = true; - if ((gametyperules & GTR_CIRCUIT)) + if (gametyperules & GTR_CIRCUIT) { const fixed_t distbarrier = FixedMul(512*mapobjectscale, FRACUNIT + ((gamespeed-1) * (FRACUNIT/4))); const fixed_t distaway = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); @@ -9009,7 +9003,7 @@ void A_SPBChase(mobj_t *actor) actor->lastlook = actor->tracer->player-players; // Save the player num for death scumming... actor->tracer->player->kartstuff[k_ringlock] = 1; // set ring lock - if (!P_IsObjectOnGround(actor->tracer) /*&& !actor->tracer->player->kartstuff[k_pogospring]*/) + if (!P_IsObjectOnGround(actor->tracer)) { // In the air you have no control; basically don't hit unless you make a near complete stop defspeed = (7 * actor->tracer->player->speed) / 8; @@ -9714,7 +9708,7 @@ void A_ReaperThinker(mobj_t *actor) continue; player = &players[i]; - if (player && player->mo && player->kartstuff[k_bumper] && player->score >= maxscore) + if (player && player->mo && player->bumpers && player->score >= maxscore) { targetplayermo = player->mo; maxscore = player->score; diff --git a/src/p_floor.c b/src/p_floor.c index f8f7fef2d..0ad27d580 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2371,7 +2371,7 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) P_SetThingPosition(thing); if (thing->flags & MF_SHOOTABLE) P_DamageMobj(thing, puncher, puncher, 1, DMG_NORMAL); - else if (thing->type == MT_RING || thing->type == MT_COIN || thing->type == MT_RANDOMITEM) + else if (thing->type == MT_RING || thing->type == MT_RANDOMITEM) { thing->momz = FixedMul(3*FRACUNIT, thing->scale); P_TouchSpecialThing(thing, puncher, false); diff --git a/src/p_inter.c b/src/p_inter.c index 1a5064f76..bff509c89 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -30,7 +30,7 @@ #include "f_finale.h" // SRB2kart -#include "k_kart.h" +#include "k_kart.h" #include "k_battle.h" #include "k_pwrlv.h" #include "k_grandprix.h" @@ -108,11 +108,13 @@ void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End) // boolean P_CanPickupItem(player_t *player, UINT8 weapon) { - if (player->exiting || mapreset) + if (player->exiting || mapreset || player->eliminated) return false; - /*if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0) // No bumpers in Match - return false;*/ +#ifndef OTHERKARMAMODES + if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0) // No bumpers in Match + return false; +#endif if (weapon) { @@ -182,15 +184,24 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (heightcheck) { + fixed_t toucher_bottom = toucher->z; + fixed_t special_bottom = special->z; + + if (toucher->flags & MF_PICKUPFROMBELOW) + toucher_bottom -= toucher->height; + + if (special->flags & MF_PICKUPFROMBELOW) + special_bottom -= special->height; + if (toucher->momz < 0) { - if (toucher->z + toucher->momz > special->z + special->height) + if (toucher_bottom + toucher->momz > special->z + special->height) return; - } else if (toucher->z > special->z + special->height) + } else if (toucher_bottom > special->z + special->height) return; if (toucher->momz > 0) { - if (toucher->z + toucher->height + toucher->momz < special->z) + if (toucher->z + toucher->height + toucher->momz < special_bottom) return; - } else if (toucher->z + toucher->height < special->z) + } else if (toucher->z + toucher->height < special_bottom) return; } @@ -231,11 +242,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetObjectMomZ(player->mo, 12<mo, player->mo->angle, 20<kartstuff[k_itemamount] && player->kartstuff[k_itemtype] != special->threshold)) return; - if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0) + if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0) return; player->kartstuff[k_itemtype] = special->threshold; @@ -252,15 +263,19 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->flags &= ~MF_SPECIAL; return; - case MT_RANDOMITEM: // SRB2kart + case MT_RANDOMITEM: if (!P_CanPickupItem(player, 1)) return; - if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0) + if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0) { - if (player->kartstuff[k_comebackmode] || player->kartstuff[k_comebacktimer]) +#ifdef OTHERKARMAMODES + if (player->kartstuff[k_comebackmode] || player->karmadelay) return; player->kartstuff[k_comebackmode] = 1; +#else + return; +#endif } special->momx = special->momy = special->momz = 0; @@ -272,7 +287,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; if (player == special->target->player) return; - if (player->kartstuff[k_bumper] <= 0) + if (player->bumpers <= 0) return; if (special->target->player->exiting || player->exiting) return; @@ -280,53 +295,38 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (P_PlayerInPain(special->target->player)) return; + if (special->target->player->karmadelay > 0) + return; + +#ifdef OTHERKARMAMODES if (!special->target->player->kartstuff[k_comebackmode]) { - if (player->kartstuff[k_growshrinktimer] - || player->kartstuff[k_hyudorotimer] || P_PlayerInPain(player) - || player->kartstuff[k_invincibilitytimer] || player->powers[pw_flashing]) - return; - else +#endif { - mobj_t *boom = P_SpawnMobj(special->target->x, special->target->y, special->target->z, MT_BOOMEXPLODE); - UINT8 ptadd = (K_IsPlayerWanted(player) ? 2 : 1); + mobj_t *boom; + + if (P_DamageMobj(toucher, special, special->target, 1, DMG_KARMA) == false) + { + return; + } + + boom = P_SpawnMobj(special->target->x, special->target->y, special->target->z, MT_BOOMEXPLODE); boom->scale = special->target->scale; boom->destscale = special->target->scale; boom->momz = 5*FRACUNIT; + if (special->target->color) boom->color = special->target->color; else boom->color = SKINCOLOR_KETCHUP; + S_StartSound(boom, special->info->attacksound); - if (player->kartstuff[k_bumper] == 1) // If you have only one bumper left, and see if it's a 1v1 - { - INT32 numingame = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator || players[i].kartstuff[k_bumper] <= 0) - continue; - numingame++; - } - - if (numingame <= 2) // If so, then an extra karma point so they are 100% certain to switch places; it's annoying to end matches with a bomb kill - ptadd++; - } - - special->target->player->kartstuff[k_comebackpoints] += ptadd; - - if (ptadd > 1) - special->target->player->karthud[khud_yougotem] = 2*TICRATE; - - if (special->target->player->kartstuff[k_comebackpoints] >= 2) - K_StealBumper(special->target->player, player); - - special->target->player->kartstuff[k_comebacktimer] = comebacktime; - - P_DamageMobj(toucher, special, special->target, 1, DMG_EXPLODE); + special->target->player->karthud[khud_yougotem] = 2*TICRATE; + special->target->player->karmadelay = comebacktime; } +#ifdef OTHERKARMAMODES } else if (special->target->player->kartstuff[k_comebackmode] == 1 && P_CanPickupItem(player, 1)) { @@ -349,8 +349,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->kartstuff[k_comebackpoints]++; if (special->target->player->kartstuff[k_comebackpoints] >= 2) - K_StealBumper(special->target->player, player); - special->target->player->kartstuff[k_comebacktimer] = comebacktime; + K_StealBumper(special->target->player, player, 1); + special->target->player->karmadelay = comebacktime; player->kartstuff[k_itemroulette] = 1; player->kartstuff[k_roulettetype] = 1; @@ -362,13 +362,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) S_StartSound(poof, special->info->seesound); - if (player->kartstuff[k_bumper] == 1) // If you have only one bumper left, and see if it's a 1v1 + if (player->bumpers == 1) // If you have only one bumper left, and see if it's a 1v1 { INT32 numingame = 0; for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i] || players[i].spectator || players[i].kartstuff[k_bumper] <= 0) + if (!playeringame[i] || players[i].spectator || players[i].bumpers <= 0) continue; numingame++; } @@ -384,9 +384,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->karthud[khud_yougotem] = 2*TICRATE; if (special->target->player->kartstuff[k_comebackpoints] >= 2) - K_StealBumper(special->target->player, player); + K_StealBumper(special->target->player, player, 1); - special->target->player->kartstuff[k_comebacktimer] = comebacktime; + special->target->player->karmadelay = comebacktime; K_DropItems(player); //K_StripItems(player); //K_StripOther(player); @@ -404,6 +404,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->kartstuff[k_eggmanblame] = -1; } +#endif return; case MT_SPB: if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0)) @@ -441,10 +442,25 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_DamageMobj(player->mo, special, special->target, 1, DMG_NORMAL); } return; - /*case MT_EERIEFOG: + case MT_EMERALD: + if (!P_CanPickupItem(player, 0)) + return; + + if (special->threshold > 0) + return; + + if (toucher->hitlag > 0) + return; + + player->powers[pw_emeralds] |= special->extravalue1; + K_CheckEmeralds(player); + break; + /* + case MT_EERIEFOG: special->frame &= ~FF_TRANS80; special->frame |= FF_TRANS90; - return;*/ + return; + */ case MT_SMK_MOLE: if (special->target && !P_MobjWasRemoved(special->target)) return; @@ -473,7 +489,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) S_StartSound(special, sfx_s1a2); return; case MT_CDUFO: // SRB2kart - if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0)) + if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)) return; player->kartstuff[k_itemroulette] = 1; @@ -552,6 +568,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; + case MT_BLUESPHERE: + if (!(P_CanPickupItem(player, 0))) + return; + + // Reached the cap, don't waste 'em! + if (player->spheres >= 40) + return; + + // Not alive + if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0)) + return; + + special->momx = special->momy = special->momz = 0; + player->spheres++; + break; + // Secret emblem thingy case MT_EMBLEM: { @@ -713,7 +745,7 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost) } // Easily make it so that overtime works offline -//#define TESTOVERTIMEINFREEPLAY +#define TESTOVERTIMEINFREEPLAY /** Checks if the level timer is over the timelimit and the round should end, * unless you are in overtime. In which case leveltime may stretch out beyond @@ -730,11 +762,10 @@ void P_CheckTimeLimit(void) if (!cv_timelimit.value) return; - if (!(multiplayer || netgame)) - return; - +#ifndef TESTOVERTIMEINFREEPLAY if (battlecapsules) // capsules override any time limit settings return; +#endif if (!(gametyperules & GTR_TIMELIMIT)) return; @@ -753,58 +784,53 @@ void P_CheckTimeLimit(void) { if (!playeringame[i] || players[i].spectator) continue; + if (foundone) { #endif // Initiate the kill zone if (!battleovertime.enabled) { - INT32 b = 0; thinker_t *th; - mobj_t *item = NULL; + mobj_t *center = NULL; - P_RespawnBattleBoxes(); // FORCE THESE TO BE RESPAWNED FOR THIS!!!!!!! - - // Find us an item box to center on. for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { mobj_t *thismo; + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; + thismo = (mobj_t *)th; - if (thismo->type != MT_RANDOMITEM) - continue; - if (thismo->threshold == 69) // Disappears - continue; - - b++; - - // Only select items that are on the ground, ignore ones in the air. Ambush flag inverts this rule. - if ((!P_IsObjectOnGround(thismo)) != (thismo->flags2 & MF2_AMBUSH)) - continue; - - if (item == NULL || (b < nummapboxes && P_RandomChance(((nummapboxes-b)*FRACUNIT)/nummapboxes))) // This is to throw off the RNG some - item = thismo; - if (b >= nummapboxes) // end early if we've found them all already + if (thismo->type == MT_OVERTIME_CENTER) + { + center = thismo; break; + } } - if (item == NULL) // no item found, could happen if every item is in the air or has ambush flag, or the map has none + if (center == NULL || P_MobjWasRemoved(center)) { - CONS_Alert(CONS_WARNING, "No usuable items for Battle overtime!\n"); - return; + CONS_Alert(CONS_WARNING, "No center point for overtime!\n"); + + battleovertime.x = 0; + battleovertime.y = 0; + battleovertime.z = 0; + } + else + { + battleovertime.x = center->x; + battleovertime.y = center->y; + battleovertime.z = center->z; } - item->threshold = 70; // Set constant respawn - battleovertime.x = item->x; - battleovertime.y = item->y; - battleovertime.z = item->z; - battleovertime.radius = 4096*mapobjectscale; - battleovertime.minradius = (cv_overtime.value == 2 ? 40 : 512) * mapobjectscale; + battleovertime.radius = 4096 * mapobjectscale; battleovertime.enabled = 1; + S_StartSound(NULL, sfx_kc47); } + return; #ifndef TESTOVERTIMEINFREEPLAY } @@ -1038,12 +1064,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { mobj_t *mo; - //if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL)) - // P_SetTarget(&target->tracer, inflictor); - - if (G_IsSpecialStage(gamemap) && target->player && target->player->nightstime > 6) - target->player->nightstime = 6; // Just let P_Ticker take care of the rest. - if (target->flags & (MF_ENEMY|MF_BOSS)) target->momx = target->momy = target->momz = 0; @@ -1069,7 +1089,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SPECIAL); target->flags2 &= ~(MF2_SKULLFLY|MF2_NIGHTSPULL); target->health = 0; // This makes it easy to check if something's dead elsewhere. - target->shadowscale = 0; + + if (target->type != MT_BATTLEBUMPER) + { + target->shadowscale = 0; + } if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target)) return; @@ -1192,10 +1216,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } } - if ((gametyperules & GTR_BUMPERS)) + if (gametyperules & GTR_BUMPERS) K_CheckBumpers(); - target->player->kartstuff[k_pogospring] = 0; + target->player->trickpanel = 0; } if (source && target && target->player && source->player) @@ -1422,6 +1446,35 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget } break; + case MT_BATTLEBUMPER: + { + mobj_t *owner = target->target; + mobj_t *overlay; + + S_StartSound(target, sfx_kc52); + target->flags &= ~MF_NOGRAVITY; + + target->destscale = (3 * target->destscale) / 2; + target->scalespeed = FRACUNIT/100; + + if (owner && !P_MobjWasRemoved(owner)) + { + P_Thrust(target, R_PointToAngle2(owner->x, owner->y, target->x, target->y), 4 * target->scale); + } + + target->momz += (24 * target->scale) * P_MobjFlip(target); + target->fuse = 8; + + overlay = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_OVERLAY); + + P_SetTarget(&target->tracer, overlay); + P_SetTarget(&overlay->target, target); + + overlay->color = target->color; + P_SetMobjState(overlay, S_INVISIBLE); + } + break; + default: break; } @@ -1658,7 +1711,7 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, return false; } - K_RemoveBumper(player, NULL, NULL); + K_DestroyBumpers(player, 1); switch (type) { @@ -1671,14 +1724,12 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, break; } + K_DropEmeraldsFromPlayer(player, player->powers[pw_emeralds]); K_SetHitLagForObjects(player->mo, inflictor, 15); player->pflags &= ~PF_SLIDING; player->powers[pw_carry] = CR_NONE; - // Get rid of shield - player->powers[pw_shield] = SH_NONE; - player->mo->color = player->skincolor; player->mo->colorized = false; @@ -1693,15 +1744,21 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, if (type == DMG_TIMEOVER) { - mobj_t *boom; + if (gametyperules & GTR_CIRCUIT) + { + mobj_t *boom; - player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP); - player->mo->drawflags |= MFD_DONTDRAW; + player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP); + player->mo->drawflags |= MFD_DONTDRAW; - boom = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FZEROBOOM); - boom->scale = player->mo->scale; - boom->angle = player->mo->angle; - P_SetTarget(&boom->target, player->mo); + boom = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FZEROBOOM); + boom->scale = player->mo->scale; + boom->angle = player->mo->angle; + P_SetTarget(&boom->target, player->mo); + } + + K_DestroyBumpers(player, player->bumpers); + player->eliminated = true; } return true; @@ -1796,8 +1853,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (!(target->flags & MF_SHOOTABLE)) return false; // shouldn't happen... - // Make sure that boxes cannot be popped by enemies, red rings, etc. - if (target->flags & MF_MONITOR && ((!source || !source->player) || (inflictor && !inflictor->player))) + if (target->hitlag > 0) return false; } @@ -1821,7 +1877,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player) // Player is the target { const UINT8 type = (damagetype & DMG_TYPEMASK); - const boolean combo = (type == DMG_EXPLODE || type == DMG_TUMBLE); // This damage type can be comboed from other damage + const boolean combo = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can be comboed from other damage INT16 ringburst = 5; if (player->pflags & PF_GODMODE) @@ -1855,9 +1911,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { if (gametyperules & GTR_BUMPERS) { - if ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1) + if ((player->bumpers <= 0 && player->karmadelay) || (player->kartstuff[k_comebackmode] == 1)) { - // No bumpers, can't be hurt + // No bumpers & in WAIT, can't be hurt K_DoInstashield(player); return false; } @@ -1890,20 +1946,60 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } } - // We successfully hit 'em! + // We successfully damaged them! Give 'em some bumpers! if (type != DMG_STING) { + UINT8 takeBumpers = 1; + + if (damagetype & DMG_STEAL) + { + takeBumpers = 2; + + if (type == DMG_KARMA) + { + takeBumpers = player->bumpers; + } + } + else + { + if (type == DMG_KARMA) + { + // Take half of their bumpers for karma comeback damage + takeBumpers = max(1, player->bumpers / 2); + } + } + if (source && source != player->mo && source->player) { K_PlayHitEmSound(source); + K_BattleAwardHit(source->player, player, inflictor, takeBumpers); + K_TakeBumpersFromPlayer(source->player, player, takeBumpers); + + if (type == DMG_KARMA) + { + // Destroy any remainder bumpers from the player for karma comeback damage + K_DestroyBumpers(player, player->bumpers); + } + if (damagetype & DMG_STEAL) { - K_StealBumper(source->player, player); + // Give them ALL of your emeralds instantly :) + source->player->powers[pw_emeralds] |= player->powers[pw_emeralds]; + player->powers[pw_emeralds] = 0; + K_CheckEmeralds(source->player); } } + else + { + K_DestroyBumpers(player, takeBumpers); + } - K_RemoveBumper(player, inflictor, source); + if (!(damagetype & DMG_STEAL)) + { + // Drop all of your emeralds + K_DropEmeraldsFromPlayer(player, player->powers[pw_emeralds]); + } } player->kartstuff[k_sneakertimer] = player->kartstuff[k_numsneakers] = 0; @@ -1921,6 +2017,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da K_TumblePlayer(player, inflictor, source); break; case DMG_EXPLODE: + case DMG_KARMA: K_ExplodePlayer(player, inflictor, source); break; case DMG_WIPEOUT: @@ -1936,11 +2033,17 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } if (type != DMG_STING) + { player->powers[pw_flashing] = K_GetKartFlashing(player); + } P_PlayRinglossSound(player->mo); + if (ringburst > 0) + { P_PlayerRingBurst(player, ringburst); + } + K_PlayPainSound(player->mo); if ((combo == true) || (cv_kartdebughuddrop.value && !modeattacking)) @@ -2017,7 +2120,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) fixed_t momxy = 5<eflags & MFE_SPRUNG) break; + if (object->player) - object->player->kartstuff[k_pogospring] = 1; - K_DoPogoSpring(object, 0, 0); + { + object->player->trickpanel = 1; + object->player->trickdelay = 1; + } + + K_DoPogoSpring(object, 32<player->kartstuff[k_bumper] && !tmthing->player->kartstuff[k_bumper]) - || (tmthing->player->kartstuff[k_bumper] && !thing->player->kartstuff[k_bumper]))) + && ((thing->player->bumpers && !tmthing->player->bumpers) + || (tmthing->player->bumpers && !thing->player->bumpers))) { return true; } @@ -1283,14 +1288,14 @@ static boolean PIT_CheckThing(mobj_t *thing) mo1 = thing; mo2 = tmthing; - if (tmthing->player->kartstuff[k_pogospring]) + if (tmthing->player->trickpanel) P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL); } else if (P_IsObjectOnGround(tmthing) && thing->momz < 0) { zbounce = true; - if (thing->player->kartstuff[k_pogospring]) + if (thing->player->trickpanel) P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL); } @@ -1565,6 +1570,23 @@ static boolean PIT_CheckCameraLine(line_t *ld) return true; } +boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing) +{ + // missiles can cross uncrossable lines + if ((thing->flags & MF_MISSILE)) + return false; + else + { + return + ( + (ld->flags & ML_IMPASSABLE) || // block objects from moving through this linedef. + (thing->player && !thing->player->spectator && + ld->flags & ML_BLOCKPLAYERS) || // SRB2Kart: Only block players, not items + ((thing->flags & (MF_ENEMY|MF_BOSS)) && ld->special == 81) // case 81: block monsters only + ); + } +} + // // PIT_CheckLine // Adjusts tmfloorz and tmceilingz as lines are contacted @@ -1640,14 +1662,8 @@ static boolean PIT_CheckLine(line_t *ld) return false; } - // missiles can cross uncrossable lines - if (!(tmthing->flags & MF_MISSILE)) - { - if (ld->flags & ML_IMPASSABLE) // block objects from moving through this linedef. - return false; - if (tmthing->player && !tmthing->player->spectator && ld->flags & ML_BLOCKPLAYERS) - return false; // SRB2Kart: Only block players, not items - } + if (P_IsLineBlocking(ld, tmthing)) + return false; // set openrange, opentop, openbottom P_LineOpening(ld, tmthing); @@ -2216,7 +2232,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) { subsector_t *s = R_PointInSubsector(x, y); boolean retval = true; - + UINT8 i; floatok = false; @@ -2588,9 +2604,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->momz <= 0) { thing->standingslope = tmfloorslope; -#ifdef HWRENDER - thing->modeltilt = thing->standingslope; -#endif + P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->momz == 0 && thing->player && !startingonground) P_PlayerHitFloor(thing->player, true); @@ -2603,9 +2617,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->momz >= 0) { thing->standingslope = tmceilingslope; -#ifdef HWRENDER - thing->modeltilt = thing->standingslope; -#endif + P_SetPitchRollFromSlope(thing, thing->standingslope); if (thing->momz == 0 && thing->player && !startingonground) P_PlayerHitFloor(thing->player, true); @@ -3117,14 +3129,8 @@ static boolean PTR_LineIsBlocking(line_t *li) if (!li->backsector) return !P_PointOnLineSide(slidemo->x, slidemo->y, li); - if (!(slidemo->flags & MF_MISSILE)) - { - if (li->flags & ML_IMPASSABLE) - return true; - - if (slidemo->player && !slidemo->player->spectator && li->flags & ML_BLOCKPLAYERS) - return true; - } + if (P_IsLineBlocking(li, slidemo)) + return true; // set openrange, opentop, openbottom P_LineOpening(li, slidemo); @@ -3611,7 +3617,7 @@ void P_BouncePlayerMove(mobj_t *mo) mmomx = mo->player->rmomx; mmomy = mo->player->rmomy; - mo->player->kartstuff[k_pogospring] = 0; + mo->player->trickpanel = 0; // trace along the three leading corners if (mo->momx > 0) diff --git a/src/p_mobj.c b/src/p_mobj.c index 403bd82d6..2cbabfd9a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1096,16 +1096,16 @@ fixed_t P_GetMobjGravity(mobj_t *mo) P_PlayerFlip(mo); } - if (mo->player->kartstuff[k_pogospring]) - { - gravityadd = (5*gravityadd)/2; - } - if (mo->player->kartstuff[k_waterskip]) { gravityadd = (4*gravityadd)/3; } + if (mo->player->trickpanel == 2 || mo->player->trickpanel == 3) + { + gravityadd = (5*gravityadd)/2; + } + if (mo->player->tumbleBounces > 0) { gravityadd = (5*gravityadd)/2; @@ -1135,7 +1135,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_FLINGCOIN: case MT_FLINGBLUESPHERE: case MT_FLINGNIGHTSCHIP: - case MT_FLINGEMERALD: case MT_BOUNCERING: case MT_RAILRING: case MT_INFINITYRING: @@ -1163,6 +1162,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) break; case MT_WATERDROP: case MT_CYBRAKDEMON: + case MT_BATTLEBUMPER: gravityadd /= 2; break; case MT_BANANA: @@ -1170,12 +1170,12 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_SSMINE: case MT_LANDMINE: case MT_SINK: + case MT_EMERALD: if (mo->extravalue2 > 0) + { gravityadd *= mo->extravalue2; - /* FALLTHRU */ - case MT_ORBINAUT: - case MT_JAWZ: - case MT_JAWZ_DUD: + } + gravityadd = (5*gravityadd)/2; break; case MT_KARMAFIREWORK: @@ -1222,6 +1222,26 @@ void P_CheckGravity(mobj_t *mo, boolean affect) } } +// +// P_SetPitchRollFromSlope +// +void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope) +{ + if (slope) + { + fixed_t tempz = slope->normal.z; + fixed_t tempy = slope->normal.y; + fixed_t tempx = slope->normal.x; + + mo->pitch = R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx); + mo->roll = R_PointToAngle2(0, 0, tempz, tempy); + } + else + { + mo->pitch = mo->roll = 0; + } +} + #define STOPSPEED (FRACUNIT) // @@ -1716,9 +1736,7 @@ void P_XYMovement(mobj_t *mo) // Now compare the Zs of the different quantizations if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later mo->standingslope = oldslope; -#ifdef HWRENDER - mo->modeltilt = mo->standingslope; -#endif + P_SetPitchRollFromSlope(mo, mo->standingslope); P_SlopeLaunch(mo); //CONS_Printf("launched off of slope - "); @@ -2102,6 +2120,7 @@ boolean P_ZMovement(mobj_t *mo) return false; } break; + case MT_REDFLAG: case MT_BLUEFLAG: // Remove from death pits. DON'T FUCKING DESPAWN IT DAMMIT @@ -2112,19 +2131,23 @@ boolean P_ZMovement(mobj_t *mo) } break; + case MT_EMERALD: + if (P_CheckDeathPitCollide(mo)) + { + P_RemoveMobj(mo); + return false; + } + + if (mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz) + { + // Stop when hitting the floor + mo->momx = mo->momy = 0; + } + break; + case MT_RING: // Ignore still rings - case MT_COIN: case MT_BLUESPHERE: - case MT_BOMBSPHERE: - case MT_NIGHTSCHIP: - case MT_NIGHTSSTAR: - case MT_REDTEAMRING: - case MT_BLUETEAMRING: case MT_FLINGRING: - case MT_FLINGCOIN: - case MT_FLINGBLUESPHERE: - case MT_FLINGNIGHTSCHIP: - case MT_FLINGEMERALD: // Remove flinged stuff from death pits. if (P_CheckDeathPitCollide(mo)) { @@ -2237,9 +2260,7 @@ boolean P_ZMovement(mobj_t *mo) if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM)) { mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope; -#ifdef HWRENDER - mo->modeltilt = mo->standingslope; -#endif + P_SetPitchRollFromSlope(mo, mo->standingslope); P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope); } @@ -5285,7 +5306,117 @@ static void P_MobjSceneryThink(mobj_t *mobj) } break; case MT_BATTLEBUMPER: - if (mobj->health > 0 && mobj->target && mobj->target->player + if (mobj->health <= 0) + { + mobj->fuse--; + + if (!S_SoundPlaying(mobj, sfx_cdfm71)) + { + S_StartSound(mobj, sfx_cdfm71); + } + + if (mobj->fuse <= 0) + { + statenum_t curState = (mobj->state - states); + + if (curState == S_BATTLEBUMPER1) + { + P_SetMobjState(mobj, S_BATTLEBUMPER_EXCRYSTALA1); + + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) + { + P_SetMobjState(mobj->tracer, S_BATTLEBUMPER_EXSHELLA1); + } + + mobj->shadowscale *= 2; + mobj->fuse = 12; + } + else if (curState >= S_BATTLEBUMPER_EXCRYSTALA1 && curState <= S_BATTLEBUMPER_EXCRYSTALA4) + { + P_SetMobjState(mobj, S_BATTLEBUMPER_EXCRYSTALB1); + + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) + { + P_SetMobjState(mobj->tracer, S_BATTLEBUMPER_EXSHELLB1); + } + + mobj->shadowscale *= 2; + mobj->fuse = 24; + break; + } + else if (curState >= S_BATTLEBUMPER_EXCRYSTALB1 && curState <= S_BATTLEBUMPER_EXCRYSTALB4) + { + P_SetMobjState(mobj, S_BATTLEBUMPER_EXCRYSTALC1); + + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) + { + P_SetMobjState(mobj->tracer, S_BATTLEBUMPER_EXSHELLC1); + } + + mobj->shadowscale *= 2; + mobj->fuse = 32; + break; + } + else + { + const INT16 spacing = 64; + UINT8 i; + + for (i = 0; i < 10; i++) + { + mobj_t *debris = P_SpawnMobjFromMobj( + mobj, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + MT_BATTLEBUMPER_DEBRIS + ); + + P_SetScale(debris, (debris->destscale *= 2)); + debris->color = mobj->color; + + debris->momz = -debris->scale * P_MobjFlip(debris); + } + + for (i = 0; i < 2; i++) + { + mobj_t *blast = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BATTLEBUMPER_BLAST); + + blast->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy) + ANGLE_45; + blast->destscale *= 4; + + if (i & 1) + { + blast->angle += ANGLE_90; + S_StartSound(blast, sfx_cdfm64); + } + } + + for (i = 0; i < 10; i++) + { + mobj_t *puff = P_SpawnMobjFromMobj( + mobj, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + MT_SPINDASHDUST + ); + + P_SetScale(puff, (puff->destscale *= 5)); + puff->momz = puff->scale * P_MobjFlip(puff); + + P_Thrust(puff, R_PointToAngle2(mobj->x, mobj->y, puff->x, puff->y), puff->scale); + } + + P_RemoveMobj(mobj); + return; + } + } + + break; + } + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player && mobj->target->health > 0 && !mobj->target->player->spectator) { fixed_t rad = 32*mobj->target->scale; @@ -5293,14 +5424,14 @@ static void P_MobjSceneryThink(mobj_t *mobj) angle_t ang, diff; if (!((mobj->target->player-players) & 1)) - ang = (FixedAngle(mobj->info->speed) * -1); + ang = -FixedAngle(mobj->info->speed); else ang = FixedAngle(mobj->info->speed); - if (mobj->target->player->kartstuff[k_bumper] <= 1) + if (mobj->target->player->bumpers <= 1) diff = 0; else - diff = FixedAngle(360*FRACUNIT/mobj->target->player->kartstuff[k_bumper]); + diff = FixedAngle(360*FRACUNIT/mobj->target->player->bumpers); ang = (ang*leveltime) + (diff * (mobj->threshold-1)); @@ -5319,51 +5450,66 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->drawflags = (mobj->target->drawflags & MFD_DONTDRAW); if (mobj->target->eflags & MFE_VERTICALFLIP) + { offz += 4*FRACUNIT; + } else + { offz -= 4*FRACUNIT; + } - if (mobj->tracer && mobj->tracer->player && mobj->tracer->player->mo + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer) && mobj->tracer->player && mobj->tracer->health > 0 && !mobj->tracer->player->spectator) // STOLEN - mobj->color = mobj->tracer->player->skincolor; // don't do star flashing for stolen bumpers + { + mobj->color = mobj->tracer->color; + } else - mobj->color = mobj->target->color; // but do so if it belongs to you :B + { + mobj->color = mobj->target->color; + } - if (mobj->target->player->kartstuff[k_bumper] < 2) + if (mobj->target->player->bumpers < 2) P_SetMobjState(mobj, S_BATTLEBUMPER3); - else if (mobj->target->player->kartstuff[k_bumper] < 3) + else if (mobj->target->player->bumpers < 3) P_SetMobjState(mobj, S_BATTLEBUMPER2); else P_SetMobjState(mobj, S_BATTLEBUMPER1); // Shrink your items if the player shrunk too. - mobj->scale = mobj->target->scale; + P_SetScale(mobj, mobj->target->scale); P_UnsetThingPosition(mobj); { - const angle_t fa = ang>>ANGLETOFINESHIFT; + const angle_t fa = ang >> ANGLETOFINESHIFT; mobj->x = mobj->target->x + FixedMul(FINECOSINE(fa), rad); mobj->y = mobj->target->y + FixedMul(FINESINE(fa), rad); mobj->z = mobj->target->z + offz; P_SetThingPosition(mobj); } - // Was this so hard? - if (mobj->target->player->kartstuff[k_bumper] <= mobj->threshold) + if (mobj->target->player->bumpers <= mobj->threshold) { - P_RemoveMobj(mobj); - return; + // Do bumper destruction + P_KillMobj(mobj, NULL, NULL, DMG_NORMAL); + break; } } - else if ((mobj->health > 0 - && (!mobj->target || !mobj->target->player || !mobj->target->player->mo || mobj->target->health <= 0 || mobj->target->player->spectator)) - || (mobj->health <= 0 && P_IsObjectOnGround(mobj)) - || P_CheckDeathPitCollide(mobj)) // When in death state + else { + // Sliently remove P_RemoveMobj(mobj); return; } + break; + + case MT_BATTLEBUMPER_DEBRIS: + if (mobj->state == states + S_BATTLEBUMPER_EXDEBRIS2) + { + mobj->drawflags ^= MFD_DONTDRAW; + } + break; + case MT_PLAYERARROW: if (mobj->target && mobj->target->health && mobj->target->player && !mobj->target->player->spectator @@ -5374,7 +5520,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->color = mobj->target->color; K_MatchGenericExtraFlags(mobj, mobj->target); - if ((gametype == GT_RACE || mobj->target->player->kartstuff[k_bumper] <= 0) + if ((gametype == GT_RACE || mobj->target->player->bumpers <= 0) #if 1 // Set to 0 to test without needing to host || (P_IsDisplayPlayer(mobj->target->player)) #endif @@ -6206,6 +6352,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true)) K_DoPogoSpring(mobj, 0, 1); + if (!(gametyperules & GTR_CIRCUIT)) + mobj->friction = max(0, 3 * mobj->friction / 4); + break; } case MT_JAWZ_DUD: @@ -6357,7 +6506,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) ghost->colorized = true; // already has color! } - if (P_IsObjectOnGround(mobj) && (mobj->state == &states[S_SSMINE_AIR1] || mobj->state == &states[S_SSMINE_AIR2])) + if (P_IsObjectOnGround(mobj) && (mobj->momz * P_MobjFlip(mobj)) <= 0 + && (mobj->state == &states[S_SSMINE_AIR1] || mobj->state == &states[S_SSMINE_AIR2])) { if (mobj->extravalue1 > 0) mobj->extravalue1--; @@ -6426,6 +6576,37 @@ static boolean P_MobjRegularThink(mobj_t *mobj) S_StartSound(mobj, sfx_s3k4e); mobj->health--; break; + case MT_EMERALD: + { + if (battleovertime.enabled >= 10*TICRATE) + { + fixed_t distance = R_PointToDist2(mobj->x, mobj->y, battleovertime.x, battleovertime.y); + + if (distance > battleovertime.radius) + { + // Delete emeralds to let them reappear + P_KillMobj(mobj, NULL, NULL, DMG_NORMAL); + } + } + + if (leveltime % 3 == 0) + { + mobj_t *sparkle = P_SpawnMobjFromMobj( + mobj, + P_RandomRange(-48, 48) * FRACUNIT, + P_RandomRange(-48, 48) * FRACUNIT, + P_RandomRange(0, 64) * FRACUNIT, + MT_EMERALDSPARK + ); + + sparkle->color = mobj->color; + sparkle->momz += 8 * mobj->scale * P_MobjFlip(mobj); + } + + if (mobj->threshold > 0) + mobj->threshold--; + } + break; case MT_DRIFTEXPLODE: if (!mobj->target || !mobj->target->health) { @@ -6457,9 +6638,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->target->z); } P_SetScale(mobj, mobj->target->scale); -#ifdef HWRENDER - mobj->modeltilt = mobj->target->modeltilt; -#endif + + mobj->roll = mobj->target->roll; + mobj->pitch = mobj->target->pitch; if (mobj->fuse <= 16) { @@ -6473,7 +6654,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->color = K_RainbowColor( (SKINCOLOR_PURPLE - SKINCOLOR_PINK) // Smoothly transition into the other state + ((mobj->fuse - 32) * 2) // Make the color flashing slow down while it runs out - ); + ); switch (mobj->extravalue1) { @@ -6521,9 +6702,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) P_TeleportMove(mobj, mobj->target->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z); P_SetScale(mobj, mobj->target->scale); -#ifdef HWRENDER - mobj->modeltilt = mobj->target->modeltilt; -#endif + + mobj->roll = mobj->target->roll; + mobj->pitch = mobj->target->pitch; { player_t *p = NULL; @@ -7047,7 +7228,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) statenum_t state = (mobj->state-states); if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator - || (gametype == GT_RACE || mobj->target->player->kartstuff[k_bumper])) + || (gametype == GT_RACE || mobj->target->player->bumpers)) { P_RemoveMobj(mobj); return false; @@ -7068,11 +7249,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->radius = 24*mobj->target->scale; mobj->height = 2*mobj->radius; - if (mobj->target->player->kartstuff[k_comebacktimer] > 0) + if (mobj->target->player->karmadelay > 0) { if (state < S_PLAYERBOMB1 || state > S_PLAYERBOMB20) P_SetMobjState(mobj, S_PLAYERBOMB1); - if (mobj->target->player->kartstuff[k_comebacktimer] < TICRATE && (leveltime & 1)) + if (mobj->target->player->karmadelay < TICRATE && (leveltime & 1)) mobj->drawflags &= ~MFD_DONTDRAW; else mobj->drawflags |= MFD_DONTDRAW; @@ -8379,6 +8560,7 @@ static boolean P_FuseThink(mobj_t *mobj) if (mobj->threshold == 70) newmobj->threshold = 70; } + P_RemoveMobj(mobj); // make sure they disappear return false; case MT_SMK_ICEBLOCK: @@ -8425,12 +8607,6 @@ void P_MobjThinker(mobj_t *mobj) I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); - if (mobj->flags & MF_NOTHINK) - return; - - if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<spawnpoint->extrainfo))) - return; - // Remove dead target/tracer. if (mobj->target && P_MobjWasRemoved(mobj->target)) P_SetTarget(&mobj->target, NULL); @@ -8441,6 +8617,12 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) P_SetTarget(&mobj->hprev, NULL); + if (mobj->flags & MF_NOTHINK) + return; + + if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<spawnpoint->extrainfo))) + return; + // Don't run any thinker code while in hitlag if (mobj->hitlag > 0) { @@ -8610,7 +8792,7 @@ void P_MobjThinker(mobj_t *mobj) || mobj->type == MT_FLINGCOIN || mobj->type == MT_FLINGBLUESPHERE || mobj->type == MT_FLINGNIGHTSCHIP - || mobj->type == MT_FLINGEMERALD + || mobj->type == MT_EMERALD || mobj->type == MT_BIGTUMBLEWEED || mobj->type == MT_LITTLETUMBLEWEED || mobj->type == MT_CANNONBALLDECOR @@ -8943,6 +9125,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) break; case MT_RING: case MT_FLOATINGITEM: + case MT_BLUESPHERE: + case MT_EMERALD: thing->shadowscale = FRACUNIT/2; break; case MT_DRIFTCLIP: @@ -9234,8 +9418,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->color = skincolor_blueteam; break; case MT_RING: - case MT_COIN: - case MT_NIGHTSSTAR: if (nummaprings >= 0) nummaprings++; break; @@ -9593,10 +9775,7 @@ void P_RemoveMobj(mobj_t *mobj) // Rings only, please! if (mobj->spawnpoint && (mobj->type == MT_RING - || mobj->type == MT_COIN - || mobj->type == MT_NIGHTSSTAR - || mobj->type == MT_REDTEAMRING - || mobj->type == MT_BLUETEAMRING) + || mobj->type == MT_BLUESPHERE) && !(mobj->flags2 & MF2_DONTRESPAWN)) { itemrespawnque[iquehead] = mobj->spawnpoint; @@ -9995,11 +10174,11 @@ mobjtype_t P_GetMobjtype(UINT16 mthingtype) void P_RespawnSpecials(void) { UINT8 p, pcount = 0; - tic_t time = 30*TICRATE; // Respawn things in empty dedicated servers + INT32 time = 30*TICRATE; // Respawn things in empty dedicated servers mapthing_t *mthing = NULL; - if (!(gametyperules & GTR_CIRCUIT) && numgotboxes >= (4*nummapboxes/5)) // Battle Mode respawns all boxes in a different way - P_RespawnBattleBoxes(); + //if (!(gametyperules & GTR_CIRCUIT) && numgotboxes >= (4*nummapboxes/5)) // Battle Mode respawns all boxes in a different way + //P_RespawnBattleBoxes(); // wait time depends on player count for (p = 0; p < MAXPLAYERS; p++) @@ -10008,22 +10187,33 @@ void P_RespawnSpecials(void) pcount++; } - if (pcount == 1) // No respawn when alone - return; - else if (pcount > 1) + if (gametyperules & GTR_SPHERES) { - time = (120 - ((pcount-2) * 10))*TICRATE; + if (pcount > 2) + time -= (5*TICRATE) * (pcount-2); - // If the map is longer or shorter than 3 laps, then adjust ring respawn to account for this. - // 5 lap courses would have more retreaded ground, while 2 lap courses would have less. - if ((mapheaderinfo[gamemap-1]->numlaps != 3) - && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)) - time = (time * 3) / max(1, mapheaderinfo[gamemap-1]->numlaps); - - if (time < 10*TICRATE) + if (time < 5*TICRATE) + time = 5*TICRATE; + } + else + { + if (pcount == 1) // No respawn when alone + return; + else if (pcount > 1) { - // Ensure it doesn't go into absurdly low values - time = 10*TICRATE; + time = (120 - ((pcount-2) * 10)) * TICRATE; + + // If the map is longer or shorter than 3 laps, then adjust ring respawn to account for this. + // 5 lap courses would have more retreaded ground, while 2 lap courses would have less. + if ((mapheaderinfo[gamemap-1]->numlaps != 3) + && !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE)) + time = (time * 3) / max(1, mapheaderinfo[gamemap-1]->numlaps); + + if (time < 10*TICRATE) + { + // Ensure it doesn't go into absurdly low values + time = 10*TICRATE; + } } } @@ -10032,7 +10222,7 @@ void P_RespawnSpecials(void) return; // the first item in the queue is the first to respawn - if (leveltime - itemrespawntime[iquetail] < time) + if (leveltime - itemrespawntime[iquetail] < (tic_t)time) return; mthing = itemrespawnque[iquetail]; @@ -10084,7 +10274,7 @@ void P_SpawnPlayer(INT32 playernum) /* if (bonusgame || specialstage) { - // Bots should avoid + // Bots should avoid p->spectator = true; } */ @@ -10181,30 +10371,35 @@ void P_SpawnPlayer(INT32 playernum) P_SetScale(mobj, mobj->destscale); P_FlashPal(p, 0, 0); // Resets - if ((gametyperules & GTR_BUMPERS)) // SRB2kart + if (gametyperules & GTR_BUMPERS) { mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW); P_SetTarget(&overheadarrow->target, mobj); overheadarrow->drawflags |= MFD_DONTDRAW; P_SetScale(overheadarrow, mobj->destscale); - if (p->spectator && pcount > 1) // HEY! No being cheap... - p->kartstuff[k_bumper] = 0; - else if (p->kartstuff[k_bumper] > 0 || leveltime < 1 - || (p->jointime <= 1 && pcount <= 1)) + if (p->spectator) { - if (leveltime < 1 || (p->jointime <= 1 && pcount <= 1)) // Start of the map? - p->kartstuff[k_bumper] = K_StartingBumperCount(); // Reset those bumpers! - - if (p->kartstuff[k_bumper]) + // HEY! No being cheap... + p->bumpers = 0; + } + else if ((p->bumpers > 0) || (leveltime < starttime) || (pcount <= 1)) + { + if ((leveltime < starttime) || (pcount <= 1)) // Start of the map? { - angle_t diff = FixedAngle(360*FRACUNIT/p->kartstuff[k_bumper]); + // Reset those bumpers! + p->bumpers = K_StartingBumperCount(); + } + + if (p->bumpers) + { + angle_t diff = FixedAngle(360*FRACUNIT/p->bumpers); angle_t newangle = mobj->angle; fixed_t newx = mobj->x + P_ReturnThrustX(mobj, newangle + ANGLE_180, 64*FRACUNIT); fixed_t newy = mobj->y + P_ReturnThrustY(mobj, newangle + ANGLE_180, 64*FRACUNIT); mobj_t *mo; - for (i = 0; i < p->kartstuff[k_bumper]; i++) + for (i = 0; i < p->bumpers; i++) { mo = P_SpawnMobj(newx, newy, mobj->z, MT_BATTLEBUMPER); mo->threshold = i; @@ -10218,7 +10413,7 @@ void P_SpawnPlayer(INT32 playernum) } } } - else if (p->kartstuff[k_bumper] <= 0) + else if (p->bumpers <= 0) { mobj_t *karmahitbox = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_KARMAHITBOX); // Player hitbox is too small!! P_SetTarget(&karmahitbox->target, mobj); @@ -10439,6 +10634,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt case MT_SPIKEBALL: case MT_EMBLEM: case MT_RING: + case MT_BLUESPHERE: offset += mthing->options & MTF_AMBUSH ? 24*mapobjectscale : 0; break; @@ -10545,8 +10741,14 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) { - // Don't need this for Kart YET! (void)mthing; + + if ((gametyperules & GTR_SPHERES) && (i == MT_RING)) + return MT_BLUESPHERE; + + if ((gametyperules & GTR_PAPERITEMS) && (i == MT_RANDOMITEM)) + return MT_PAPERITEMSPOT; + return i; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 96d929041..93b4c7c6b 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -157,6 +157,8 @@ typedef enum MF_RUNSPAWNFUNC = 1<<27, // Don't remap in Encore mode. (Not a drawflag so that it's settable by mobjinfo.) MF_DONTENCOREMAP = 1<<28, + // Hitbox extends just as far below as above. + MF_PICKUPFROMBELOW = 1<<29, // free: to and including 1<<31 } mobjflag_t; @@ -408,9 +410,6 @@ typedef struct mobj_s INT32 cvmem; struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) -#ifdef HWRENDER - struct pslope_s *modeltilt; // Slope used for model tilting. Also is not synched, this is totally visual. -#endif boolean colorized; // Whether the mobj uses the rainbow colormap boolean mirrored; // The object's rotations will be mirrored left to right, e.g., see frame AL from the right and AR from the left @@ -532,7 +531,6 @@ boolean P_ZMovement(mobj_t *mo); void P_RingZMovement(mobj_t *mo); boolean P_SceneryZMovement(mobj_t *mo); void P_PlayerZMovement(mobj_t *mo); -void P_EmeraldManager(void); extern INT32 modulothing; diff --git a/src/p_saveg.c b/src/p_saveg.c index 7c9a3a96f..5d8c2e2f1 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -111,6 +111,7 @@ static void P_NetArchivePlayers(void) WRITEANGLE(save_p, players[i].awayviewaiming); WRITEINT32(save_p, players[i].awayviewtics); WRITEINT16(save_p, players[i].rings); + WRITEINT16(save_p, players[i].spheres); for (j = 0; j < NUMPOWERS; j++) WRITEUINT16(save_p, players[i].powers[j]); @@ -234,7 +235,7 @@ static void P_NetArchivePlayers(void) if (flags & FOLLOWITEM) WRITEUINT32(save_p, players[i].followmobj->mobjnum); - + WRITEUINT32(save_p, (UINT32)players[i].followitem); WRITEUINT32(save_p, players[i].charflags); @@ -255,6 +256,15 @@ static void P_NetArchivePlayers(void) WRITEUINT32(save_p, players[i].distancetofinish); WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint)); WRITEUINT32(save_p, players[i].airtime); + WRITEUINT8(save_p, players[i].trickpanel); + WRITEUINT8(save_p, players[i].trickdelay); + WRITEUINT32(save_p, players[i].trickmomx); + WRITEUINT32(save_p, players[i].trickmomy); + WRITEUINT32(save_p, players[i].trickmomz); + + WRITEUINT8(save_p, players[i].bumpers); + WRITEINT16(save_p, players[i].karmadelay); + WRITEUINT8(save_p, players[i].eliminated); WRITEUINT8(save_p, players[i].tumbleBounces); WRITEUINT16(save_p, players[i].tumbleHeight); @@ -308,6 +318,7 @@ static void P_NetUnArchivePlayers(void) players[i].awayviewaiming = READANGLE(save_p); players[i].awayviewtics = READINT32(save_p); players[i].rings = READINT16(save_p); + players[i].spheres = READINT16(save_p); for (j = 0; j < NUMPOWERS; j++) players[i].powers[j] = READUINT16(save_p); @@ -422,7 +433,7 @@ static void P_NetUnArchivePlayers(void) if (flags & FOLLOWITEM) players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p); - + players[i].followitem = (mobjtype_t)READUINT32(save_p); //SetPlayerSkinByNum(i, players[i].skin); @@ -444,6 +455,15 @@ static void P_NetUnArchivePlayers(void) players[i].distancetofinish = READUINT32(save_p); players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save_p); players[i].airtime = READUINT32(save_p); + players[i].trickpanel = READUINT8(save_p); + players[i].trickdelay = READUINT8(save_p); + players[i].trickmomx = READUINT32(save_p); + players[i].trickmomy = READUINT32(save_p); + players[i].trickmomz = READUINT32(save_p); + + players[i].bumpers = READUINT8(save_p); + players[i].karmadelay = READINT16(save_p); + players[i].eliminated = (boolean)READUINT8(save_p); players[i].tumbleBounces = READUINT8(save_p); players[i].tumbleHeight = READUINT16(save_p); @@ -2808,12 +2828,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) if (diff2 & MD2_ITNEXT) mobj->itnext = (mobj_t *)(size_t)READUINT32(save_p); if (diff2 & MD2_SLOPE) - { mobj->standingslope = P_SlopeById(READUINT16(save_p)); -#ifdef HWRENDER - mobj->modeltilt = mobj->standingslope; -#endif - } if (diff2 & MD2_COLORIZED) mobj->colorized = READUINT8(save_p); if (diff2 & MD2_MIRRORED) @@ -4132,7 +4147,6 @@ static void P_NetArchiveMisc(void) // battleovertime_t WRITEUINT16(save_p, battleovertime.enabled); WRITEFIXED(save_p, battleovertime.radius); - WRITEFIXED(save_p, battleovertime.minradius); WRITEFIXED(save_p, battleovertime.x); WRITEFIXED(save_p, battleovertime.y); WRITEFIXED(save_p, battleovertime.z); @@ -4266,7 +4280,6 @@ static inline boolean P_NetUnArchiveMisc(void) // battleovertime_t battleovertime.enabled = READUINT16(save_p); battleovertime.radius = READFIXED(save_p); - battleovertime.minradius = READFIXED(save_p); battleovertime.x = READFIXED(save_p); battleovertime.y = READFIXED(save_p); battleovertime.z = READFIXED(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 50f39c5fa..15e6767a5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3924,40 +3924,40 @@ boolean P_LoadLevel(boolean fromnetsave) } */ - // Make sure all sounds are stopped before Z_FreeTags. - S_StopSounds(); - S_ClearSfx(); - - // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. - // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!titlemapinaction) - S_FadeMusic(0, FixedMul( - FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); - - // Reset the palette now all fades have been done - if (rendermode != render_none) - V_SetPaletteLump(GetPalette()); // Set the level palette - - if (!titlemapinaction) - { - if (ranspecialwipe == 2) - { - pausedelay = -3; // preticker plus one - S_StartSound(NULL, sfx_s3k73); - } - - // As oddly named as this is, this handles music only. - // We should be fine starting it here. - // Don't do this during titlemap, because the menu code handles music by itself. - S_Start(); - } - - levelfadecol = (encoremode ? 0 : 31); - // Let's fade to white here // But only if we didn't do the encore startup wipe if (!demo.rewinding) { + // Make sure all sounds are stopped before Z_FreeTags. + S_StopSounds(); + S_ClearSfx(); + + // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. + // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. + if (!titlemapinaction) + S_FadeMusic(0, FixedMul( + FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); + + // Reset the palette now all fades have been done + if (rendermode != render_none) + V_SetPaletteLump(GetPalette()); // Set the level palette + + if (!titlemapinaction) + { + if (ranspecialwipe == 2) + { + pausedelay = -3; // preticker plus one + S_StartSound(NULL, sfx_s3k73); + } + + // As oddly named as this is, this handles music only. + // We should be fine starting it here. + // Don't do this during titlemap, because the menu code handles music by itself. + S_Start(); + } + + levelfadecol = (encoremode ? 0 : 31); + if (rendermode != render_none) { F_WipeStartScreen(); diff --git a/src/p_sight.c b/src/p_sight.c index a18f22d40..38a50df36 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -498,3 +498,161 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) // the head node is the last node output return P_CrossBSPNode((INT32)numnodes - 1, &los); } + +// +// P_TraceBlockingLines +// +// Returns true if a straight line between t1 and t2 is unobstructed. +// Unlike P_CheckSight, simplifed down to only check for explicit blocking lines on the 2D plane. +// Intended for Kart waypoints. +// Might be better in it's own file? +// + +typedef struct { + fixed_t t2x, t2y; + divline_t strace; // from t1 to t2 + fixed_t bbox[4]; + mobj_t *compareThing; +} traceblocking_t; + +static boolean P_CrossBlockingSubsector(size_t num, register traceblocking_t *tb) +{ + seg_t *seg; + INT32 count; + +#ifdef RANGECHECK + if (num >= numsubsectors) + I_Error("P_CrossBlockingSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors)); +#endif + + // haleyjd 02/23/06: this assignment should be after the above check + seg = segs + subsectors[num].firstline; + + for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines + { + line_t *line = seg->linedef; + divline_t divl; + const vertex_t *v1,*v2; + + if (seg->glseg) + continue; + + // already checked other side? + if (line->validcount == validcount) + continue; + + line->validcount = validcount; + + // OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test + if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] || + line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] || + line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] || + line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM]) + continue; + + v1 = line->v1; + v2 = line->v2; + + // line isn't crossed? + if (P_DivlineSide(v1->x, v1->y, &tb->strace) == + P_DivlineSide(v2->x, v2->y, &tb->strace)) + continue; + + // stop because it is not two sided anyway + if (!(line->flags & ML_TWOSIDED)) + return false; + + divl.dx = v2->x - (divl.x = v1->x); + divl.dy = v2->y - (divl.y = v1->y); + + // line isn't crossed? + if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) == + P_DivlineSide(tb->t2x, tb->t2y, &divl)) + continue; + + if (P_IsLineBlocking(line, tb->compareThing) == true) + { + // This line will block us + return false; + } + } + + // passed the subsector ok + return true; +} + +static boolean P_CrossBSPNodeBlocking(INT32 bspnum, register traceblocking_t *tb) +{ + while (!(bspnum & NF_SUBSECTOR)) + { + register node_t *bsp = nodes + bspnum; + INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1; + if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp)) + bspnum = bsp->children[side]; // doesn't touch the other side + else // the partition plane is crossed here + { + if (!P_CrossBSPNodeBlocking(bsp->children[side], tb)) + return false; // cross the starting side + else + bspnum = bsp->children[side^1]; // cross the ending side + } + } + + return P_CrossBlockingSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb); +} + +boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2) +{ + const sector_t *s1, *s2; + size_t pnum; + traceblocking_t tb; + + // First check for trivial rejection. + if (!t1 || !t2) + return false; + + I_Assert(!P_MobjWasRemoved(t1)); + I_Assert(!P_MobjWasRemoved(t2)); + + if (!t1->subsector || !t2->subsector + || !t1->subsector->sector || !t2->subsector->sector) + return false; + + s1 = t1->subsector->sector; + s2 = t2->subsector->sector; + pnum = (s1-sectors)*numsectors + (s2-sectors); + + if (rejectmatrix != NULL) + { + // Check in REJECT table. + if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected + return false; + } + + // killough 11/98: shortcut for melee situations + // same subsector? obviously visible + // haleyjd 02/23/06: can't do this if there are polyobjects in the subsec + if (!t1->subsector->polyList && + t1->subsector == t2->subsector) + return true; + + validcount++; + + tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x); + tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y); + + if (t1->x > t2->x) + tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x; + else + tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x; + + if (t1->y > t2->y) + tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y; + else + tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y; + + tb.compareThing = t1; + + // the head node is the last node output + return P_CrossBSPNodeBlocking((INT32)numnodes - 1, &tb); +} diff --git a/src/p_slopes.c b/src/p_slopes.c index d903afb71..f3e1e2930 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -897,9 +897,8 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope { thing->standingslope = slope; -#ifdef HWRENDER - thing->modeltilt = thing->standingslope; -#endif + P_SetPitchRollFromSlope(thing, slope); + if (!thing->player || !(thing->player->pflags & PF_BOUNCING)) thing->momz = -P_MobjFlip(thing); } @@ -916,9 +915,7 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope) thing->momx = mom.x; thing->momy = mom.y; thing->standingslope = slope; -#ifdef HWRENDER - thing->modeltilt = thing->standingslope; -#endif + P_SetPitchRollFromSlope(thing, slope); if (!thing->player || !(thing->player->pflags & PF_BOUNCING)) thing->momz = -P_MobjFlip(thing); } diff --git a/src/p_spec.c b/src/p_spec.c index c0ed5b63b..6bd6381ba 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1612,7 +1612,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller { if (GETSECSPECIAL(caller->special, 2) == 6) { - if (!(ALL7EMERALDS(emeralds))) + if (!(ALLCHAOSEMERALDS(emeralds))) return false; } @@ -2028,6 +2028,14 @@ static void K_HandleLapIncrement(player_t *player) player->karthud[khud_laphand] = 0; // No hands in FREE PLAY player->karthud[khud_lapanimation] = 80; + + // save best lap for record attack + if (player == &players[consoleplayer]) + { + if (curlap < bestlap || bestlap == 0) + bestlap = curlap; + curlap = 0; + } } if (rainbowstartavailable == true) @@ -2041,14 +2049,6 @@ static void K_HandleLapIncrement(player_t *player) if (netgame && player->laps >= (UINT8)cv_numlaps.value) CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players])); - // SRB2Kart: save best lap for record attack - if (player == &players[consoleplayer]) - { - if (curlap < bestlap || bestlap == 0) - bestlap = curlap; - curlap = 0; - } - player->starpostnum = 0; if (P_IsDisplayPlayer(player)) @@ -2133,6 +2133,7 @@ static void K_HandleLapDecrement(player_t *player) { player->starpostnum = numstarposts; player->laps--; + curlap = UINT32_MAX; } } } @@ -4598,47 +4599,43 @@ DoneSection2: switch (special) { case 1: // SRB2kart: Spring Panel + case 3: if (roversector || P_MobjReadyToTrigger(player->mo, sector)) { const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); const fixed_t minspeed = 24*hscale; - angle_t pushangle = K_MomentumAngle(player->mo); + fixed_t speed = FixedHypot(player->mo->momx, player->mo->momy); + fixed_t upwards = 32*FRACUNIT; if (player->mo->eflags & MFE_SPRUNG) + { break; + } - if (player->speed < minspeed) // Push forward to prevent getting stuck - P_InstaThrust(player->mo, pushangle, minspeed); + if (special == 3) + { + upwards /= 2; + } - player->kartstuff[k_pogospring] = 1; - K_DoPogoSpring(player->mo, 0, 1); + player->trickpanel = 1; + player->trickdelay = 1; + K_DoPogoSpring(player->mo, upwards, 1); + + // Reduce speed + speed /= 2; + + if (speed < minspeed) + { + speed = minspeed; + } + + P_InstaThrust(player->mo, player->mo->angle, speed); } break; case 2: // Wind/Current break; - case 3: // SRB2kart: Spring Panel (capped speed) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - { - const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); - const fixed_t minspeed = 24*hscale; - const fixed_t maxspeed = 28*hscale; - angle_t pushangle = K_MomentumAngle(player->mo); - - if (player->mo->eflags & MFE_SPRUNG) - break; - - if (player->speed > maxspeed) // Prevent overshooting jumps - P_InstaThrust(player->mo, pushangle, maxspeed); - else if (player->speed < minspeed) // Push forward to prevent getting stuck - P_InstaThrust(player->mo, pushangle, minspeed); - - player->kartstuff[k_pogospring] = 2; - K_DoPogoSpring(player->mo, 0, 1); - } - break; - case 4: // Conveyor Belt break; @@ -4678,7 +4675,7 @@ DoneSection2: P_InstaThrust(player->mo, lineangle, max(linespeed, 2*playerspeed)); player->kartstuff[k_dashpadcooldown] = TICRATE/3; - player->kartstuff[k_pogospring] = 0; + player->trickpanel = 0; player->kartstuff[k_floorboost] = 2; S_StartSound(player->mo, sfx_cdfm62); } diff --git a/src/p_tick.c b/src/p_tick.c index 79e71c655..c7e6a946a 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -332,6 +332,11 @@ static inline void P_RunThinkers(void) ps_thlist_times[i] = I_GetTimeMicros() - ps_thlist_times[i]; } + if (gametyperules & GTR_PAPERITEMS) + K_RunPaperItemSpawners(); + + if ((gametyperules & GTR_BUMPERS) && battleovertime.enabled) + K_RunBattleOvertime(); } // @@ -516,6 +521,8 @@ void P_Ticker(boolean run) if (demo.rewinding && leveltime > 0) { leveltime = (leveltime-1) & ~3; + if (timeinmap > 0) + timeinmap = (timeinmap-1) & ~3; G_PreviewRewind(leveltime); } else if (demo.freecam && democam.cam) // special case: allow freecam to MOVE during pause! @@ -592,9 +599,6 @@ void P_Ticker(boolean run) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); - if ((gametyperules & GTR_BUMPERS) && battleovertime.enabled) - K_RunBattleOvertime(); - ps_lua_thinkframe_time = I_GetTimeMicros(); LUAh_ThinkFrame(); ps_lua_thinkframe_time = I_GetTimeMicros() - ps_lua_thinkframe_time; @@ -613,9 +617,7 @@ void P_Ticker(boolean run) if (run) leveltime++; - // as this is mostly used for HUD stuff, add the record attack specific hack to it as well! - if (!(modeattacking && !demo.playback) || leveltime >= starttime - TICRATE*4) - timeinmap++; + timeinmap++; if (G_GametypeHasTeams()) P_DoTeamStuff(); @@ -752,9 +754,6 @@ void P_PreTicker(INT32 frames) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); - if ((gametyperules & GTR_BUMPERS) && battleovertime.enabled) - K_RunBattleOvertime(); - LUAh_ThinkFrame(); // Run shield positioning diff --git a/src/p_user.c b/src/p_user.c index 61c7c5e8a..befea60fa 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -461,18 +461,9 @@ UINT8 P_FindHighestLap(void) // boolean P_PlayerInPain(player_t *player) { - if (player->respawn.state != RESPAWNST_NONE) - return true; - if (player->kartstuff[k_spinouttimer] || player->tumbleBounces > 0) return true; - if (gametyperules & GTR_KARMA) - { - if (player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) - return true; - } - return false; } @@ -488,7 +479,7 @@ void P_ResetPlayer(player_t *player) player->onconveyor = 0; //player->kartstuff[k_drift] = player->kartstuff[k_driftcharge] = 0; - player->kartstuff[k_pogospring] = 0; + player->trickpanel = 0; } // @@ -1293,6 +1284,8 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->colorized = mobj->colorized; // Kart: they should also be colorized if their origin is ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); + ghost->roll = mobj->roll; + ghost->pitch = mobj->pitch; ghost->sprite = mobj->sprite; ghost->sprite2 = mobj->sprite2; ghost->frame = mobj->frame; @@ -1301,13 +1294,11 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->fuse = ghost->info->damage; ghost->skin = mobj->skin; ghost->standingslope = mobj->standingslope; -#ifdef HWRENDER - ghost->modeltilt = mobj->modeltilt; -#endif ghost->sprxoff = mobj->sprxoff; ghost->spryoff = mobj->spryoff; ghost->sprzoff = mobj->sprzoff; + ghost->rollangle = mobj->rollangle; if (mobj->flags2 & MF2_OBJECTFLIP) ghost->flags |= MF2_OBJECTFLIP; @@ -1927,8 +1918,7 @@ static void P_3dMovement(player_t *player) //} // Do not let the player control movement if not onground. - // SRB2Kart: pogo spring and speed bumps are supposed to control like you're on the ground - onground = (P_IsObjectOnGround(player->mo) || (player->kartstuff[k_pogospring])); + onground = P_IsObjectOnGround(player->mo); K_AdjustPlayerFriction(player); @@ -1944,11 +1934,6 @@ static void P_3dMovement(player_t *player) totalthrust.x += P_ReturnThrustX(player->mo, movepushangle, movepushforward); totalthrust.y += P_ReturnThrustY(player->mo, movepushangle, movepushforward); - - if (K_PlayerUsesBotMovement(player) == true) - { - K_MomentumToFacing(player); - } } if ((totalthrust.x || totalthrust.y) @@ -2220,10 +2205,14 @@ void P_MovePlayer(player_t *player) { K_KartMoveAnimation(player); - if (player->kartstuff[k_pogospring]) + if (player->trickpanel == 2) { player->drawangle += ANGLE_22h; } + else if (player->trickpanel == 3) + { + player->drawangle -= ANGLE_22h; + } else { player->drawangle = player->mo->angle; @@ -2676,7 +2665,7 @@ static void P_DeathThink(player_t *player) { if (player->spectator || !circuitmap) curlap = 0; - else + else if (curlap != UINT32_MAX) curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V } } @@ -3221,17 +3210,40 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } // sets ideal cam pos - dist = camdist; + { + const fixed_t speedthreshold = 48*mapobjectscale; + const fixed_t olddist = P_AproxDistance(mo->x - thiscam->x, mo->y - thiscam->y); - /* player->speed subtracts conveyors, janks up the camera */ - speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy); + fixed_t lag, distoffset; - if (speed > K_GetKartSpeed(player, false)) - dist += 4*(speed - K_GetKartSpeed(player, false)); - dist += abs(thiscam->momz)/4; + dist = camdist; - if (player->karthud[khud_boostcam]) - dist -= FixedMul(11*dist/16, player->karthud[khud_boostcam]); + if (player->karthud[khud_boostcam]) + { + dist -= FixedMul(11*dist/16, player->karthud[khud_boostcam]); + } + + speed = P_AproxDistance(P_AproxDistance(mo->momx, mo->momy), mo->momz / 16); + lag = FRACUNIT - ((FixedDiv(speed, speedthreshold) - FRACUNIT) * 2); + + if (lag > FRACUNIT) + { + lag = FRACUNIT; + } + + if (lag < camspeed) + { + lag = camspeed; + } + + distoffset = dist - olddist; + dist = olddist + FixedMul(distoffset, lag); + + if (dist < 0) + { + dist = 0; + } + } if (mo->standingslope) { @@ -3520,7 +3532,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall thiscam->momz = 0; } else if (player->exiting || timeover == 2) + { thiscam->momx = thiscam->momy = thiscam->momz = 0; + } else if (leveltime < introtime) { thiscam->momx = FixedMul(x - thiscam->x, camspeed); @@ -4418,7 +4432,7 @@ void P_PlayerThink(player_t *player) { if (player->spectator || !circuitmap) curlap = 0; - else + else if (curlap != UINT32_MAX) curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V } } @@ -4562,7 +4576,7 @@ void P_PlayerThink(player_t *player) || player->kartstuff[k_growshrinktimer] > 0 // Grow doesn't flash either. || (player->respawn.state != RESPAWNST_NONE) // Respawn timer (for drop dash effect) || (player->pflags & PF_GAMETYPEOVER) // NO CONTEST explosion - || ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) + || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0 && player->karmadelay) || leveltime < starttime)) // Level intro { if (player->powers[pw_flashing] > 0 && player->powers[pw_flashing] < K_GetKartFlashing(player) diff --git a/src/r_picformats.c b/src/r_picformats.c index 95fe23aeb..19079d3b7 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -23,6 +23,7 @@ #include "v_video.h" #include "z_zone.h" #include "w_wad.h" +#include "r_main.h" // R_PointToAngle #ifdef HWRENDER #include "hardware/hw_glob.h" @@ -1605,6 +1606,27 @@ void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps) } #ifdef ROTSPRITE +// +// R_SpriteRotationAngle +// +// Gets the rollangle for the input object. +// +angle_t R_SpriteRotationAngle(mobj_t *mobj) +{ +#if 0 + angle_t viewingAngle = R_PointToAngle(mobj->x, mobj->y); + + fixed_t pitchMul = -FINESINE(viewingAngle >> ANGLETOFINESHIFT); + fixed_t rollMul = FINECOSINE(viewingAngle >> ANGLETOFINESHIFT); + + angle_t rollOrPitch = FixedMul(mobj->pitch, pitchMul) + FixedMul(mobj->roll, rollMul); + + return (rollOrPitch + mobj->rollangle); +#else + return mobj->rollangle; +#endif +} + // // R_GetRollAngle // diff --git a/src/r_picformats.h b/src/r_picformats.h index 3ee76a92f..d677e783b 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -122,6 +122,7 @@ void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum); // Sprite rotation #ifdef ROTSPRITE +angle_t R_SpriteRotationAngle(mobj_t *mobj); INT32 R_GetRollAngle(angle_t rollangle); void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip); void R_FreeSingleRotSprite(spritedef_t *spritedef); diff --git a/src/r_skins.c b/src/r_skins.c index 951eeaad6..135221ea6 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -876,6 +876,11 @@ boolean SetPlayerFollower(INT32 playernum, const char *skinname) INT32 i; player_t *player = &players[playernum]; + if (stricmp("None", skinname) == 0) + { + SetFollower(playernum, -1); // reminder that -1 is nothing + return true; + } for (i = 0; i < numfollowers; i++) { // search in the skin list diff --git a/src/r_things.c b/src/r_things.c index 9788d916b..e1e38041b 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1230,32 +1230,6 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) return groundz; } -static void R_SetSpritePlaneHeights(vissprite_t *vis) -{ - ffloor_t *rover; - - fixed_t top; - fixed_t bot; - - vis->pt = vis->sector->floorheight; - vis->pb = vis->sector->ceilingheight; - - for (rover = vis->sector->ffloors; rover; rover = rover->next) - { - if (rover->flags & FF_EXISTS) - { - top = P_GetFFloorTopZAt (rover, vis->gx, vis->gy); - bot = P_GetFFloorBottomZAt (rover, vis->gx, vis->gy); - - if (top <= vis->gzt && top > vis->pt) - vis->pt = top; - - if (bot >= vis->gz && bot < vis->pb) - vis->pb = bot; - } - } -} - static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz) { vissprite_t *shadow; @@ -1344,8 +1318,6 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000 shadow->scale = FixedMul(yscale, shadowyscale); shadow->sector = vis->sector; - shadow->pt = vis->pt; - shadow->pb = vis->pb; shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS); shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS); shadow->cut = SC_ISSCALED|SC_SHADOW; //check this @@ -1462,6 +1434,7 @@ static void R_ProjectSprite(mobj_t *thing) #ifdef ROTSPRITE patch_t *rotsprite = NULL; INT32 rollangle = 0; + angle_t spriterotangle = 0; #endif // hitlag vibrating @@ -1602,9 +1575,11 @@ static void R_ProjectSprite(mobj_t *thing) spr_topoffset = spritecachedinfo[lump].topoffset; #ifdef ROTSPRITE - if (thing->rollangle) + spriterotangle = R_SpriteRotationAngle(thing); + + if (spriterotangle != 0) { - rollangle = R_GetRollAngle(thing->rollangle); + rollangle = R_GetRollAngle(spriterotangle); if (!(sprframe->rotsprite.cached & (1<sprite, frame, sprinfo, sprframe, rot, flip); rotsprite = sprframe->rotsprite.patch[rot][rollangle]; @@ -1860,9 +1835,6 @@ static void R_ProjectSprite(mobj_t *thing) vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); - - R_SetSpritePlaneHeights(vis); - vis->cut = cut; if (thing->subsector->sector->numlights) vis->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; @@ -2077,8 +2049,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, yscale))>>FRACBITS); - R_SetSpritePlaneHeights(vis); - iscale = FixedDiv(FRACUNIT, xscale); vis->startfrac = 0; @@ -2458,12 +2428,12 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps // bird: if any part of the sprite peeks in front the plane if (planecameraz < viewz) { - if (rover->pt >= planeobjectz && rover->gzt >= planeobjectz) + if (rover->gzt >= planeobjectz) continue; } else if (planecameraz > viewz) { - if (rover->pb <= planeobjectz && rover->gz <= planeobjectz) + if (rover->gz <= planeobjectz) continue; } @@ -2496,7 +2466,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps } else if (r2->thickseg) { - fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; + //fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1) continue; @@ -2507,6 +2477,11 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if (scale <= rover->sortscale) continue; + // bird: Always sort sprites behind segs. This helps the plane + // sorting above too. Basically if the sprite gets sorted behind + // the seg here, it will be behind the plane too, since planes + // are added after segs in the list. +#if 0 topplaneobjectz = P_GetFFloorTopZAt (r2->ffloor, rover->gx, rover->gy); topplanecameraz = P_GetFFloorTopZAt (r2->ffloor, viewx, viewy); botplaneobjectz = P_GetFFloorBottomZAt(r2->ffloor, rover->gx, rover->gy); @@ -2515,6 +2490,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if ((topplanecameraz > viewz && botplanecameraz < viewz) || (topplanecameraz < viewz && rover->gzt < topplaneobjectz) || (botplanecameraz > viewz && rover->gz > botplaneobjectz)) +#endif { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; diff --git a/src/r_things.h b/src/r_things.h index f95cd5c9e..400a63bcb 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -171,7 +171,6 @@ typedef struct vissprite_s // Precalculated top and bottom screen coords for the sprite. sector_t *sector; // The sector containing the thing. - fixed_t pt, pb; // plane heights, also for sorting against 3D floors INT16 sz, szt; spritecut_e cut; diff --git a/src/sounds.c b/src/sounds.c index d06e521d0..dc777a088 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -740,14 +740,14 @@ sfxinfo_t S_sfx[NUMSFX] = {"cdfm61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Speed boost"}, {"cdfm63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"cdfm64", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm64", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm65", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm70", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"cdfm71", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"cdfm71", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm72", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm73", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"cdfm74", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, @@ -808,7 +808,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc51", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"kc52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, + {"kc52", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc54", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, {"kc55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, diff --git a/src/st_stuff.c b/src/st_stuff.c index a8e7d2434..d6f80a9f5 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -673,10 +673,8 @@ void ST_preDrawTitleCard(void) if (lt_ticker >= (lt_endtime + TICRATE)) return; - if (!lt_exitticker) - st_translucency = 0; - else - st_translucency = max(0, min((INT32)lt_exitticker-4, cv_translucenthud.value)); + // Kart: nothing + st_translucency = cv_translucenthud.value; } //