diff --git a/src/command.c b/src/command.c index df5ffa4f..3ca7cb3a 100644 --- a/src/command.c +++ b/src/command.c @@ -1600,6 +1600,31 @@ void CV_AddValue(consvar_t *var, INT32 increment) return; } } + else if (var == &cv_kartspeed) + { + INT32 maxspeed = (M_SecretUnlocked(SECRET_HARDSPEED) ? 2 : 1); + // Special case for the kartspeed variable, used only directly from the menu to prevent selecting hard mode + if (increment > 0) // Going up! + { + newvalue = var->value + 1; + if (newvalue > maxspeed) + newvalue = 0; + var->value = newvalue; + var->string = var->PossibleValue[var->value].strvalue; + var->func(); + return; + } + else if (increment < 0) // Going down! + { + newvalue = var->value - 1; + if (newvalue < 0) + newvalue = maxspeed; + var->value = newvalue; + var->string = var->PossibleValue[var->value].strvalue; + var->func(); + return; + } + } #ifdef PARANOIA if (currentindice == -1) I_Error("CV_AddValue: current value %d not found in possible value\n", diff --git a/src/console.c b/src/console.c index f79a6faf..88ef0b49 100644 --- a/src/console.c +++ b/src/console.c @@ -134,11 +134,15 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"} // whether to use console background picture, or translucent mode static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Gray"}, {2, "Brown"}, - {3, "Red"}, {4, "Orange"}, {5, "Yellow"}, - {6, "Green"}, {7, "Blue"}, {8, "Cyan"}, +static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Black"}, {2, "Sepia"}, + {3, "Brown"}, {4, "Pink"}, {5, "Raspberry"}, + {6, "Red"}, {7, "Creamsicle"}, {8, "Orange"}, + {9, "Gold"}, {10,"Yellow"}, {11,"Emerald"}, + {12,"Green"}, {13,"Cyan"}, {14,"Steel"}, + {15,"Periwinkle"}, {16,"Blue"}, {17,"Purple"}, + {18,"Lavender"}, {0, NULL}}; -consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cons_backcolor = {"con_backcolor", "Black", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t menuhighlight_cons_t[] = { @@ -255,21 +259,32 @@ void CON_SetupBackColormap(void) UINT16 i, palsum; UINT8 j, palindex; UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE); + INT32 shift = 6; if (!consolebgmap) consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL); switch (cons_backcolor.value) { - case 0: palindex = 15; break; // White - case 1: palindex = 31; break; // Gray - case 2: palindex = 63; break; // Brown - case 3: palindex = 143; break; // Red - case 4: palindex = 95; break; // Orange - case 5: palindex = 111; break; // Yellow - case 6: palindex = 175; break; // Green - case 7: palindex = 239; break; // Blue - case 8: palindex = 219; break; // Cyan + case 0: palindex = 15; break; // White + case 1: palindex = 31; break; // Gray + case 2: palindex = 47; break; // Sepia + case 3: palindex = 63; break; // Brown + case 4: palindex = 150; shift = 7; break; // Pink + case 5: palindex = 127; shift = 7; break; // Raspberry + case 6: palindex = 143; break; // Red + case 7: palindex = 86; shift = 7; break; // Creamsicle + case 8: palindex = 95; break; // Orange + case 9: palindex = 119; shift = 7; break; // Gold + case 10: palindex = 111; break; // Yellow + case 11: palindex = 191; shift = 7; break; // Emerald + case 12: palindex = 175; break; // Green + case 13: palindex = 219; break; // Cyan + case 14: palindex = 207; shift = 7; break; // Steel + case 15: palindex = 230; shift = 7; break; // Periwinkle + case 16: palindex = 239; break; // Blue + case 17: palindex = 199; shift = 7; break; // Purple + case 18: palindex = 255; shift = 7; break; // Lavender // Default green default: palindex = 175; break; } @@ -277,7 +292,7 @@ void CON_SetupBackColormap(void) // setup background colormap for (i = 0, j = 0; i < 768; i += 3, j++) { - palsum = (pal[i] + pal[i+1] + pal[i+2]) >> 6; + palsum = (pal[i] + pal[i+1] + pal[i+2]) >> shift; consolebgmap[j] = (UINT8)(palindex - palsum); } } @@ -748,6 +763,19 @@ boolean CON_Responder(event_t *ev) if (modeattacking || metalrecording) return false; + if (ev->data1 >= KEY_MOUSE1) // See also: HUD_Responder + { + INT32 i; + for (i = 0; i < num_gamecontrols; i++) + { + if (gamecontrol[i][0] == ev->data1 || gamecontrol[i][1] == ev->data1) + break; + } + + if (i == num_gamecontrols) + return false; + } + if (key == gamecontrol[gc_console][0] || key == gamecontrol[gc_console][1]) { if (consdown) // ignore repeat diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0f0d5972..fc6ccf81 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -563,6 +563,8 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) for (j = 0; j < NUMKARTSTUFF; ++j) rsp->kartstuff[j] = LONG(players[i].kartstuff[j]); // SRB2kart + rsp->frameangle = (angle_t)LONG(players[i].frameangle); // SRB2kart + // Score is resynched in the rspfirm resync packet rsp->health = 0; // resynched with mo health rsp->lives = players[i].lives; @@ -576,8 +578,8 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) // Just in case Lua does something like // modify these at runtime // SRB2kart - rsp->kartspeed = (UINT8)LONG(players[i].kartspeed); - rsp->kartweight = (UINT8)LONG(players[i].kartweight); + rsp->kartspeed = (UINT8)players[i].kartspeed; + rsp->kartweight = (UINT8)players[i].kartweight; // rsp->normalspeed = (fixed_t)LONG(players[i].normalspeed); rsp->runspeed = (fixed_t)LONG(players[i].runspeed); @@ -644,6 +646,8 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->timeshit = players[i].timeshit; rsp->onconveyor = LONG(players[i].onconveyor); + rsp->jointime = (tic_t)LONG(players[i].jointime); + rsp->hasmo = false; //Transfer important mo information if the player has a body. //This lets us resync players even if they are dead. @@ -654,26 +658,26 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->health = LONG(players[i].mo->health); rsp->angle = (angle_t)LONG(players[i].mo->angle); - rsp->x = LONG(players[i].mo->x); - rsp->y = LONG(players[i].mo->y); - rsp->z = LONG(players[i].mo->z); - rsp->momx = LONG(players[i].mo->momx); - rsp->momy = LONG(players[i].mo->momy); - rsp->momz = LONG(players[i].mo->momz); - rsp->friction = LONG(players[i].mo->friction); - rsp->movefactor = LONG(players[i].mo->movefactor); + rsp->x = (fixed_t)LONG(players[i].mo->x); + rsp->y = (fixed_t)LONG(players[i].mo->y); + rsp->z = (fixed_t)LONG(players[i].mo->z); + rsp->momx = (fixed_t)LONG(players[i].mo->momx); + rsp->momy = (fixed_t)LONG(players[i].mo->momy); + rsp->momz = (fixed_t)LONG(players[i].mo->momz); + rsp->friction = (fixed_t)LONG(players[i].mo->friction); + rsp->movefactor = (fixed_t)LONG(players[i].mo->movefactor); rsp->tics = LONG(players[i].mo->tics); rsp->statenum = (statenum_t)LONG(players[i].mo->state-states); // :( + rsp->flags = (UINT32)LONG(players[i].mo->flags); + rsp->flags2 = (UINT32)LONG(players[i].mo->flags2); rsp->eflags = (UINT16)SHORT(players[i].mo->eflags); - rsp->flags = LONG(players[i].mo->flags); - rsp->flags2 = LONG(players[i].mo->flags2); - rsp->radius = LONG(players[i].mo->radius); - rsp->height = LONG(players[i].mo->height); - rsp->scale = LONG(players[i].mo->scale); - rsp->destscale = LONG(players[i].mo->destscale); - rsp->scalespeed = LONG(players[i].mo->scalespeed); + rsp->radius = (fixed_t)LONG(players[i].mo->radius); + rsp->height = (fixed_t)LONG(players[i].mo->height); + rsp->scale = (fixed_t)LONG(players[i].mo->scale); + rsp->destscale = (fixed_t)LONG(players[i].mo->destscale); + rsp->scalespeed = (fixed_t)LONG(players[i].mo->scalespeed); } static void resynch_read_player(resynch_pak *rsp) @@ -696,6 +700,8 @@ static void resynch_read_player(resynch_pak *rsp) for (j = 0; j < NUMKARTSTUFF; ++j) players[i].kartstuff[j] = LONG(rsp->kartstuff[j]); // SRB2kart + players[i].frameangle = (angle_t)LONG(rsp->frameangle); // SRB2kart + // Score is resynched in the rspfirm resync packet players[i].health = rsp->health; players[i].lives = rsp->lives; @@ -708,8 +714,8 @@ static void resynch_read_player(resynch_pak *rsp) players[i].skin = LONG(rsp->skin); // Just in case Lua does something like // modify these at runtime - players[i].kartspeed = (UINT8)LONG(rsp->kartspeed); - players[i].kartweight = (UINT8)LONG(rsp->kartweight); + players[i].kartspeed = (UINT8)rsp->kartspeed; + players[i].kartweight = (UINT8)rsp->kartweight; players[i].normalspeed = (fixed_t)LONG(rsp->normalspeed); players[i].runspeed = (fixed_t)LONG(rsp->runspeed); @@ -776,6 +782,8 @@ static void resynch_read_player(resynch_pak *rsp) players[i].timeshit = rsp->timeshit; players[i].onconveyor = LONG(rsp->onconveyor); + players[i].jointime = (tic_t)LONG(rsp->jointime); + //We get a packet for each player in game. if (!playeringame[i]) return; @@ -794,27 +802,30 @@ static void resynch_read_player(resynch_pak *rsp) //At this point, the player should have a body, whether they were respawned or not. P_UnsetThingPosition(players[i].mo); - players[i].mo->angle = (angle_t)LONG(rsp->angle); - players[i].mo->eflags = (UINT16)SHORT(rsp->eflags); - players[i].mo->flags = LONG(rsp->flags); - players[i].mo->flags2 = LONG(rsp->flags2); - players[i].mo->friction = LONG(rsp->friction); players[i].mo->health = LONG(rsp->health); - players[i].mo->momx = LONG(rsp->momx); - players[i].mo->momy = LONG(rsp->momy); - players[i].mo->momz = LONG(rsp->momz); - players[i].mo->movefactor = LONG(rsp->movefactor); + + players[i].mo->angle = (angle_t)LONG(rsp->angle); + players[i].mo->x = (fixed_t)LONG(rsp->x); + players[i].mo->y = (fixed_t)LONG(rsp->y); + players[i].mo->z = (fixed_t)LONG(rsp->z); + players[i].mo->momx = (fixed_t)LONG(rsp->momx); + players[i].mo->momy = (fixed_t)LONG(rsp->momy); + players[i].mo->momz = (fixed_t)LONG(rsp->momz); + players[i].mo->friction = (fixed_t)LONG(rsp->friction); + players[i].mo->movefactor = (fixed_t)LONG(rsp->movefactor); + players[i].mo->tics = LONG(rsp->tics); - P_SetMobjStateNF(players[i].mo, LONG(rsp->statenum)); - players[i].mo->x = LONG(rsp->x); - players[i].mo->y = LONG(rsp->y); - players[i].mo->z = LONG(rsp->z); - players[i].mo->radius = LONG(rsp->radius); - players[i].mo->height = LONG(rsp->height); + P_SetMobjStateNF(players[i].mo, (statenum_t)LONG(rsp->statenum)); + players[i].mo->flags = (UINT32)LONG(rsp->flags); + players[i].mo->flags2 = (UINT32)LONG(rsp->flags2); + players[i].mo->eflags = (UINT16)SHORT(rsp->eflags); + + players[i].mo->radius = (fixed_t)LONG(rsp->radius); + players[i].mo->height = (fixed_t)LONG(rsp->height); // P_SetScale is redundant for this, as all related variables are already restored properly. - players[i].mo->scale = LONG(rsp->scale); - players[i].mo->destscale = LONG(rsp->destscale); - players[i].mo->scalespeed = LONG(rsp->scalespeed); + players[i].mo->scale = (fixed_t)LONG(rsp->scale); + players[i].mo->destscale = (fixed_t)LONG(rsp->destscale); + players[i].mo->scalespeed = (fixed_t)LONG(rsp->scalespeed); // And finally, SET THE MOBJ SKIN damn it. players[i].mo->skin = &skins[players[i].skin]; @@ -939,8 +950,7 @@ static inline void resynch_write_others(resynchend_pak *rst) { rst->ctfteam[i] = 0; rst->score[i] = 0; - rst->numboxes[i] = 0; - rst->totalring[i] = 0; + rst->marescore[i] = 0; rst->realtime[i] = 0; rst->laps[i] = 0; continue; @@ -950,8 +960,7 @@ static inline void resynch_write_others(resynchend_pak *rst) rst->ingame |= (1<ctfteam[i] = (INT32)LONG(players[i].ctfteam); rst->score[i] = (UINT32)LONG(players[i].score); - rst->numboxes[i] = SHORT(players[i].numboxes); - rst->totalring[i] = SHORT(players[i].totalring); + rst->marescore[i] = (UINT32)LONG(players[i].marescore); rst->realtime[i] = (tic_t)LONG(players[i].realtime); rst->laps[i] = players[i].laps; } @@ -971,8 +980,7 @@ static inline void resynch_read_others(resynchend_pak *p) players[i].spectator = !(loc_ingame & (1<ctfteam[i]); // no, 0 does not mean spectator, at least not in Match players[i].score = (UINT32)LONG(p->score[i]); - players[i].numboxes = SHORT(p->numboxes[i]); - players[i].totalring = SHORT(p->totalring[i]); + players[i].marescore = (UINT32)LONG(p->marescore[i]); players[i].realtime = (tic_t)LONG(p->realtime[i]); players[i].laps = p->laps[i]; } @@ -993,7 +1001,8 @@ static void SV_RequireResynch(INT32 node) resynch_delay[node] = 10; // Delay before you can fail sync again resynch_score[node] += 200; // Add score for initial desynch - resynch_status[node] = 0xFFFFFFFF; // No players assumed synched + for (i = 0; i < MAXPLAYERS; ++i) + resynch_status[node] |= (1<lvlttl) > 0) { - CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl); + CON_LogMessage(va(": %s", mapheaderinfo[gamemap-1]->lvlttl)); if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) - CONS_Printf(" %s", mapheaderinfo[gamemap-1]->zonttl); + CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->zonttl)); else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) - CONS_Printf(M_GetText(" ZONE")); + CON_LogMessage(M_GetText(" ZONE")); if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0) - CONS_Printf(" %s", mapheaderinfo[gamemap-1]->actnum); + CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->actnum)); } - CONS_Printf("\"\n"); + CON_LogMessage("\"\n"); } else { @@ -2375,8 +2384,11 @@ static void Command_connect(void) CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n")); } - splitscreen = 0; - SplitScreen_OnChange(); + if (splitscreen != cv_splitplayers.value-1) + { + splitscreen = cv_splitplayers.value-1; + SplitScreen_OnChange(); + } botingame = false; botskin = 0; CL_ConnectToServer(viams); @@ -2417,14 +2429,15 @@ static void CL_RemovePlayer(INT32 playernum) if (server && !demoplayback) { INT32 node = playernode[playernum]; + //playerpernode[node] = 0; // It'd be better to remove them all at once, but ghosting happened, so continue to let CL_RemovePlayer do it one-by-one playerpernode[node]--; if (playerpernode[node] <= 0) { // If a resynch was in progress, well, it no longer needs to be. - SV_InitResynchVars(playernode[playernum]); + SV_InitResynchVars(node); - nodeingame[playernode[playernum]] = false; - Net_CloseConnection(playernode[playernum]); + nodeingame[node] = false; + Net_CloseConnection(node); ResetNode(node); } } @@ -2759,11 +2772,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) } // Is playernum authorized to make this kick? - if (playernum != serverplayer && !IsPlayerAdmin(playernum) - && !(playerpernode[playernode[playernum]] >= 2 - && (nodetoplayer2[playernode[playernum]] == pnum - || nodetoplayer3[playernode[playernum]] == pnum - || nodetoplayer4[playernode[playernum]] == pnum))) + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { // We received a kick command from someone who isn't the // server or admin, and who isn't in splitscreen removing @@ -2775,12 +2784,6 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) // "consistency failure" and kicking the offending user // instead. - // Note: Splitscreen in netgames is broken because of - // this. Only the server has any idea of which players - // are using splitscreen on the same computer, so - // clients cannot always determine if a kick is - // legitimate. - CONS_Alert(CONS_WARNING, M_GetText("Illegal kick command received from %s for player %d\n"), player_names[playernum], pnum); // In debug, print a longer message with more details. @@ -2810,7 +2813,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) msg = KICK_MSG_CON_FAIL; } - CONS_Printf("\x82%s ", player_names[pnum]); + //CONS_Printf("\x82%s ", player_names[pnum]); // If a verified admin banned someone, the server needs to know about it. // If the playernum isn't zero (the server) then the server needs to record the ban. @@ -2827,15 +2830,15 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) switch (msg) { case KICK_MSG_GO_AWAY: - CONS_Printf(M_GetText("has been kicked (Go away)\n")); + HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false); break; #ifdef NEWPING case KICK_MSG_PING_HIGH: - CONS_Printf(M_GetText("left the game (Broke ping limit)\n")); + HU_AddChatText(va("\x82*%s left the game (Broke ping limit)", player_names[pnum]), false); break; #endif case KICK_MSG_CON_FAIL: - CONS_Printf(M_GetText("left the game (Synch failure)\n")); + HU_AddChatText(va("\x82*%s left the game (Synch Failure)", player_names[pnum]), false); if (M_CheckParm("-consisdump")) // Helps debugging some problems { @@ -2871,26 +2874,26 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) } break; case KICK_MSG_TIMEOUT: - CONS_Printf(M_GetText("left the game (Connection timeout)\n")); + HU_AddChatText(va("\x82*%s left the game (Connection timeout)", player_names[pnum]), false); break; case KICK_MSG_PLAYER_QUIT: if (netgame) // not splitscreen/bots - CONS_Printf(M_GetText("left the game\n")); + HU_AddChatText(va("\x82*%s left the game", player_names[pnum]), false); break; case KICK_MSG_BANNED: - CONS_Printf(M_GetText("has been banned (Don't come back)\n")); + HU_AddChatText(va("\x82*%s has been banned (Don't come back)", player_names[pnum]), false); break; case KICK_MSG_CUSTOM_KICK: READSTRINGN(*p, reason, MAX_REASONLENGTH+1); - CONS_Printf(M_GetText("has been kicked (%s)\n"), reason); + HU_AddChatText(va("\x82*%s has been kicked (%s)", player_names[pnum], reason), false); break; case KICK_MSG_CUSTOM_BAN: READSTRINGN(*p, reason, MAX_REASONLENGTH+1); - CONS_Printf(M_GetText("has been banned (%s)\n"), reason); + HU_AddChatText(va("\x82*%s has been banned (%s)", player_names[pnum], reason), false); break; } - if (pnum == consoleplayer) + if (playernode[pnum] == playernode[consoleplayer]) { #ifdef DUMPCONSISTENCY if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); @@ -2899,7 +2902,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_Reset(); D_StartTitle(); if (msg == KICK_MSG_CON_FAIL) - M_StartMessage(M_GetText("Server closed connection\n(synch failure)\nPress ESC\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("Server closed connection\n(Synch failure)\nPress ESC\n"), NULL, MM_NOTHING); #ifdef NEWPING else if (msg == KICK_MSG_PING_HIGH) M_StartMessage(M_GetText("Server closed connection\n(Broke ping limit)\nPress ESC\n"), NULL, MM_NOTHING); @@ -2913,8 +2916,32 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) else M_StartMessage(M_GetText("You have been kicked by the server\n\nPress ESC\n"), NULL, MM_NOTHING); } - else - CL_RemovePlayer(pnum); + else if (server) + { + XBOXSTATIC UINT8 buf[0]; + + // Sal: Because kicks (and a lot of other commands) are player-based, we can't tell which player pnum is on the node from a glance. + // When we want to remove everyone from a node, we have to get the kicked player's node, then remove everyone on that node manually so we don't miss any. + // This avoids the bugs with older SRB2 version's online splitscreen kicks, specifically ghosting. + // On top of this, it can't just be a CL_RemovePlayer call; it has to be a server-sided. + // Clients don't bother setting any nodes for anything but THE server player (even ignoring the server's extra players!), so it'll often remove everyone because they all have node -1/255, insta-desync! + // And yes. This is a netxcmd wrap for just CL_RemovePlayer! :V + +#define removethisplayer(otherp) \ + if (otherp >= 0) \ + { \ + if (otherp != pnum) \ + HU_AddChatText(va("\x82*%s left the game (Joined with %s)", player_names[otherp], player_names[pnum]), false); \ + buf[0] = (UINT8)otherp; \ + SendNetXCmd(XD_REMOVEPLAYER, &buf, 1); \ + otherp = -1; \ + } + removethisplayer(nodetoplayer[playernode[pnum]]) + removethisplayer(nodetoplayer2[playernode[pnum]]) + removethisplayer(nodetoplayer3[playernode[pnum]]) + removethisplayer(nodetoplayer4[playernode[pnum]]) +#undef removethisplayer + } } consvar_t cv_allownewplayer = {"allowjoin", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; @@ -2937,6 +2964,7 @@ static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static void Got_AddPlayer(UINT8 **p, INT32 playernum); +static void Got_RemovePlayer(UINT8 **p, INT32 playernum); // called one time at init void D_ClientServerInit(void) @@ -2964,6 +2992,7 @@ void D_ClientServerInit(void) RegisterNetXCmd(XD_KICK, Got_KickCmd); RegisterNetXCmd(XD_ADDPLAYER, Got_AddPlayer); + RegisterNetXCmd(XD_REMOVEPLAYER, Got_RemovePlayer); #ifndef NONET CV_RegisterVar(&cv_allownewplayer); #ifdef VANILLAJOINNEXTROUND @@ -3157,17 +3186,13 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) newplayernum %= MAXPLAYERS; // Clear player before joining, lest some things get set incorrectly - // HACK: don't do this for splitscreen, it relies on preset values - if (!splitscreen && !botingame) - CL_ClearPlayer(newplayernum); + CL_ClearPlayer(newplayernum); + playeringame[newplayernum] = true; G_AddPlayer(newplayernum); if (newplayernum+1 > doomcom->numslots) doomcom->numslots = (INT16)(newplayernum+1); - if (netgame) - CONS_Printf(M_GetText("Player %d has joined the game (node %d)\n"), newplayernum+1, node); - // the server is creating my player if (node == mynode) { @@ -3226,11 +3251,17 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) D_SendPlayerConfig(); addedtogame = true; } - else if (server && netgame && cv_showjoinaddress.value) + + if (netgame) { - const char *address; - if (I_GetNodeAddress && (address = I_GetNodeAddress(node)) != NULL) - CONS_Printf(M_GetText("Player Address is %s\n"), address); + if (server && netgame && cv_showjoinaddress.value) + { + const char *address; + if (I_GetNodeAddress && (address = I_GetNodeAddress(node)) != NULL) + HU_AddChatText(va("\x82*Player %d has joined the game (node %d) (%s)", newplayernum+1, node, address), false); // merge join notification + IP to avoid clogging console/chat. + } + else + HU_AddChatText(va("\x82*Player %d has joined the game (node %d)", newplayernum+1, node), false); } if (server && multiplayer && motd[0] != '\0') @@ -3241,6 +3272,27 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) #endif } +// Xcmd XD_REMOVEPLAYER +static void Got_RemovePlayer(UINT8 **p, INT32 playernum) +{ + if (playernum != serverplayer && !IsPlayerAdmin(playernum)) + { + // protect against hacked/buggy client + CONS_Alert(CONS_WARNING, M_GetText("Illegal remove player command received from %s\n"), player_names[playernum]); + if (server) + { + XBOXSTATIC UINT8 buf[2]; + + buf[0] = (UINT8)playernum; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + return; + } + + CL_RemovePlayer(READUINT8(*p)); +} + static boolean SV_AddWaitingPlayers(void) { INT32 node, n, newplayer = false; @@ -3258,69 +3310,17 @@ static boolean SV_AddWaitingPlayers(void) { newplayer = true; - if (netgame) - // !!!!!!!!! EXTREMELY SUPER MEGA GIGA ULTRA ULTIMATELY TERRIBLY IMPORTANT !!!!!!!!! - // - // The line just after that comment is an awful, horrible, terrible, TERRIBLE hack. - // - // Basically, the fix I did in order to fix the download freezes happens - // to cause situations in which a player number does not match - // the node number associated to that player. - // That is totally normal, there is absolutely *nothing* wrong with that. - // Really. Player 7 being tied to node 29, for instance, is totally fine. - // - // HOWEVER. A few (broken) parts of the netcode do the TERRIBLE mistake - // of mixing up the concepts of node and player, resulting in - // incorrect handling of cases where a player is tied to a node that has - // a different number (which is a totally normal case, or at least should be). - // This incorrect handling can go as far as literally - // anyone from joining your server at all, forever. - // - // Given those two facts, there are two options available - // in order to let this download freeze fix be: - // 1) Fix the broken parts that assume a node is a player or similar bullshit. - // 2) Change the part this comment is located at, so that any player who joins - // is given the same number as their associated node. - // - // No need to say, 1) is by far the obvious best, whereas 2) is a terrible hack. - // Unfortunately, after trying 1), I most likely didn't manage to find all - // of those broken parts, and thus 2) has become the only safe option that remains. - // - // So I did this hack. - // - // If it isn't clear enough, in order to get rid of this ugly hack, - // you will have to fix all parts of the netcode that - // make a confusion between nodes and players. - // - // And if it STILL isn't clear enough, a node and a player - // is NOT the same thing. Never. NEVER. *NEVER*. - // - // And if someday you make the terrible mistake of - // daring to have the unforgivable idea to try thinking - // that a node might possibly be the same as a player, - // or that a player should have the same number as its node, - // be sure that I will somehow know about it and - // hunt you down tirelessly and make you regret it, - // even if you live on the other side of the world. - // - // TODO: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - // \todo >>>>>>>>>> Remove this horrible hack as soon as possible <<<<<<<<<< - // TODO: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // - // !!!!!!!!! EXTREMELY SUPER MEGA GIGA ULTRA ULTIMATELY TERRIBLY IMPORTANT !!!!!!!!! - newplayernum = node; // OMFG SAY WELCOME TO TEH NEW HACK FOR FIX FIL DOWNLOAD!!1! - else // Don't use the hack if we don't have to - // search for a free playernum - // we can't use playeringame since it is not updated here - for (; newplayernum < MAXPLAYERS; newplayernum++) - { - for (n = 0; n < MAXNETNODES; n++) - if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum - || nodetoplayer3[n] == newplayernum || nodetoplayer4[n] == newplayernum) - break; - if (n == MAXNETNODES) + // search for a free playernum + // we can't use playeringame since it is not updated here + for (; newplayernum < MAXPLAYERS; newplayernum++) + { + for (n = 0; n < MAXNETNODES; n++) + if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum + || nodetoplayer3[n] == newplayernum || nodetoplayer4[n] == newplayernum) break; - } + if (n == MAXNETNODES) + break; + } // should never happen since we check the playernum // before accepting the join @@ -3495,7 +3495,7 @@ static void HandleConnect(SINT8 node) SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment")); else if (D_NumPlayers() >= cv_maxplayers.value) SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value)); - else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client? + else if (netgame && netbuffer->u.clientcfg.localplayers > 4) // Hacked client? SV_SendRefuse(node, M_GetText("Too many players from\nthis node.")); else if (netgame && !netbuffer->u.clientcfg.localplayers) // Stealth join? SV_SendRefuse(node, M_GetText("No players from\nthis node.")); @@ -3529,8 +3529,8 @@ static void HandleConnect(SINT8 node) { G_SetGamestate(backupstate); /// \note Shouldn't SV_SendRefuse be called before ResetNode? - ResetNode(node); SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again")); + ResetNode(node); // Yeah, lets try it! /// \todo fix this !!! return; // restart the while } @@ -3983,10 +3983,10 @@ FILESTAMP --resynch_score[node]; break; case PT_TEXTCMD: - case PT_TEXTCMD2: // splitscreen special + case PT_TEXTCMD2: case PT_TEXTCMD3: case PT_TEXTCMD4: - if (netbuffer->packettype == PT_TEXTCMD2) + if (netbuffer->packettype == PT_TEXTCMD2) // splitscreen special netconsole = nodetoplayer2[node]; else if (netbuffer->packettype == PT_TEXTCMD3) netconsole = nodetoplayer3[node]; @@ -4073,9 +4073,9 @@ FILESTAMP else buf[1] = KICK_MSG_PLAYER_QUIT; SendNetXCmd(XD_KICK, &buf, 2); - nodetoplayer[node] = -1; + //nodetoplayer[node] = -1; - if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 + /*if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0 && playeringame[(UINT8)nodetoplayer2[node]]) { buf[0] = nodetoplayer2[node]; @@ -4097,7 +4097,7 @@ FILESTAMP buf[0] = nodetoplayer4[node]; SendNetXCmd(XD_KICK, &buf, 2); nodetoplayer4[node] = -1; - } + }*/ } Net_CloseConnection(node); nodeingame[node] = false; @@ -4353,7 +4353,7 @@ static INT16 Consistancy(void) { ret += players[i].mo->x; ret -= players[i].mo->y; - ret += players[i].powers[pw_shield]; + ret += players[i].kartstuff[k_itemtype]; // powers[pw_shield] ret *= i+1; } } @@ -4430,6 +4430,47 @@ static INT16 Consistancy(void) } else ret ^= 0xAAAA; + // SRB2Kart: We use hnext & hprev very extensively + if (mo->hnext) + { + ret += mo->hnext->type; + ret -= mo->hnext->x; + ret += mo->hnext->y; + ret -= mo->hnext->z; + ret += mo->hnext->momx; + ret -= mo->hnext->momy; + ret += mo->hnext->momz; + ret -= mo->hnext->angle; + ret += mo->hnext->flags; + ret -= mo->hnext->flags2; + ret += mo->hnext->eflags; + ret -= mo->hnext->state - states; + ret += mo->hnext->tics; + ret -= mo->hnext->sprite; + ret += mo->hnext->frame; + } + else + ret ^= 0x5555; + if (mo->hprev) + { + ret += mo->hprev->type; + ret -= mo->hprev->x; + ret += mo->hprev->y; + ret -= mo->hprev->z; + ret += mo->hprev->momx; + ret -= mo->hprev->momy; + ret += mo->hprev->momz; + ret -= mo->hprev->angle; + ret += mo->hprev->flags; + ret -= mo->hprev->flags2; + ret += mo->hprev->eflags; + ret -= mo->hprev->state - states; + ret += mo->hprev->tics; + ret -= mo->hprev->sprite; + ret += mo->hprev->frame; + } + else + ret ^= 0xCCCC; ret -= mo->state - states; ret += mo->tics; ret -= mo->sprite; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index e2a6ed7c..4d738632 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -166,8 +166,7 @@ typedef struct // Resynch game scores and the like all at once UINT32 score[MAXPLAYERS]; // Everyone's score - INT16 numboxes[MAXPLAYERS]; - INT16 totalring[MAXPLAYERS]; + UINT32 marescore[MAXPLAYERS]; // SRB2kart: Battle score tic_t realtime[MAXPLAYERS]; UINT8 laps[MAXPLAYERS]; } ATTRPACK resynchend_pak; @@ -186,6 +185,7 @@ typedef struct angle_t aiming; INT32 currentweapon; INT32 ringweapons; + UINT16 powers[NUMPOWERS]; INT32 kartstuff[NUMKARTSTUFF]; // SRB2kart @@ -271,6 +271,8 @@ typedef struct UINT8 timeshit; INT32 onconveyor; + tic_t jointime; + //player->mo stuff UINT8 hasmo; // Boolean diff --git a/src/d_main.c b/src/d_main.c index 024b1dfd..3eedb607 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1362,11 +1362,26 @@ void D_SRB2Main(void) #endif } + // Set up splitscreen players before joining! + if (!dedicated && (M_CheckParm("-splitscreen") && M_IsNextParm())) + { + UINT8 num = atoi(M_GetNextParm()); + if (num >= 1 && num <= 4) + { + CV_StealthSetValue(&cv_splitplayers, num); + splitscreen = num-1; + SplitScreen_OnChange(); + } + } + // init all NETWORK CONS_Printf("D_CheckNetGame(): Checking network game status.\n"); if (D_CheckNetGame()) autostart = true; + if (splitscreen) // Make sure multiplayer & autostart is set if you have splitscreen, even after D_CheckNetGame + multiplayer = autostart = true; + // check for a driver that wants intermission stats // start the apropriate game based on parms if (M_CheckParm("-metal")) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 17ae1242..6e598801 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -375,6 +375,7 @@ consvar_t cv_kartdebugdistribution = {"kartdebugdistribution", "Off", CV_NETVAR| consvar_t cv_kartdebughuddrop = {"kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kartdebugcheckpoint = {"kartdebugcheckpoint", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartdebugnodes = {"kartdebugnodes", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t votetime_cons_t[] = {{10, "MIN"}, {3600, "MAX"}, {0, NULL}}; consvar_t cv_votetime = {"votetime", "20", CV_NETVAR, votetime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -419,9 +420,6 @@ consvar_t cv_numlaps = {"numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_con static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}}; consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL}; -// log elemental hazards -- not a netvar, is local to current player -consvar_t cv_hazardlog = {"hazardlog", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; - consvar_t cv_forceskin = {"forceskin", "-1", CV_NETVAR|CV_CALL|CV_CHEAT, NULL, ForceSkin_OnChange, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_downloading = {"downloading", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_allowexitlevel = {"allowexitlevel", "No", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -594,8 +592,6 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_numlaps); CV_RegisterVar(&cv_basenumlaps); - CV_RegisterVar(&cv_hazardlog); - CV_RegisterVar(&cv_autobalance); CV_RegisterVar(&cv_teamscramble); CV_RegisterVar(&cv_scrambleonchange); @@ -758,6 +754,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_playername4); CV_RegisterVar(&cv_playercolor4); CV_RegisterVar(&cv_skin4); + // preferred number of players + CV_RegisterVar(&cv_splitplayers); #ifdef SEENAMES CV_RegisterVar(&cv_seenames); @@ -1140,8 +1138,8 @@ static void SetPlayerName(INT32 playernum, char *newname) if (strcasecmp(newname, player_names[playernum]) != 0) { if (netgame) - CONS_Printf(M_GetText("%s renamed to %s\n"), - player_names[playernum], newname); + HU_AddChatText(va("\x82*%s renamed to %s", player_names[playernum], newname), false); + strcpy(player_names[playernum], newname); } } @@ -1350,16 +1348,23 @@ static void SendNameAndColor(void) // splitscreen static void SendNameAndColor2(void) { - INT32 secondplaya; + INT32 secondplaya = -1; + XBOXSTATIC char buf[MAXPLAYERNAME+2]; + char *p; if (splitscreen < 1 && !botingame) return; // can happen if skin2/color2/name2 changed if (secondarydisplayplayer != consoleplayer) secondplaya = secondarydisplayplayer; - else // HACK + else if (!netgame) // HACK secondplaya = 1; + if (secondplaya == -1) + return; + + p = buf; + // normal player colors if (G_GametypeHasTeams()) { @@ -1436,21 +1441,53 @@ static void SendNameAndColor2(void) return; } - // Don't actually send anything because splitscreen isn't actually allowed in netgames anyway! + snac2pending++; + + // Don't change name if muted + if (cv_mute.value && !(server || IsPlayerAdmin(secondarydisplayplayer))) + CV_StealthSet(&cv_playername2, player_names[secondarydisplayplayer]); + else // Cleanup name if changing it + CleanupPlayerName(secondarydisplayplayer, cv_playername2.zstring); + + // Don't change skin if the server doesn't want you to. + if (!CanChangeSkin(secondarydisplayplayer)) + CV_StealthSet(&cv_skin2, skins[players[secondarydisplayplayer].skin].name); + + // check if player has the skin loaded (cv_skin2 may have + // the name of a skin that was available in the previous game) + cv_skin2.value = R_SkinAvailable(cv_skin2.string); + if (cv_skin2.value < 0) + { + CV_StealthSet(&cv_skin2, DEFAULTSKIN); + cv_skin2.value = 0; + } + + // Finally write out the complete packet and send it off. + WRITESTRINGN(p, cv_playername2.zstring, MAXPLAYERNAME); + WRITEUINT8(p, (UINT8)cv_playercolor2.value); + WRITEUINT8(p, (UINT8)cv_skin2.value); + SendNetXCmd2(XD_NAMEANDCOLOR, buf, p - buf); } static void SendNameAndColor3(void) { - INT32 thirdplaya; + INT32 thirdplaya = -1; + XBOXSTATIC char buf[MAXPLAYERNAME+2]; + char *p; if (splitscreen < 2) return; // can happen if skin3/color3/name3 changed if (thirddisplayplayer != consoleplayer) thirdplaya = thirddisplayplayer; - else // HACK + else if (!netgame) // HACK thirdplaya = 2; + if (thirdplaya == -1) + return; + + p = buf; + // normal player colors if (G_GametypeHasTeams()) { @@ -1519,21 +1556,53 @@ static void SendNameAndColor3(void) return; } - // Don't actually send anything because splitscreen isn't actually allowed in netgames anyway! + snac3pending++; + + // Don't change name if muted + if (cv_mute.value && !(server || IsPlayerAdmin(thirddisplayplayer))) + CV_StealthSet(&cv_playername3, player_names[thirddisplayplayer]); + else // Cleanup name if changing it + CleanupPlayerName(thirddisplayplayer, cv_playername3.zstring); + + // Don't change skin if the server doesn't want you to. + if (!CanChangeSkin(thirddisplayplayer)) + CV_StealthSet(&cv_skin3, skins[players[thirddisplayplayer].skin].name); + + // check if player has the skin loaded (cv_skin3 may have + // the name of a skin that was available in the previous game) + cv_skin3.value = R_SkinAvailable(cv_skin3.string); + if (cv_skin3.value < 0) + { + CV_StealthSet(&cv_skin3, DEFAULTSKIN); + cv_skin3.value = 0; + } + + // Finally write out the complete packet and send it off. + WRITESTRINGN(p, cv_playername3.zstring, MAXPLAYERNAME); + WRITEUINT8(p, (UINT8)cv_playercolor3.value); + WRITEUINT8(p, (UINT8)cv_skin3.value); + SendNetXCmd3(XD_NAMEANDCOLOR, buf, p - buf); } static void SendNameAndColor4(void) { - INT32 fourthplaya; + INT32 fourthplaya = -1; + XBOXSTATIC char buf[MAXPLAYERNAME+2]; + char *p; if (splitscreen < 3) return; // can happen if skin4/color4/name4 changed if (fourthdisplayplayer != consoleplayer) fourthplaya = fourthdisplayplayer; - else // HACK + else if (!netgame) // HACK fourthplaya = 3; + if (fourthplaya == -1) + return; + + p = buf; + // normal player colors if (G_GametypeHasTeams()) { @@ -1610,7 +1679,32 @@ static void SendNameAndColor4(void) return; } - // Don't actually send anything because splitscreen isn't actually allowed in netgames anyway! + snac4pending++; + + // Don't change name if muted + if (cv_mute.value && !(server || IsPlayerAdmin(fourthdisplayplayer))) + CV_StealthSet(&cv_playername4, player_names[fourthdisplayplayer]); + else // Cleanup name if changing it + CleanupPlayerName(fourthdisplayplayer, cv_playername4.zstring); + + // Don't change skin if the server doesn't want you to. + if (!CanChangeSkin(fourthdisplayplayer)) + CV_StealthSet(&cv_skin4, skins[players[fourthdisplayplayer].skin].name); + + // check if player has the skin loaded (cv_skin4 may have + // the name of a skin that was available in the previous game) + cv_skin4.value = R_SkinAvailable(cv_skin4.string); + if (cv_skin4.value < 0) + { + CV_StealthSet(&cv_skin4, DEFAULTSKIN); + cv_skin4.value = 0; + } + + // Finally write out the complete packet and send it off. + WRITESTRINGN(p, cv_playername4.zstring, MAXPLAYERNAME); + WRITEUINT8(p, (UINT8)cv_playercolor4.value); + WRITEUINT8(p, (UINT8)cv_skin4.value); + SendNetXCmd4(XD_NAMEANDCOLOR, buf, p - buf); } static void Got_NameAndColor(UINT8 **cp, INT32 playernum) @@ -2010,16 +2104,20 @@ void D_SetupVote(void) void D_ModifyClientVote(SINT8 voted, UINT8 splitplayer) { - char buf[1]; + char buf[2]; char *p = buf; + UINT8 player = consoleplayer; - if (splitplayer > 0) // Don't actually send anything for splitscreen - votes[splitplayer] = voted; - else - { - WRITESINT8(p, voted); - SendNetXCmd(XD_MODIFYVOTE, &buf, 1); - } + if (splitplayer == 1) + player = secondarydisplayplayer; + else if (splitplayer == 2) + player = thirddisplayplayer; + else if (splitplayer == 3) + player = fourthdisplayplayer; + + WRITESINT8(p, voted); + WRITEUINT8(p, player); + SendNetXCmd(XD_MODIFYVOTE, &buf, 2); } void D_PickVote(void) @@ -2388,11 +2486,12 @@ static void Command_Suicide(void) }*/ // Retry is quicker. Probably should force people to use it. - if (!(netgame || multiplayer)) + // nope, this is srb2kart - a complete retry is overkill + /*if (!(netgame || multiplayer)) { CONS_Printf(M_GetText("You can't use this in Single Player! Use \"retry\" instead.\n")); return; - } + }*/ SendNetXCmd(XD_SUICIDE, &buf, 4); } @@ -3135,6 +3234,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) players[playernum].playerstate = PST_REBORN; } + players[playernum].pflags &= ~PF_WANTSTOJOIN; + //Now that we've done our error checking and killed the player //if necessary, put the player on the correct team/status. if (G_TagGametype()) @@ -3216,12 +3317,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) else CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[playernum], '\x84', M_GetText("Blue Team"), '\x80'); } - else if (NetPacket.packet.newteam == 3) - /*CONS_Printf(M_GetText("%s entered the game.\n"), player_names[playernum])*/; - else if (players[playernum].pflags & PF_WANTSTOJOIN) - players[playernum].pflags &= ~PF_WANTSTOJOIN; - else - CONS_Printf(M_GetText("%s became a spectator.\n"), player_names[playernum]); + else if (NetPacket.packet.newteam == 0) + HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false); // "entered the game" text was moved to P_SpectatorJoinGame //reset view if you are changed, or viewing someone who was changed. if (playernum == consoleplayer || displayplayer == playernum) @@ -4635,7 +4732,10 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum) { SINT8 voted = READSINT8(*cp); - votes[playernum] = voted; + UINT8 p = READUINT8(*cp); + + (void)playernum; + votes[p] = voted; } static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) @@ -4753,9 +4853,13 @@ static void Command_RestartAudio_f(void) I_SetSfxVolume(cv_soundvolume.value); I_SetDigMusicVolume(cv_digmusicvolume.value); //I_SetMIDIMusicVolume(cv_midimusicvolume.value); + + S_StartSound(NULL, sfx_strpst); + if (Playing()) // Gotta make sure the player is in a level P_RestoreMusic(&players[consoleplayer]); - + else + S_ChangeMusicInternal("titles", looptitle); } /** Quits a game and returns to the title screen. @@ -4792,10 +4896,10 @@ void Command_Retry_f(void) CONS_Printf(M_GetText("You must be in a level to use this.\n")); else if (netgame || multiplayer) CONS_Printf(M_GetText("This only works in single player.\n")); - else if (!&players[consoleplayer] || players[consoleplayer].lives <= 1) + /*else if (!&players[consoleplayer] || players[consoleplayer].lives <= 1) CONS_Printf(M_GetText("You can't retry without any lives remaining!\n")); else if (G_IsSpecialStage(gamemap)) - CONS_Printf(M_GetText("You can't retry special stages!\n")); + CONS_Printf(M_GetText("You can't retry special stages!\n"));*/ else { M_ClearMenus(true); @@ -5156,13 +5260,17 @@ static void Color4_OnChange(void) */ static void Mute_OnChange(void) { - if (server || (IsPlayerAdmin(consoleplayer))) - return; + /*if (server || (IsPlayerAdmin(consoleplayer))) + return;*/ + // Kinda dumb IMO, you should be able to see confirmation for having muted the chat as the host or admin. + + if (leveltime <= 1) + return; // avoid having this notification put in our console / log when we boot the server. if (cv_mute.value) - CONS_Printf(M_GetText("Chat has been muted.\n")); + HU_AddChatText(M_GetText("\x82*Chat has been muted."), false); else - CONS_Printf(M_GetText("Chat is no longer muted.\n")); + HU_AddChatText(M_GetText("\x82*Chat is no longer muted."), false); } /** Hack to clear all changed flags after game start. @@ -5245,6 +5353,13 @@ static void KartFrantic_OnChange(void) static void KartSpeed_OnChange(void) { + if (!M_SecretUnlocked(SECRET_HARDSPEED) && cv_kartspeed.value == 2) + { + CONS_Printf(M_GetText("You haven't earned this yet.\n")); + CV_StealthSetValue(&cv_kartspeed, 1); + return; + } + if (G_RaceGametype()) { if ((UINT8)cv_kartspeed.value != gamespeed && gamestate == GS_LEVEL && leveltime > starttime) diff --git a/src/d_netcmd.h b/src/d_netcmd.h index aee243cf..366357bf 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -81,8 +81,6 @@ extern consvar_t cv_basenumlaps; extern UINT32 timelimitintics; extern consvar_t cv_allowexitlevel; -extern consvar_t cv_hazardlog; - extern consvar_t cv_autobalance; extern consvar_t cv_teamscramble; extern consvar_t cv_scrambleonchange; @@ -134,7 +132,7 @@ extern consvar_t cv_karteliminatelast; extern consvar_t cv_votetime; extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop; -extern consvar_t cv_kartdebugcheckpoint; +extern consvar_t cv_kartdebugcheckpoint, cv_kartdebugnodes; extern consvar_t cv_itemfinder; @@ -197,9 +195,10 @@ typedef enum XD_SETUPVOTE, // 22 XD_MODIFYVOTE, // 23 XD_PICKVOTE, // 24 + XD_REMOVEPLAYER,// 25 #ifdef HAVE_BLUA - XD_LUACMD, // 25 - XD_LUAVAR, // 26 + XD_LUACMD, // 26 + XD_LUAVAR, // 27 #endif MAXNETXCMD } netxcmd_t; diff --git a/src/d_player.h b/src/d_player.h index 02f7f45e..a5907646 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -280,6 +280,7 @@ typedef enum k_throwdir, // Held dir of controls; 1 = forward, 0 = none, -1 = backward (was "player->heldDir") k_lapanimation, // Used to show the lap start wing logo animation + k_laphand, // Lap hand gfx to use; 0 = none, 1 = :ok_hand:, 2 = :thumbs_up:, 3 = :thumps_down: k_cardanimation, // Used to determine the position of some full-screen Battle Mode graphics k_voices, // Used to stop the player saying more voices than it should k_tauntvoices, // Used to specifically stop taunt voice spam @@ -306,7 +307,9 @@ typedef enum k_accelboost, // Boost value smoothing for acceleration k_boostcam, // Camera push forward on boost k_destboostcam, // Ditto + k_timeovercam, // Camera timer for leaving behind or not k_aizdriftstrat, // Let go of your drift while boosting? Helper for the SICK STRATZ you have just unlocked + k_brakedrift, // Helper for brake-drift spark spawning k_itemroulette, // Used for the roulette when deciding what item to give you (was "pw_kartitem") k_roulettetype, // Used for the roulette, for deciding type (currently only used for Battle, to give you better items from Karma items) @@ -327,7 +330,6 @@ typedef enum k_squishedtimer, // Squished frame timer k_rocketsneakertimer, // Rocket Sneaker duration timer k_invincibilitytimer, // Invincibility timer - k_deathsentence, // 30 seconds to live... (SPB murder timer (not actually 30 sec, I just couldn't help the FF reference :p)) k_eggmanheld, // Eggman monitor held, separate from k_itemheld so it doesn't stop you from getting items k_eggmanexplode, // Fake item recieved, explode in a few seconds k_eggmanblame, // Fake item recieved, who set this fake @@ -344,6 +346,7 @@ typedef enum k_comebackpoints, // Number of times you've bombed or gave an item to someone; once it's 3 it gets set back to 0 and you're given a bumper k_comebackmode, // 0 = bomb, 1 = item k_wanted, // Timer for determining WANTED status, lowers when hitting people, prevents the game turning into Camp Lazlo + k_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly NUMKARTSTUFF } kartstufftype_t; diff --git a/src/dehacked.c b/src/dehacked.c index 4a7599b9..1e03c865 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -990,7 +990,7 @@ static const struct { {"2D",TOL_2D}, {"MARIO",TOL_MARIO}, {"NIGHTS",TOL_NIGHTS}, - //{"OLDBRAK",TOL_ERZ3}, + {"TV",TOL_TV}, {"XMAS",TOL_XMAS}, {"CHRISTMAS",TOL_XMAS}, @@ -1835,9 +1835,17 @@ static actionpointer_t actionpointers[] = {{A_ItemPop}, "A_ITEMPOP"}, // SRB2kart {{A_JawzChase}, "A_JAWZCHASE"}, // SRB2kart {{A_JawzExplode}, "A_JAWZEXPLODE"}, // SRB2kart + {{A_SPBChase}, "A_SPBCHASE"}, // SRB2kart {{A_MineExplode}, "A_MINEEXPLODE"}, // SRB2kart {{A_BallhogExplode}, "A_BALLHOGEXPLODE"}, // SRB2kart - {{A_LightningFollowPlayer}, "A_LIGHTNINGFOLLOWPLAYER"}, //SRB2kart + {{A_LightningFollowPlayer},"A_LIGHTNINGFOLLOWPLAYER"}, //SRB2kart + {{A_FZBoomFlash}, "A_FZBOOMFLASH"}, //SRB2kart + {{A_FZBoomSmoke}, "A_FZBOOMSMOKE"}, //SRB2kart + {{A_RandomShadowFrame}, "A_RANDOMSHADOWFRAME"}, //SRB2kart + {{A_RoamingShadowThinker}, "A_ROAMINGSHADOWTHINKER"}, //SRB2kart + {{A_ReaperThinker}, "A_REAPERTHINKER"}, //SRB2kart + {{A_MementosTPParticles}, "A_MEMENTOSTPPARTICLES"}, //SRB2kart + {{A_FlameParticle}, "A_FLAMEPARTICLE"}, // SRB2kart {{A_OrbitNights}, "A_ORBITNIGHTS"}, {{A_GhostMe}, "A_GHOSTME"}, {{A_SetObjectState}, "A_SETOBJECTSTATE"}, @@ -2430,6 +2438,8 @@ static void readunlockable(MYFILE *f, INT32 num) unlockables[num].type = SECRET_ENCORE; else if (fastcmp(word2, "HELLATTACK")) unlockables[num].type = SECRET_HELLATTACK; + else if (fastcmp(word2, "HARDSPEED")) + unlockables[num].type = SECRET_HARDSPEED; else unlockables[num].type = (INT16)i; } @@ -5265,6 +5275,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_XMASPOLE", "S_CANDYCANE", "S_SNOWMAN", + "S_SNOWMANHAT", + "S_LAMPPOST1", + "S_LAMPPOST2", + "S_HANGSTAR", // Botanic Serenity's loads of scenery states "S_BSZTALLFLOWER_RED", @@ -6238,6 +6252,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_DRIFTSPARK_C1", "S_DRIFTSPARK_C2", + // Brake drift sparks + "S_BRAKEDRIFT", + // Drift Smoke "S_DRIFTDUST1", "S_DRIFTDUST2", @@ -6311,32 +6328,38 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_WIPEOUTTRAIL4", "S_WIPEOUTTRAIL5", + // Rocket sneaker + "S_ROCKETSNEAKER_L", + "S_ROCKETSNEAKER_R", + "S_ROCKETSNEAKER_LVIBRATE", + "S_ROCKETSNEAKER_RVIBRATE", + //{ Eggman Monitor - "S_FAKEITEM1", - "S_FAKEITEM2", - "S_FAKEITEM3", - "S_FAKEITEM4", - "S_FAKEITEM5", - "S_FAKEITEM6", - "S_FAKEITEM7", - "S_FAKEITEM8", - "S_FAKEITEM9", - "S_FAKEITEM10", - "S_FAKEITEM11", - "S_FAKEITEM12", - "S_FAKEITEM13", - "S_FAKEITEM14", - "S_FAKEITEM15", - "S_FAKEITEM16", - "S_FAKEITEM17", - "S_FAKEITEM18", - "S_FAKEITEM19", - "S_FAKEITEM20", - "S_FAKEITEM21", - "S_FAKEITEM22", - "S_FAKEITEM23", - "S_FAKEITEM24", - "S_DEADFAKEITEM", + "S_EGGMANITEM1", + "S_EGGMANITEM2", + "S_EGGMANITEM3", + "S_EGGMANITEM4", + "S_EGGMANITEM5", + "S_EGGMANITEM6", + "S_EGGMANITEM7", + "S_EGGMANITEM8", + "S_EGGMANITEM9", + "S_EGGMANITEM10", + "S_EGGMANITEM11", + "S_EGGMANITEM12", + "S_EGGMANITEM13", + "S_EGGMANITEM14", + "S_EGGMANITEM15", + "S_EGGMANITEM16", + "S_EGGMANITEM17", + "S_EGGMANITEM18", + "S_EGGMANITEM19", + "S_EGGMANITEM20", + "S_EGGMANITEM21", + "S_EGGMANITEM22", + "S_EGGMANITEM23", + "S_EGGMANITEM24", + "S_EGGMANITEM_DEAD", //} // Banana @@ -6467,17 +6490,27 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_BALLHOGBOOM16", // Self-Propelled Bomb - just an explosion for now... - "S_BLUELIGHTNING1", - "S_BLUELIGHTNING2", - "S_BLUELIGHTNING3", - "S_BLUELIGHTNING4", - "S_BLUEEXPLODE", - - // Grow/shrink beams - "S_LIGHTNING1", - "S_LIGHTNING2", - "S_LIGHTNING3", - "S_LIGHTNING4", + "S_SPB1", + "S_SPB2", + "S_SPB3", + "S_SPB4", + "S_SPB5", + "S_SPB6", + "S_SPB7", + "S_SPB8", + "S_SPB9", + "S_SPB10", + "S_SPB11", + "S_SPB12", + "S_SPB13", + "S_SPB14", + "S_SPB15", + "S_SPB16", + "S_SPB17", + "S_SPB18", + "S_SPB19", + "S_SPB20", + "S_SPB_DEAD", // Thunder Shield "S_THUNDERSHIELD1", @@ -6708,12 +6741,61 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PLAYERARROW_WANTED6", "S_PLAYERARROW_WANTED7", - "S_PLAYERBOMB", // Player bomb overlay + "S_PLAYERBOMB1", // Player bomb overlay + "S_PLAYERBOMB2", + "S_PLAYERBOMB3", + "S_PLAYERBOMB4", + "S_PLAYERBOMB5", + "S_PLAYERBOMB6", + "S_PLAYERBOMB7", + "S_PLAYERBOMB8", + "S_PLAYERBOMB9", + "S_PLAYERBOMB10", + "S_PLAYERBOMB11", + "S_PLAYERBOMB12", + "S_PLAYERBOMB13", + "S_PLAYERBOMB14", + "S_PLAYERBOMB15", + "S_PLAYERBOMB16", + "S_PLAYERBOMB17", + "S_PLAYERBOMB18", + "S_PLAYERBOMB19", + "S_PLAYERBOMB20", "S_PLAYERITEM", // Player item overlay "S_PLAYERFAKE", // Player fake overlay "S_KARMAWHEEL", // Karma player wheels + "S_BATTLEPOINT1A", // Battle point indicators + "S_BATTLEPOINT1B", + "S_BATTLEPOINT1C", + "S_BATTLEPOINT1D", + "S_BATTLEPOINT1E", + "S_BATTLEPOINT1F", + "S_BATTLEPOINT1G", + "S_BATTLEPOINT1H", + "S_BATTLEPOINT1I", + + "S_BATTLEPOINT2A", + "S_BATTLEPOINT2B", + "S_BATTLEPOINT2C", + "S_BATTLEPOINT2D", + "S_BATTLEPOINT2E", + "S_BATTLEPOINT2F", + "S_BATTLEPOINT2G", + "S_BATTLEPOINT2H", + "S_BATTLEPOINT2I", + + "S_BATTLEPOINT3A", + "S_BATTLEPOINT3B", + "S_BATTLEPOINT3C", + "S_BATTLEPOINT3D", + "S_BATTLEPOINT3E", + "S_BATTLEPOINT3F", + "S_BATTLEPOINT3G", + "S_BATTLEPOINT3H", + "S_BATTLEPOINT3I", + // Thunder shield use stuff; "S_KSPARK1", // Sparkling Radius "S_KSPARK2", @@ -6762,6 +6844,254 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_KLIT11", "S_KLIT12", + "S_FZEROSMOKE1", // F-Zero NO CONTEST explosion + "S_FZEROSMOKE2", + "S_FZEROSMOKE3", + "S_FZEROSMOKE4", + "S_FZEROSMOKE5", + + "S_FZEROBOOM1", + "S_FZEROBOOM2", + "S_FZEROBOOM3", + "S_FZEROBOOM4", + "S_FZEROBOOM5", + "S_FZEROBOOM6", + "S_FZEROBOOM7", + "S_FZEROBOOM8", + "S_FZEROBOOM9", + "S_FZEROBOOM10", + "S_FZEROBOOM11", + "S_FZEROBOOM12", + + "S_FZSLOWSMOKE1", + "S_FZSLOWSMOKE2", + "S_FZSLOWSMOKE3", + "S_FZSLOWSMOKE4", + "S_FZSLOWSMOKE5", + + // Various plants + "S_SONICBUSH", + "S_SHRUB", + "S_TALLBUSH", + "S_AZURECITYTREE", + + // Marble Zone + "S_FLAMEPARTICLE", + "S_MARBLETORCH", + "S_MARBLELIGHT", + "S_MARBLEBURNER", + + // CD Special Stage + "S_CDUFO", + "S_CDUFO_DIE", + + // Rusty Rig + "S_RUSTYLAMP_ORANGE", + "S_RUSTYCHAIN", + + // D2 Balloon Panic + "S_BALLOON", + "S_BALLOONPOP1", + "S_BALLOONPOP2", + "S_BALLOONPOP3", + + // Smokin' & Vapin' (Don't try this at home, kids!) + "S_PETSMOKE0", + "S_PETSMOKE1", + "S_PETSMOKE2", + "S_PETSMOKE3", + "S_PETSMOKE4", + "S_PETSMOKE5", + "S_VVVAPING0", + "S_VVVAPING1", + "S_VVVAPING2", + "S_VVVAPING3", + "S_VVVAPING4", + "S_VVVAPING5", + "S_VVVAPE", + + // Hill Top Zone + "S_HTZTREE", + "S_HTZBUSH", + + // Ports of gardens + "S_SGVINE1", + "S_SGVINE2", + "S_SGVINE3", + "S_PGTREE", + "S_PGFLOWER1", + "S_PGFLOWER2", + "S_PGFLOWER3", + "S_PGBUSH", + "S_DHPILLAR", + + // Midnight Channel stuff: + "S_SPOTLIGHT", // Spotlight decoration + "S_RANDOMSHADOW", // Random Shadow. They're static and don't do nothing. + "S_GARU1", + "S_GARU2", + "S_GARU3", + "S_TGARU", + "S_TGARU1", + "S_TGARU2", + "S_TGARU3", // Wind attack used by Roaming Shadows on Players. + "S_ROAMINGSHADOW", // Roaming Shadow (the one that uses above's wind attack or smth) + "S_MAYONAKAARROW", // Arrow sign + + // Mementos stuff: + "S_REAPER_INVIS", // Reaper waiting for spawning + "S_REAPER", // Reaper main frame where its thinker is handled + "S_MEMENTOSTP", // Mementos teleporter state. (Used for spawning particles) + + // JackInTheBox + "S_JITB1", + "S_JITB2", + "S_JITB3", + "S_JITB4", + "S_JITB5", + "S_JITB6", + + // Color Drive + "S_CDMOONSP", + "S_CDBUSHSP", + "S_CDTREEASP", + "S_CDTREEBSP", + + // Daytona Speedway + "S_PINETREE", + "S_PINETREE_SIDE", + + // Egg Zeppelin + "S_EZZPROPELLER", + "S_EZZPROPELLER_BLADE", + + // Desert Palace + "S_DP_PALMTREE", + + // Aurora Atoll + "S_AAZTREE_SEG", + "S_AAZTREE_COCONUT", + "S_AAZTREE_LEAF", + + // Barren Badlands + "S_BBZDUST1", // Dust + "S_BBZDUST2", + "S_BBZDUST3", + "S_BBZDUST4", + "S_FROGGER", // Frog badniks + "S_FROGGER_ATTACK", + "S_FROGGER_JUMP", + "S_FROGTONGUE", + "S_FROGTONGUE_JOINT", + "S_ROBRA", // Black cobra badniks + "S_ROBRA_HEAD", + "S_ROBRA_JOINT", + "S_ROBRASHELL_INSIDE", + "S_ROBRASHELL_OUTSIDE", + "S_BLUEROBRA", // Blue cobra badniks + "S_BLUEROBRA_HEAD", + "S_BLUEROBRA_JOINT", + + // Eerie Grove + "S_EERIEFOG1", + "S_EERIEFOG2", + "S_EERIEFOG3", + "S_EERIEFOG4", + "S_EERIEFOG5", + + // SMK ports + "S_SMK_PIPE1", // Generic pipes + "S_SMK_PIPE2", + "S_SMK_MOLE", // Donut Plains Monty Moles + "S_SMK_THWOMP", // Bowser Castle Thwomps + "S_SMK_SNOWBALL", // Vanilla Lake snowballs + "S_SMK_ICEBLOCK", // Vanilla Lake breakable ice blocks + "S_SMK_ICEBLOCK2", + "S_SMK_ICEBLOCK_DEBRIS", + "S_SMK_ICEBLOCK_DEBRIS2", + + // Ezo's maps + "S_BLUEFIRE1", + "S_BLUEFIRE2", + "S_BLUEFIRE3", + "S_BLUEFIRE4", + "S_GREENFIRE1", + "S_GREENFIRE2", + "S_GREENFIRE3", + "S_GREENFIRE4", + "S_REGALCHEST", + "S_CHIMERASTATUE", + "S_DRAGONSTATUE", + "S_LIZARDMANSTATUE", + "S_PEGASUSSTATUE", + "S_ZELDAFIRE1", + "S_ZELDAFIRE2", + "S_ZELDAFIRE3", + "S_ZELDAFIRE4", + "S_GANBARETHING", + "S_GANBAREDUCK", + "S_GANBARETREE", + "S_MONOIDLE", + "S_MONOCHASE1", + "S_MONOCHASE2", + "S_MONOCHASE3", + "S_MONOCHASE4", + "S_MONOPAIN", + "S_REDZELDAFIRE1", + "S_REDZELDAFIRE2", + "S_REDZELDAFIRE3", + "S_REDZELDAFIRE4", + "S_BOWLINGPIN", + "S_BOWLINGHIT1", + "S_BOWLINGHIT2", + "S_BOWLINGHIT3", + "S_BOWLINGHIT4", + "S_ARIDTOAD", + "S_TOADHIT1", + "S_TOADHIT2", + "S_TOADHIT3", + "S_TOADHIT4", + "S_EBARRELIDLE", + "S_EBARREL1", + "S_EBARREL2", + "S_EBARREL3", + "S_EBARREL4", + "S_EBARREL5", + "S_EBARREL6", + "S_EBARREL7", + "S_EBARREL8", + "S_EBARREL9", + "S_EBARREL10", + "S_EBARREL11", + "S_EBARREL12", + "S_EBARREL13", + "S_EBARREL14", + "S_EBARREL15", + "S_EBARREL16", + "S_EBARREL17", + "S_EBARREL18", + "S_MERRYHORSE", + "S_BLUEFRUIT", + "S_ORANGEFRUIT", + "S_REDFRUIT", + "S_PINKFRUIT", + "S_ADVENTURESPIKEA1", + "S_ADVENTURESPIKEA2", + "S_ADVENTURESPIKEB1", + "S_ADVENTURESPIKEB2", + "S_ADVENTURESPIKEC1", + "S_ADVENTURESPIKEC2", + "S_BOOSTPROMPT1", + "S_BOOSTPROMPT2", + "S_BOOSTOFF1", + "S_BOOSTOFF2", + "S_BOOSTON1", + "S_BOOSTON2", + "S_LIZARDMAN", + "S_LIONMAN", + "S_MOUSEMAN1", + "S_MOUSEMAN2", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -7048,6 +7378,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_XMASPOLE", "MT_CANDYCANE", "MT_SNOWMAN", + "MT_SNOWMANHAT", + "MT_LAMPPOST1", + "MT_LAMPPOST2", + "MT_HANGSTAR", // Botanic Serenity "MT_BSZTALLFLOWER_RED", @@ -7292,10 +7626,13 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_INVULNFLASH", "MT_WIPEOUTTRAIL", "MT_DRIFTSPARK", + "MT_BRAKEDRIFT", "MT_DRIFTDUST", - "MT_FAKESHIELD", - "MT_FAKEITEM", + "MT_ROCKETSNEAKER", // Rocket sneakers + + "MT_EGGMANITEM", // Eggman items + "MT_EGGMANITEM_SHIELD", "MT_BANANA", // Banana Stuff "MT_BANANA_SHIELD", @@ -7305,7 +7642,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_JAWZ", // Jawz stuff "MT_JAWZ_DUD", - "MT_JAWZ_SHIELD", + "MT_JAWZ_SHIELD", "MT_PLAYERRETICULE", // Jawz reticule @@ -7321,9 +7658,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_BALLHOG", // Ballhog "MT_BALLHOGBOOM", - "MT_BLUELIGHTNING", // Grow/shrink stuff - "MT_BLUEEXPLOSION", - "MT_LIGHTNING", + "MT_SPB", // Self-Propelled Bomb + "MT_SPBEXPLOSION", "MT_THUNDERSHIELD", // Thunder Shield stuff @@ -7413,6 +7749,149 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_KARMAHITBOX", "MT_KARMAWHEEL", + "MT_BATTLEPOINT", + + "MT_FZEROBOOM", + + // Various plants + "MT_SONICBUSH", + "MT_SHRUB", + "MT_TALLBUSH", + "MT_AZURECITYTREE", + + // Marble Zone + "MT_FLAMEPARTICLE", + "MT_MARBLETORCH", + "MT_MARBLELIGHT", + "MT_MARBLEBURNER", + + // CD Special Stage + "MT_CDUFO", + + // Rusty Rig + "MT_RUSTYLAMP_ORANGE", + "MT_RUSTYCHAIN", + + // D2 Balloon Panic + "MT_BALLOON", + + // Smokin' & Vapin' (Don't try this at home, kids!) + "MT_PETSMOKER", + "MT_PETSMOKE", + "MT_VVVAPE", + + // Hill Top Zone + "MT_HTZTREE", + "MT_HTZBUSH", + + // Ports of gardens + "MT_SGVINE1", + "MT_SGVINE2", + "MT_SGVINE3", + "MT_PGTREE", + "MT_PGFLOWER1", + "MT_PGFLOWER2", + "MT_PGFLOWER3", + "MT_PGBUSH", + "MT_DHPILLAR", + + // Midnight Channel stuff: + "MT_SPOTLIGHT", // Spotlight Object + "MT_RANDOMSHADOW", // Random static Shadows. + "MT_ROAMINGSHADOW", // Roaming Shadows. + "MT_MAYONAKAARROW", // Arrow static signs for Mayonaka + + // Mementos stuff + "MT_REAPERWAYPOINT", + "MT_REAPER", + "MT_MEMENTOSTP", + "MT_MEMENTOSPARTICLE", + + "MT_JACKINTHEBOX", + + // Color Drive: + "MT_CDMOON", + "MT_CDBUSH", + "MT_CDTREEA", + "MT_CDTREEB", + + // Daytona Speedway + "MT_PINETREE", + "MT_PINETREE_SIDE", + + // Egg Zeppelin + "MT_EZZPROPELLER", + "MT_EZZPROPELLER_BLADE", + + // Desert Palace + "MT_DP_PALMTREE", + + // Aurora Atoll + "MT_AAZTREE_HELPER", + "MT_AAZTREE_SEG", + "MT_AAZTREE_COCONUT", + "MT_AAZTREE_LEAF", + + // Barren Badlands + "MT_BBZDUST", + "MT_FROGGER", + "MT_FROGTONGUE", + "MT_FROGTONGUE_JOINT", + "MT_ROBRA", + "MT_ROBRA_HEAD", + "MT_ROBRA_JOINT", + "MT_BLUEROBRA", + "MT_BLUEROBRA_HEAD", + "MT_BLUEROBRA_JOINT", + + // Eerie Grove + "MT_EERIEFOG", + "MT_EERIEFOGGEN", + + // SMK ports + "MT_SMK_PIPE", + "MT_SMK_MOLESPAWNER", + "MT_SMK_MOLE", + "MT_SMK_THWOMP", + "MT_SMK_SNOWBALL", + "MT_SMK_ICEBLOCK", + "MT_SMK_ICEBLOCK_SIDE", + "MT_SMK_ICEBLOCK_DEBRIS", + + // Ezo's maps + "MT_BLUEFIRE", + "MT_GREENFIRE", + "MT_REGALCHEST", + "MT_CHIMERASTATUE", + "MT_DRAGONSTATUE", + "MT_LIZARDMANSTATUE", + "MT_PEGASUSSTATUE", + "MT_ZELDAFIRE", + "MT_GANBARETHING", + "MT_GANBAREDUCK", + "MT_GANBARETREE", + "MT_MONOKUMA", + "MT_REDZELDAFIRE", + "MT_BOWLINGPIN", + "MT_MERRYAMBIENCE", + "MT_TWINKLECARTAMBIENCE", + "MT_EXPLODINGBARREL", + "MT_MERRYHORSE", + "MT_ARIDTOAD", + "MT_BLUEFRUIT", + "MT_ORANGEFRUIT", + "MT_REDFRUIT", + "MT_PINKFRUIT", + "MT_ADVENTURESPIKEA", + "MT_ADVENTURESPIKEB", + "MT_ADVENTURESPIKEC", + "MT_BOOSTPROMPT", + "MT_BOOSTOFF", + "MT_BOOSTON", + "MT_LIZARDMAN", + "MT_LIONMAN", + "MT_MOUSEMAN", + #ifdef SEENAMES "MT_NAMECHECK", #endif @@ -7743,6 +8222,7 @@ static const char *const KARTSTUFF_LIST[] = { "THROWDIR", "LAPANIMATION", + "LAPHAND", "CARDANIMATION", "VOICES", "TAUNTVOICES", @@ -7769,7 +8249,9 @@ static const char *const KARTSTUFF_LIST[] = { "ACCELBOOST", "BOOSTCAM", "DESTBOOSTCAM", + "TIMEOVERCAM", "AIZDRIFTSTRAT", + "BRAKEDRIFT", "ITEMROULETTE", "ROULETTETYPE", @@ -7787,7 +8269,6 @@ static const char *const KARTSTUFF_LIST[] = { "SQUISHEDTIMER", "ROCKETSNEAKERTIMER", "INVINCIBILITYTIMER", - "DEATHSENTENCE", "EGGMANHELD", "EGGMANEXPLODE", "EGGMANBLAME", @@ -7803,6 +8284,7 @@ static const char *const KARTSTUFF_LIST[] = { "COMEBACKPOINTS", "COMEBACKMODE", "WANTED", + "YOUGOTEM", }; static const char *const HUDITEMS_LIST[] = { diff --git a/src/doomstat.h b/src/doomstat.h index 8e26d100..f45651d1 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -302,7 +302,7 @@ enum TypeOfLevel TOL_2D = 0x0100, ///< 2D TOL_MARIO = 0x0200, ///< Mario TOL_NIGHTS = 0x0400, ///< NiGHTS - //TOL_ERZ3 = 0x0800, ///< ERZ3 + TOL_TV = 0x0800, ///< Midnight Channel specific: draw TV like overlay on HUD TOL_XMAS = 0x1000 ///< Christmas NiGHTS //TOL_KART = 0x4000 ///< Kart 32768 }; @@ -458,9 +458,9 @@ extern boolean comeback; extern SINT8 battlewanted[4]; extern tic_t wantedcalcdelay; extern tic_t indirectitemcooldown; -extern tic_t spbincoming; -extern UINT8 spbplayer; extern tic_t mapreset; +extern UINT8 nospectategrief; +extern boolean thwompsactive; extern boolean legitimateexit; extern boolean comebackshowninfo; diff --git a/src/g_game.c b/src/g_game.c index ee1ee053..fecef69a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -264,9 +264,9 @@ SINT8 pickedvote; // What vote the host rolls SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points tic_t wantedcalcdelay; // Time before it recalculates WANTED tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded -tic_t spbincoming; // Timer before SPB hits, can switch targets at this point -UINT8 spbplayer; // Player num that used the last SPB tic_t mapreset; // Map reset delay when enough players have joined an empty game +UINT8 nospectategrief; // How many players need to be in-game to eliminate last; for preventing spectate griefing +boolean thwompsactive; // Thwomps activate on lap 2 // Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players) boolean legitimateexit; // Did this client actually finish the match? @@ -425,7 +425,7 @@ consvar_t cv_chatspamprotection = {"chatspamprotection", "On", CV_SAVE, CV_OnOff consvar_t cv_chatbacktint = {"chatbacktint", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // old shit console chat. (mostly exists for stuff like terminal, not because I cared if anyone liked the old chat.) -static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {0, NULL}}; +static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {2, "Window (Hidden)"}, {0, NULL}}; consvar_t cv_consolechat = {"chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; /*consvar_t cv_crosshair = {"crosshair", "Off", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -1839,6 +1839,9 @@ boolean G_Responder(event_t *ev) if (players[displayplayer].exiting) continue; + if (players[displayplayer].pflags & PF_TIMEOVER) + continue; + // I don't know if we want this actually, but I'll humor the suggestion anyway if (G_BattleGametype()) { @@ -2100,10 +2103,12 @@ void G_Ticker(boolean run) G_ClearRetryFlag(); // Costs a life to retry ... unless the player in question is dead already. - if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE) + /*if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE) players[consoleplayer].lives -= 1; - G_DoReborn(consoleplayer); + G_DoReborn(consoleplayer);*/ + + D_MapChange(gamemap, gametype, cv_kartencore.value, true, 1, false, false); } for (i = 0; i < MAXPLAYERS; i++) @@ -2353,6 +2358,7 @@ void G_PlayerReborn(INT32 player) INT32 itemamount; INT32 itemroulette; INT32 roulettetype; + INT32 growshrinktimer; INT32 bumper; INT32 comebackpoints; INT32 wanted; @@ -2365,7 +2371,7 @@ void G_PlayerReborn(INT32 player) exiting = players[player].exiting; jointime = players[player].jointime; spectator = players[player].spectator; - pflags = (players[player].pflags & (PF_TIMEOVER|PF_FLIPCAM|PF_TAGIT|PF_TAGGED|PF_ANALOGMODE)); + pflags = (players[player].pflags & (PF_TIMEOVER|PF_FLIPCAM|PF_TAGIT|PF_TAGGED|PF_ANALOGMODE|PF_WANTSTOJOIN)); // As long as we're not in multiplayer, carry over cheatcodes from map to map if (!(netgame || multiplayer)) @@ -2416,6 +2422,7 @@ void G_PlayerReborn(INT32 player) roulettetype = 0; itemtype = 0; itemamount = 0; + growshrinktimer = 0; bumper = (G_BattleGametype() ? cv_kartbumpers.value : 0); comebackpoints = 0; wanted = 0; @@ -2439,6 +2446,9 @@ void G_PlayerReborn(INT32 player) itemamount = players[player].kartstuff[k_itemamount]; } + // Keep Shrink status, remove Grow status + growshrinktimer = min(players[player].kartstuff[k_growshrinktimer], 0); + bumper = players[player].kartstuff[k_bumper]; comebackpoints = players[player].kartstuff[k_comebackpoints]; wanted = players[player].kartstuff[k_wanted]; @@ -2503,6 +2513,7 @@ void G_PlayerReborn(INT32 player) p->kartstuff[k_roulettetype] = roulettetype; 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; @@ -2935,7 +2946,7 @@ void G_DoReborn(INT32 playernum) if (oldmo) G_ChangePlayerReferences(oldmo, players[playernum].mo); } - else if (countdowntimeup || (!multiplayer && gametype == GT_COOP)) + /*else if (countdowntimeup || (!multiplayer && !modeattacking)) { // reload the level from scratch if (countdowntimeup) @@ -3004,7 +3015,7 @@ void G_DoReborn(INT32 playernum) #ifdef HAVE_BLUA } #endif - } + }*/ else { // respawn at the start @@ -3051,7 +3062,7 @@ void G_ExitLevel(void) } if (netgame || multiplayer) - CONS_Printf(M_GetText("The round has ended.\n")); + CON_LogMessage(M_GetText("The round has ended.\n")); // Remove CEcho text on round end. HU_DoCEcho(""); @@ -3119,7 +3130,7 @@ boolean G_GametypeHasSpectators(void) #if 0 return (gametype != GT_COOP && gametype != GT_COMPETITION && gametype != GT_RACE); #else - return (!splitscreen);//true; + return (netgame); //true #endif } @@ -4023,6 +4034,7 @@ static void M_ForceLoadGameResponse(INT32 ch) displayplayer = consoleplayer; multiplayer = false; splitscreen = 0; + SplitScreen_OnChange(); // not needed? if (setsizeneeded) R_ExecuteSetViewSize(); @@ -4112,6 +4124,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) displayplayer = consoleplayer; multiplayer = false; splitscreen = 0; + SplitScreen_OnChange(); // not needed? // G_DeferedInitNew(sk_medium, G_BuildMapName(1), 0, 0, 1); if (setsizeneeded) @@ -4339,13 +4352,13 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool { char *title = G_BuildMapTitle(gamemap); - CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); + CON_LogMessage(va(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap))); if (title) { - CONS_Printf(": %s", title); + CON_LogMessage(va(": %s", title)); Z_Free(title); } - CONS_Printf("\"\n"); + CON_LogMessage("\"\n"); } } @@ -4496,6 +4509,13 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) G_CopyTiccmd(cmd, &oldcmd, 1); + // SRB2kart: Copy-pasted from ticcmd building, removes that crappy demo cam + if (((players[displayplayer].mo && players[displayplayer].speed > 0) // Moving + || (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn + || (players[displayplayer].spectator || objectplacing)) // Not a physical player + && !(players[displayplayer].kartstuff[k_spinouttimer] && players[displayplayer].kartstuff[k_sneakertimer])) // Spinning and boosting cancels out spinout + localangle += (cmd->angleturn<<16); + if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) { // end of demo data stream diff --git a/src/g_game.h b/src/g_game.h index e34a6986..7620861e 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -62,6 +62,7 @@ extern consvar_t cv_turnaxis2,cv_moveaxis2,cv_brakeaxis2,cv_aimaxis2,cv_lookaxis extern consvar_t cv_turnaxis3,cv_moveaxis3,cv_brakeaxis3,cv_aimaxis3,cv_lookaxis3,cv_fireaxis3,cv_driftaxis3; extern consvar_t cv_turnaxis4,cv_moveaxis4,cv_brakeaxis4,cv_aimaxis4,cv_lookaxis4,cv_fireaxis4,cv_driftaxis4; extern consvar_t cv_ghost_besttime, cv_ghost_bestlap, cv_ghost_last, cv_ghost_guest, cv_ghost_staff; +extern consvar_t cv_splitplayers; typedef enum { @@ -188,7 +189,6 @@ void G_StopMetalDemo(void); ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(void); void G_StopDemo(void); boolean G_CheckDemoStatus(void); -char *G_DemoPlayerName(char *defdemoname); boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); diff --git a/src/g_input.c b/src/g_input.c index 101fa8e4..fa23c5d4 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1321,21 +1321,21 @@ void G_Controldefault(void) gamecontrolbis[gc_accelerate ][0] = KEY_2JOY1+0; // A gamecontrolbis[gc_lookback ][0] = KEY_2JOY1+1; // X gamecontrolbis[gc_brake ][0] = KEY_2JOY1+2; // B - gamecontrolbis[gc_fire ][0] = KEY_2JOY1+4; // LB + gamecontrolbis[gc_fire ][0] = KEY_2JOY1+4; // LB gamecontrolbis[gc_drift ][0] = KEY_2JOY1+5; // RB // Player 3 controls gamecontrol3[gc_accelerate ][0] = KEY_3JOY1+0; // A gamecontrol3[gc_lookback ][0] = KEY_3JOY1+1; // X gamecontrol3[gc_brake ][0] = KEY_3JOY1+2; // B - gamecontrol3[gc_fire ][0] = KEY_3JOY1+4; // LB + gamecontrol3[gc_fire ][0] = KEY_3JOY1+4; // LB gamecontrol3[gc_drift ][0] = KEY_3JOY1+5; // RB // Player 4 controls gamecontrol4[gc_accelerate ][0] = KEY_4JOY1+0; // A gamecontrol4[gc_lookback ][0] = KEY_4JOY1+1; // X gamecontrol4[gc_brake ][0] = KEY_4JOY1+2; // B - gamecontrol4[gc_fire ][0] = KEY_4JOY1+4; // LB + gamecontrol4[gc_fire ][0] = KEY_4JOY1+4; // LB gamecontrol4[gc_drift ][0] = KEY_4JOY1+5; // RB } //#endif diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 145a0150..2a0957b9 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1328,6 +1328,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) frame = (spr->mobj->frame & FF_FRAMEMASK) % md2->model->header.numFrames; buff = md2->model->glCommandBuffer; curr = &md2->model->frames[frame]; +#if 0 if (cv_grmd2.value == 1 && tics <= durs) { // frames are handled differently for states with FF_ANIMATE, so get the next frame differently for the interpolation @@ -1348,6 +1349,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) } } } +#endif //Hurdler: it seems there is still a small problem with mobj angle p.x = FIXED_TO_FLOAT(spr->mobj->x); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 2632197c..614ca49a 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -87,7 +87,6 @@ patch_t *rmatcico; patch_t *bmatcico; patch_t *tagico; patch_t *tallminus; -patch_t *iconprefix[MAXSKINS]; // minimap icons //------------------------------------------- // coop hud @@ -109,8 +108,8 @@ static patch_t *crosshair[HU_CROSSHAIRS]; // 3 precached crosshair graphics // protos. // ------- static void HU_DrawRankings(void); -static void HU_DrawCoopOverlay(void); -static void HU_DrawNetplayCoopOverlay(void); +//static void HU_DrawCoopOverlay(void); +//static void HU_DrawNetplayCoopOverlay(void); //====================================================================== // KEYBOARD LAYOUTS FOR ENTERING TEXT @@ -386,12 +385,11 @@ static void HU_removeChatText_Log(void) chat_nummsg_log--; // lost 1 msg. } -void HU_AddChatText(const char *text) +void HU_AddChatText(const char *text, boolean playsound) { - if (cv_chatnotifications.value) + if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat. S_StartSound(NULL, sfx_radio); - - // TODO: check if we're oversaturating the log (we can only log CHAT_BUFSIZE messages.) + // reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game. if (chat_nummsg_log >= CHAT_BUFSIZE) HU_removeChatText_Log(); @@ -405,6 +403,11 @@ void HU_AddChatText(const char *text) strcpy(chat_mini[chat_nummsg_min], text); chat_timers[chat_nummsg_min] = TICRATE*cv_chattime.value; chat_nummsg_min++; + + if (OLDCHAT) // if we're using oldchat, print directly in console + CONS_Printf("%s\n", text); + else // if we aren't, still save the message to log.txt + CON_LogMessage(va("%s\n", text)); } /** Runs a say command, sending an ::XD_SAY message. @@ -437,7 +440,7 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) if (CHAT_MUTE) // TODO: Per Player mute. { - HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85")); + HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); return; } @@ -478,7 +481,7 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) // let it slide else { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'."); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); return; } } @@ -487,7 +490,7 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) { if (msg[5] != ' ') { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'."); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); return; } } @@ -500,7 +503,7 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! else { - HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target)); // same + HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same return; } buf[0] = target; @@ -716,7 +719,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) || target == 0 // To everyone || consoleplayer == target-1) // To you { - const char *prefix = "", *cstart = "", *cend = "", *adminchar = "\x82~\x83", *remotechar = "\x82@\x83", *fmt, *fmt2, *textcolor = "\x80"; + const char *prefix = "", *cstart = "", *cend = "", *adminchar = "\x82~\x83", *remotechar = "\x82@\x83", *fmt2, *textcolor = "\x80"; char *tempchar = NULL; // player is a spectator? @@ -796,16 +799,12 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) // name, color end, and the message itself. // '\4' makes the message yellow and beeps; '\3' just beeps. if (action) - { - fmt = "\3* %s%s%s%s \x82%s%s\n"; // don't make /me yellow, yellow will be for mentions and PMs! fmt2 = "* %s%s%s%s \x82%s%s"; - } else if (target-1 == consoleplayer) // To you { prefix = "\x82[PM]"; cstart = "\x82"; textcolor = "\x82"; - fmt = "\4%s<%s%s>%s\x80 %s%s\n"; // make this yellow, however. fmt2 = "%s<%s%s>%s\x80 %s%s"; } else if (target > 0) // By you, to another player @@ -814,15 +813,11 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) dispname = player_names[target-1]; prefix = "\x82[TO]"; cstart = "\x82"; - fmt = "\4%s<%s%s>%s\x80 %s%s\n"; // make this yellow, however. fmt2 = "%s<%s%s>%s\x80 %s%s"; } else // To everyone or sayteam, it doesn't change anything. - { - fmt = "\3%s<%s%s%s>\x80 %s%s\n"; fmt2 = "%s<%s%s%s>\x80 %s%s"; - } /*else // To your team { if (players[playernum].ctfteam == 1) // red @@ -836,12 +831,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) fmt2 = "%s<%s%s>\x80%s %s%s"; }*/ - HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg)); // add it reguardless, in case we decide to change our mind about our chat type. - - if OLDCHAT - CONS_Printf(fmt, prefix, cstart, dispname, cend, textcolor, msg); - else - CON_LogMessage(va(fmt, prefix, cstart, dispname, cend, textcolor, msg)); // save to log.txt + HU_AddChatText(va(fmt2, prefix, cstart, dispname, cend, textcolor, msg), cv_chatnotifications.value); // add to chat if (tempchar) Z_Free(tempchar); @@ -968,7 +958,7 @@ static void HU_queueChatChar(INT32 c) // last minute mute check if (CHAT_MUTE) { - HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85")); + HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); return; } @@ -983,7 +973,7 @@ static void HU_queueChatChar(INT32 c) // teamtalk can't send PMs, just don't send it, else everyone would be able to see it, and no one wants to see your sex RP sicko. if (teamtalk) { - HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85")); + HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85"), false); return; } @@ -999,7 +989,7 @@ static void HU_queueChatChar(INT32 c) // let it slide else { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'."); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); return; } } @@ -1008,7 +998,7 @@ static void HU_queueChatChar(INT32 c) { if (msg[5] != ' ') { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'."); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); return; } } @@ -1021,7 +1011,7 @@ static void HU_queueChatChar(INT32 c) target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! else { - HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target)); // same + HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same return; } // we need to get rid of the /pm @@ -1066,6 +1056,26 @@ boolean HU_Responder(event_t *ev) // only KeyDown events now... + // Shoot, to prevent P1 chatting from ruining the game for everyone else, it's either: + // A. completely disallow opening chat entirely in online splitscreen + // or B. iterate through all controls to make sure it's bound to player 1 before eating + // You can see which one I chose. + // (Unless if you're sharing a keyboard, since you probably establish when you start chatting that you have dibs on it...) + // (Ahhh, the good ol days when I was a kid who couldn't afford an extra USB controller...) + + if (ev->data1 >= KEY_MOUSE1) + { + INT32 i; + for (i = 0; i < num_gamecontrols; i++) + { + if (gamecontrol[i][0] == ev->data1 || gamecontrol[i][1] == ev->data1) + break; + } + + if (i == num_gamecontrols) + return false; + } + if (!chat_on) { // enter chat mode @@ -1269,6 +1279,7 @@ static void HU_drawMiniChat(void) { INT32 x = chatx+2; INT32 charwidth = 4, charheight = 6; + INT32 boxw = cv_chatwidth.value; INT32 dx = 0, dy = 0; size_t i = chat_nummsg_min; boolean prev_linereturn = false; // a hack to prevent double \n while I have no idea why they happen in the first place. @@ -1280,9 +1291,12 @@ static void HU_drawMiniChat(void) if (!chat_nummsg_min) return; // needless to say it's useless to do anything if we don't have anything to draw. + if (splitscreen > 1) + boxw = max(64, boxw/2); + for (; i>0; i--) { - const char *msg = CHAT_WordWrap(x+2, cv_chatwidth.value-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]); + const char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]); size_t j = 0; INT32 linescount = 0; @@ -1315,7 +1329,7 @@ static void HU_drawMiniChat(void) } prev_linereturn = false; dx += charwidth; - if (dx >= cv_chatwidth.value) + if (dx >= boxw) { dx = 0; linescount += 1; @@ -1326,7 +1340,17 @@ static void HU_drawMiniChat(void) msglines += linescount+1; } - y = chaty - charheight*(msglines+1) - (cv_kartspeedometer.value ? 16 : 0); + y = chaty - charheight*(msglines+1); + + if (splitscreen) + { + y -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + y += 16; + } + else + y -= (cv_kartspeedometer.value ? 16 : 0); + dx = 0; dy = 0; i = 0; @@ -1338,7 +1362,7 @@ static void HU_drawMiniChat(void) INT32 timer = ((cv_chattime.value*TICRATE)-chat_timers[i]) - cv_chattime.value*TICRATE+9; // see below... INT32 transflag = (timer >= 0 && timer <= 9) ? (timer*V_10TRANS) : 0; // you can make bad jokes out of this one. size_t j = 0; - const char *msg = CHAT_WordWrap(x+2, cv_chatwidth.value-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it. + const char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it. UINT8 *colormap = NULL; while(msg[j]) // iterate through msg @@ -1376,7 +1400,7 @@ static void HU_drawMiniChat(void) dx += charwidth; prev_linereturn = false; - if (dx >= cv_chatwidth.value) + if (dx >= boxw) { dx = 0; dy += charheight; @@ -1397,26 +1421,45 @@ static void HU_drawMiniChat(void) static void HU_drawChatLog(INT32 offset) { INT32 charwidth = 4, charheight = 6; + INT32 boxw = cv_chatwidth.value, boxh = cv_chatheight.value; INT32 x = chatx+2, y, dx = 0, dy = 0; UINT32 i = 0; INT32 chat_topy, chat_bottomy; + INT32 highlight = HU_GetHighlightColor(); boolean atbottom = false; // make sure that our scroll position isn't "illegal"; if (chat_scroll > chat_maxscroll) chat_scroll = chat_maxscroll; - y = chaty - offset*charheight - (chat_scroll*charheight) - cv_chatheight.value*charheight - 12 - (cv_kartspeedometer.value ? 16 : 0); - chat_topy = y + chat_scroll*charheight; - chat_bottomy = chat_topy + cv_chatheight.value*charheight; + if (splitscreen) + { + boxh = max(6, boxh/2); + if (splitscreen > 1) + boxw = max(64, boxw/2); + } - V_DrawFillConsoleMap(chatx, chat_topy, cv_chatwidth.value, cv_chatheight.value*charheight +2, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); // log box + y = chaty - offset*charheight - (chat_scroll*charheight) - boxh*charheight - 12; + + if (splitscreen) + { + y -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + y += 16; + } + else + y -= (cv_kartspeedometer.value ? 16 : 0); + + chat_topy = y + chat_scroll*charheight; + chat_bottomy = chat_topy + boxh*charheight; + + V_DrawFillConsoleMap(chatx, chat_topy, boxw, boxh*charheight +2, 239|V_SNAPTOBOTTOM|V_SNAPTOLEFT); // log box for (i=0; i= cv_chatwidth.value-charwidth-2 && i= HU_FONTSTART) // end of message shouldn't count, nor should invisible characters!!!! + if (dx >= boxw-charwidth-2 && i= HU_FONTSTART) // end of message shouldn't count, nor should invisible characters!!!! { dx = 0; dy += charheight; @@ -1466,10 +1509,10 @@ static void HU_drawChatLog(INT32 offset) // getmaxscroll through a lazy hack. We do all these loops, so let's not do more loops that are gonna lag the game more. :P chat_maxscroll = (dy/charheight); // welcome to C, we don't know what min() and max() are. - if (chat_maxscroll <= (UINT32)cv_chatheight.value) + if (chat_maxscroll <= (UINT32)boxh) chat_maxscroll = 0; else - chat_maxscroll -= cv_chatheight.value; + chat_maxscroll -= boxh; // if we're not bound by the time, autoscroll for next frame: if (atbottom) @@ -1480,12 +1523,12 @@ static void HU_drawChatLog(INT32 offset) if (chat_scroll > 0) { V_DrawCharacter(chatx-9, ((justscrolledup) ? (chat_topy-1) : (chat_topy)), - '\x1A' | V_SNAPTOBOTTOM | V_SNAPTOLEFT, false); // up arrow + '\x1A' | V_SNAPTOBOTTOM | V_SNAPTOLEFT | highlight, false); // up arrow } if (chat_scroll < chat_maxscroll) { V_DrawCharacter(chatx-9, chat_bottomy-((justscrolleddown) ? 5 : 6), - '\x1B' | V_SNAPTOBOTTOM | V_SNAPTOLEFT, false); // down arrow + '\x1B' | V_SNAPTOBOTTOM | V_SNAPTOLEFT | highlight, false); // down arrow } justscrolleddown = false; @@ -1502,13 +1545,26 @@ static INT16 typelines = 1; // number of drawfill lines we need. it's some weird static void HU_DrawChat(void) { INT32 charwidth = 4, charheight = 6; - INT32 t = 0, c = 0, y = chaty - (typelines*charheight) - (cv_kartspeedometer.value ? 16 : 0); + INT32 boxw = cv_chatwidth.value; + INT32 t = 0, c = 0, y = chaty - (typelines*charheight); UINT32 i = 0, saylen = strlen(w_chat); // You learn new things everyday! INT32 cflag = 0; const char *ntalk = "Say: ", *ttalk = "Team: "; const char *talk = ntalk; const char *mute = "Chat has been muted."; + if (splitscreen) + { + y -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + { + y += 16; + boxw = max(64, boxw/2); + } + } + else + y -= (cv_kartspeedometer.value ? 16 : 0); + if (teamtalk) { talk = ttalk; @@ -1527,7 +1583,7 @@ static void HU_DrawChat(void) cflag = V_GRAYMAP; // set text in gray if chat is muted. } - V_DrawFillConsoleMap(chatx, y-1, cv_chatwidth.value, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT); + V_DrawFillConsoleMap(chatx, y-1, boxw, (typelines*charheight), 239 | V_SNAPTOBOTTOM | V_SNAPTOLEFT); while (talk[i]) { @@ -1560,7 +1616,7 @@ static void HU_DrawChat(void) boolean skippedline = false; if (c_input == (i+1)) { - int cursorx = (c+charwidth < cv_chatwidth.value-charwidth) ? (chatx + 2 + c+charwidth) : (chatx+1); // we may have to go down. + int cursorx = (c+charwidth < boxw-charwidth) ? (chatx + 2 + c+charwidth) : (chatx+1); // we may have to go down. int cursory = (cursorx != chatx+1) ? (y) : (y+charheight); if (hu_tick < 4) V_DrawChatCharacter(cursorx, cursory+1, '_' |V_SNAPTOBOTTOM|V_SNAPTOLEFT|t, !cv_allcaps.value, NULL); @@ -1580,7 +1636,7 @@ static void HU_DrawChat(void) V_DrawChatCharacter(chatx + c + 2, y, w_chat[i++] | V_SNAPTOBOTTOM|V_SNAPTOLEFT | t, !cv_allcaps.value, NULL); c += charwidth; - if (c > cv_chatwidth.value-(charwidth*2) && !skippedline) + if (c > boxw-(charwidth*2) && !skippedline) { c = 0; y += charheight; @@ -1593,6 +1649,14 @@ static void HU_DrawChat(void) { INT32 count = 0; INT32 p_dispy = chaty - charheight -1; + if (splitscreen) + { + p_dispy -= BASEVIDHEIGHT/2; + if (splitscreen > 1) + p_dispy += 16; + } + else + p_dispy -= (cv_kartspeedometer.value ? 16 : 0); i = 0; for(i=0; (i 8) - { - V_DrawFill(160, 26, 1, 154, 0); // Draw a vertical line to separate the two sides. - V_DrawFill(1, 180, 318, 1, 0); // And a horizontal line near the bottom. - rightoffset = 156; - } - - for (i = 0; i < scorelines; i++) - { - char strtime[MAXPLAYERNAME+1]; - - if (players[tab[i].num].spectator || !players[tab[i].num].mo) - continue; //ignore them. - - if (!splitscreen) // don't draw it on splitscreen, - { - if (!(tab[i].num == serverplayer)) - HU_drawPing(x+ 253, y+2, playerpingtable[tab[i].num], false); - } - - if (scorelines > 8) - strlcpy(strtime, tab[i].name, 6); - else - STRBUFCPY(strtime, tab[i].name); - - V_DrawString(x + 20, y, - ((tab[i].num == whiteplayer) - ? hilicol|V_ALLOWLOWERCASE - : V_ALLOWLOWERCASE), - strtime); - - if (players[tab[i].num].mo->color) - { - colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); - if (players[tab[i].num].mo->colorized) - colormap = R_GetTranslationColormap(TC_RAINBOW, players[tab[i].num].mo->color, GTC_CACHE); - else - colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); - - V_DrawSmallMappedPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); - if (G_BattleGametype() && players[tab[i].num].kartstuff[k_bumper] > 0) - { - INT32 bumperx = x-5; - for (j = 0; j < players[tab[i].num].kartstuff[k_bumper]; j++) - { - bumperx -= 3; - V_DrawSmallMappedPatch(bumperx, y+6, 0, W_CachePatchName("K_BLNICO", PU_CACHE), colormap); - } - } - } - - if (G_BattleGametype() && players[tab[i].num].kartstuff[k_bumper] <= 0) - V_DrawSmallScaledPatch(x-2, y-4, 0, W_CachePatchName("K_NOBLNS", PU_CACHE)); - - if (G_RaceGametype()) - { -#define timestring(time) va("%i'%02i\"%02i", G_TicsToMinutes(time, true), G_TicsToSeconds(time), G_TicsToCentiseconds(time)) - if (players[tab[i].num].exiting) - V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime)); - else if (players[tab[i].num].pflags & PF_TIMEOVER) - V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST."); - else if (circuitmap) - V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count)); -#undef timestring - } - else - V_DrawRightAlignedString(x+rightoffset, y, 0, va("%u", tab[i].count)); - - y += 16; - if (i == 7) - { - y = 32; - x += BASEVIDWIDTH/2; - } - } -} // // HU_DrawTeamTabRankings @@ -2350,15 +2331,15 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (players[tab[i].num].powers[pw_super]) { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); - V_DrawSmallMappedPatch (x, y-4, 0, superprefix[players[tab[i].num].skin], colormap); + V_DrawSmallMappedPatch (x, y-4, 0, facewantprefix[players[tab[i].num].skin], colormap); } else { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); if (players[tab[i].num].health <= 0) - V_DrawSmallTranslucentMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); + V_DrawSmallTranslucentMappedPatch (x, y-4, 0, facerankprefix[players[tab[i].num].skin], colormap); else - V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); + V_DrawSmallMappedPatch (x, y-4, 0, facerankprefix[players[tab[i].num].skin], colormap); } V_DrawRightAlignedThinString(x+120, y-1, ((players[tab[i].num].health > 0) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); if (!splitscreen) @@ -2412,13 +2393,13 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline { colormap = colormaps; if (players[tab[i].num].powers[pw_super]) - V_DrawSmallScaledPatch (x, y-4, 0, superprefix[players[tab[i].num].skin]); + V_DrawSmallScaledPatch (x, y-4, 0, facewantprefix[players[tab[i].num].skin]); else { if (players[tab[i].num].health <= 0) - V_DrawSmallTranslucentPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin]); + V_DrawSmallTranslucentPatch (x, y-4, 0, facerankprefix[players[tab[i].num].skin]); else - V_DrawSmallScaledPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin]); + V_DrawSmallScaledPatch (x, y-4, 0, facerankprefix[players[tab[i].num].skin]); } } else @@ -2426,15 +2407,15 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline if (players[tab[i].num].powers[pw_super]) { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); - V_DrawSmallMappedPatch (x, y-4, 0, superprefix[players[tab[i].num].skin], colormap); + V_DrawSmallMappedPatch (x, y-4, 0, facewantprefix[players[tab[i].num].skin], colormap); } else { colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo ? players[tab[i].num].mo->color : tab[i].color, GTC_CACHE); if (players[tab[i].num].health <= 0) - V_DrawSmallTranslucentMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); + V_DrawSmallTranslucentMappedPatch (x, y-4, 0, facerankprefix[players[tab[i].num].skin], colormap); else - V_DrawSmallMappedPatch (x, y-4, 0, faceprefix[players[tab[i].num].skin], colormap); + V_DrawSmallMappedPatch (x, y-4, 0, facerankprefix[players[tab[i].num].skin], colormap); } } @@ -2496,16 +2477,17 @@ void HU_DrawEmeralds(INT32 x, INT32 y, INT32 pemeralds) // static inline void HU_DrawSpectatorTicker(void) { - int i; - int length = 0, height = 174; - int totallength = 0, templength = 0; + INT32 i; + INT32 length = 0, height = 174; + INT32 totallength = 0, templength = -8; + INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2; for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].spectator) totallength += (signed)strlen(player_names[i]) * 8 + 16; - length -= (leveltime % (totallength + BASEVIDWIDTH)); - length += BASEVIDWIDTH; + length -= (leveltime % (totallength + dupadjust+8)); + length += dupadjust; for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].spectator) @@ -2513,15 +2495,18 @@ static inline void HU_DrawSpectatorTicker(void) char *pos; char initial[MAXPLAYERNAME+1]; char current[MAXPLAYERNAME+1]; + INT32 len; + + len = ((signed)strlen(player_names[i]) * 8 + 16); strcpy(initial, player_names[i]); pos = initial; - if (length >= -((signed)strlen(player_names[i]) * 8 + 16) && length <= BASEVIDWIDTH) + if (length >= -len) { - if (length < 0) + if (length < -8) { - UINT8 eatenchars = (UINT8)(abs(length) / 8 + 1); + UINT8 eatenchars = (UINT8)(abs(length) / 8); if (eatenchars <= strlen(initial)) { @@ -2529,7 +2514,7 @@ static inline void HU_DrawSpectatorTicker(void) // then compensate the drawing position. pos += eatenchars; strcpy(current, pos); - templength = length % 8 + 8; + templength = ((length + 8) % 8); } else { @@ -2543,10 +2528,11 @@ static inline void HU_DrawSpectatorTicker(void) templength = length; } - V_DrawString(templength, height + 8, V_TRANSLUCENT, current); + V_DrawString(templength - duptweak, height, V_TRANSLUCENT|V_ALLOWLOWERCASE, current); } - length += (signed)strlen(player_names[i]) * 8 + 16; + if ((length += len) >= dupadjust+8) + break; } } @@ -2561,6 +2547,8 @@ static void HU_DrawRankings(void) boolean completed[MAXPLAYERS]; UINT32 whiteplayer = MAXPLAYERS; + V_DrawFadeScreen(0xFF00, 16); // A little more readable, and prevents cheating the fades under other circumstances. + if (cons_menuhighlight.value) hilicol = cons_menuhighlight.value; else if (modeattacking) @@ -2570,9 +2558,9 @@ static void HU_DrawRankings(void) // draw the current gametype in the lower right if (modeattacking) - V_DrawString(4, 188, hilicol, "Record Attack"); + V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, "Record Attack"); else - V_DrawString(4, 188, hilicol, gametype_cons_t[gametype].strvalue); + V_DrawString(4, 188, hilicol|V_SNAPTOBOTTOM|V_SNAPTOLEFT, gametype_cons_t[gametype].strvalue); if (G_GametypeHasTeams()) { @@ -2661,21 +2649,18 @@ static void HU_DrawRankings(void) tab[i].name = NULL; tab[i].count = INT32_MAX; - if (!playeringame[i] || players[i].spectator) + if (!playeringame[i] || players[i].spectator || !players[i].mo) continue; numplayersingame++; } - if (netgame && numplayersingame <= 1) - K_drawKartFreePlay(leveltime); - for (j = 0; j < numplayersingame; j++) { UINT8 lowestposition = MAXPLAYERS; for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i] || players[i].spectator || completed[i]) + if (completed[i] || !playeringame[i] || players[i].spectator || !players[i].mo) continue; if (players[i].kartstuff[k_position] >= lowestposition) @@ -2712,16 +2697,16 @@ static void HU_DrawRankings(void) /*if (G_GametypeHasTeams()) HU_DrawTeamTabRankings(tab, whiteplayer); //separate function for Spazzo's silly request -- gotta fix this up later else if (scorelines > 10)*/ - HU_DrawTabRankings(((scorelines > 8) ? 32 : 40), 32, tab, scorelines, whiteplayer, hilicol); + HU_DrawTabRankings(((scorelines > 8) ? 32 : 40), 33, tab, scorelines, whiteplayer, hilicol); /*else HU_DrawDualTabRankings(32, 32, tab, scorelines, whiteplayer);*/ // draw spectators in a ticker across the bottom - if (!splitscreen && G_GametypeHasSpectators()) + if (netgame && G_GametypeHasSpectators()) HU_DrawSpectatorTicker(); } -static void HU_DrawCoopOverlay(void) +/*static void HU_DrawCoopOverlay(void) { if (token #ifdef HAVE_BLUA @@ -2777,7 +2762,7 @@ static void HU_DrawNetplayCoopOverlay(void) if (emeralds & (1 << i)) V_DrawScaledPatch(20 + (i * 20), 6, 0, emeraldpics[i]); } -} +}*/ // Interface to CECHO settings for the outside world, avoiding the diff --git a/src/hu_stuff.h b/src/hu_stuff.h index fc0e57a2..a9194975 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -76,16 +76,15 @@ extern patch_t *rmatcico; extern patch_t *bmatcico; extern patch_t *tagico; extern patch_t *tallminus; -extern patch_t *iconprefix[MAXSKINS]; #define CHAT_BUFSIZE 64 // that's enough messages, right? We'll delete the older ones when that gets out of hand. -#define OLDCHAT (cv_consolechat.value || dedicated || vid.width < 640) +#define OLDCHAT (cv_consolechat.value == 1 || dedicated || vid.width < 640) #define CHAT_MUTE (cv_mute.value && !(server || IsPlayerAdmin(consoleplayer))) // this still allows to open the chat but not to type. That's used for scrolling and whatnot. #define OLD_MUTE (OLDCHAT && cv_mute.value && !(server || IsPlayerAdmin(consoleplayer))) // this is used to prevent oldchat from opening when muted. // some functions -void HU_AddChatText(const char *text); +void HU_AddChatText(const char *text, boolean playsound); // set true when entering a chat message extern boolean chat_on; diff --git a/src/info.c b/src/info.c index 932ff21a..4028c187 100644 --- a/src/info.c +++ b/src/info.c @@ -56,12 +56,20 @@ char sprnames[NUMSPRITES + 1][5] = "SRBJ","SRBK","SRBL","SRBM","SRBN","SRBO", //SRB2kart Sprites "SPRG","BSPR","RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE", - "KINV","KINF","WIPD","DRIF","DUST","FITM","BANA","ORBN","JAWZ","SSMN", - "KRBM","BHOG","BHBM","BLIG","LIGH","THNS","SINK","SITR","KBLN","DEZL", - "POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO", - "CRAB","SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO", - "ITEM","ITMO","ITMI","ITMN","WANT","PBOM","RETI","AIDU","KSPK","LZI1", - "LZI2","KLIT","VIEW" + "KINV","KINF","WIPD","DRIF","BDRF","DUST","RSHE","FITM","BANA","ORBN", + "JAWZ","SSMN","KRBM","BHOG","BHBM","SPBM","THNS","SINK","SITR","KBLN", + "DEZL","POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM", + "SACO","CRAB","SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB", + "ARRO","ITEM","ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2","HIT3", + "RETI","AIDU","KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT","SBUS", + "SHRB","TWEE","MARB","FUFO","RUST","BLON","VAPE","HTZA","HTZB","SGVA", + "SGVB","SGVC","PGTR","PGF1","PGF2","PGF3","PGBH","DPLR","SPTL","ENM1", + "GARU","MARR","REAP","JITB","CDMO","CDBU","PINE","PPLR","DPPT","AATR", + "COCO","BDST","FROG","CBRA","HOLE","BBRA","EGFG","SMKP","MTYM","THWP", + "SNOB","ICEB","CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN", + "PGSS","ZTCH","MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE", + "TOAH","BFRT","OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ", + "WBLN","MSMF","XMS4","XMS5","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -96,25 +104,25 @@ state_t states[NUMSTATES] = {SPR_PLAY, 3, 1, {NULL}, 0, 0, S_KART_STND1_L}, // S_KART_STND2_L D {SPR_PLAY, 4, 1, {NULL}, 0, 0, S_KART_STND2_R}, // S_KART_STND1_R E {SPR_PLAY, 5, 1, {NULL}, 0, 0, S_KART_STND1_R}, // S_KART_STND2_R F - {SPR_PLAY, 6, 1, {NULL}, 0, 0, S_KART_WALK2}, // S_KART_WALK1 G - {SPR_PLAY, 7, 1, {NULL}, 0, 0, S_KART_WALK1}, // S_KART_WALK2 H - {SPR_PLAY, 8, 1, {NULL}, 0, 0, S_KART_WALK2_L}, // S_KART_WALK1_L I - {SPR_PLAY, 9, 1, {NULL}, 0, 0, S_KART_WALK1_L}, // S_KART_WALK2_L J - {SPR_PLAY, 10, 1, {NULL}, 0, 0, S_KART_WALK2_R}, // S_KART_WALK1_R K - {SPR_PLAY, 11, 1, {NULL}, 0, 0, S_KART_WALK1_R}, // S_KART_WALK2_R L - {SPR_PLAY, 12, 1, {NULL}, 0, 0, S_KART_RUN2}, // S_KART_RUN1 M - {SPR_PLAY, 13, 1, {NULL}, 0, 0, S_KART_RUN1}, // S_KART_RUN2 N - {SPR_PLAY, 14, 1, {NULL}, 0, 0, S_KART_RUN2_L}, // S_KART_RUN1_L O - {SPR_PLAY, 15, 1, {NULL}, 0, 0, S_KART_RUN1_L}, // S_KART_RUN2_L P - {SPR_PLAY, 16, 1, {NULL}, 0, 0, S_KART_RUN2_R}, // S_KART_RUN1_R Q - {SPR_PLAY, 17, 1, {NULL}, 0, 0, S_KART_RUN1_R}, // S_KART_RUN2_R R - {SPR_PLAY, 18, 1, {NULL}, 0, 0, S_KART_DRIFT2_L}, // S_KART_DRIFT1_L S - {SPR_PLAY, 19, 1, {NULL}, 0, 0, S_KART_DRIFT1_L}, // S_KART_DRIFT2_L T - {SPR_PLAY, 20, 1, {NULL}, 0, 0, S_KART_DRIFT2_R}, // S_KART_DRIFT1_R U - {SPR_PLAY, 21, 1, {NULL}, 0, 0, S_KART_DRIFT1_R}, // S_KART_DRIFT2_R V - {SPR_PLAY, 22, -1, {NULL}, 0, 0, S_KART_SPIN}, // S_KART_SPIN W - {SPR_PLAY, 22, 350, {NULL}, 0, 0, S_KART_STND1}, // S_KART_PAIN W - {SPR_PLAY, 23, 350, {NULL}, 0, 0, S_KART_STND1}, // S_KART_SQUISH X + {SPR_PLAY, 9, 1, {NULL}, 0, 0, S_KART_WALK2}, // S_KART_WALK1 J + {SPR_PLAY, 6, 1, {NULL}, 0, 0, S_KART_WALK1}, // S_KART_WALK2 G + {SPR_PLAY, 10, 1, {NULL}, 0, 0, S_KART_WALK2_L}, // S_KART_WALK1_L K + {SPR_PLAY, 7, 1, {NULL}, 0, 0, S_KART_WALK1_L}, // S_KART_WALK2_L H + {SPR_PLAY, 11, 1, {NULL}, 0, 0, S_KART_WALK2_R}, // S_KART_WALK1_R L + {SPR_PLAY, 8, 1, {NULL}, 0, 0, S_KART_WALK1_R}, // S_KART_WALK2_R I + {SPR_PLAY, 0, 1, {NULL}, 0, 0, S_KART_RUN2}, // S_KART_RUN1 A + {SPR_PLAY, 9, 1, {NULL}, 0, 0, S_KART_RUN1}, // S_KART_RUN2 J + {SPR_PLAY, 2, 1, {NULL}, 0, 0, S_KART_RUN2_L}, // S_KART_RUN1_L C + {SPR_PLAY, 10, 1, {NULL}, 0, 0, S_KART_RUN1_L}, // S_KART_RUN2_L K + {SPR_PLAY, 4, 1, {NULL}, 0, 0, S_KART_RUN2_R}, // S_KART_RUN1_R E + {SPR_PLAY, 11, 1, {NULL}, 0, 0, S_KART_RUN1_R}, // S_KART_RUN2_R L + {SPR_PLAY, 12, 1, {NULL}, 0, 0, S_KART_DRIFT2_L}, // S_KART_DRIFT1_L M + {SPR_PLAY, 13, 1, {NULL}, 0, 0, S_KART_DRIFT1_L}, // S_KART_DRIFT2_L N + {SPR_PLAY, 14, 1, {NULL}, 0, 0, S_KART_DRIFT2_R}, // S_KART_DRIFT1_R O + {SPR_PLAY, 15, 1, {NULL}, 0, 0, S_KART_DRIFT1_R}, // S_KART_DRIFT2_R P + {SPR_PLAY, 16, -1, {NULL}, 0, 0, S_KART_SPIN}, // S_KART_SPIN Q + {SPR_PLAY, 16, 350, {NULL}, 0, 0, S_KART_STND1}, // S_KART_PAIN Q + {SPR_PLAY, 17, 350, {NULL}, 0, 0, S_KART_STND1}, // S_KART_SQUISH R /* {SPR_PLAY, 0, 105, {NULL}, 0, 0, S_PLAY_TAP1}, // S_PLAY_STND {SPR_PLAY, 1, 16, {NULL}, 0, 0, S_PLAY_TAP2}, // S_PLAY_TAP1 @@ -177,14 +185,14 @@ state_t states[NUMSTATES] = // 1-Up Box Sprites (uses player sprite) // Kart: default to signpost just to ensure there are no missing sprite errors... - {SPR_PLAY, 24, 2, {NULL}, 0, 16, S_PLAY_BOX2}, // S_PLAY_BOX1 + {SPR_PLAY, 18, 2, {NULL}, 0, 16, S_PLAY_BOX2}, // S_PLAY_BOX1 {SPR_NULL, 0, 1, {NULL}, 0, 0, S_PLAY_BOX1}, // S_PLAY_BOX2 - {SPR_PLAY, 24, 4, {NULL}, 0, 4, S_PLAY_ICON2}, // S_PLAY_ICON1 + {SPR_PLAY, 18, 4, {NULL}, 0, 4, S_PLAY_ICON2}, // S_PLAY_ICON1 {SPR_NULL, 0, 12, {NULL}, 0, 0, S_PLAY_ICON3}, // S_PLAY_ICON2 - {SPR_PLAY, 24, 18, {NULL}, 0, 4, S_NULL}, // S_PLAY_ICON3 + {SPR_PLAY, 18, 18, {NULL}, 0, 4, S_NULL}, // S_PLAY_ICON3 // Level end sign (uses player sprite) - {SPR_PLAY, 24, 1, {NULL}, 0, 24, S_PLAY_SIGN}, // S_PLAY_SIGN + {SPR_PLAY, 18, 1, {NULL}, 0, 24, S_PLAY_SIGN}, // S_PLAY_SIGN S // Blue Crawla {SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND @@ -1534,6 +1542,10 @@ state_t states[NUMSTATES] = {SPR_XMS1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_XMASPOLE {SPR_XMS2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CANDYCANE {SPR_XMS3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOWMAN + {SPR_XMS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOWMANHAT + {SPR_XMS4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST1 + {SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST2 + {SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HANGSTAR // Loads of Botanic Serenity bullshit {SPR_BSZ1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BSZTALLFLOWER_RED @@ -2560,6 +2572,8 @@ state_t states[NUMSTATES] = {SPR_DRIF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DRIFTSPARK_C2}, // S_DRIFTSPARK_C1 {SPR_DRIF, FF_FULLBRIGHT|FF_TRANS20, 1, {NULL}, 0, 0, S_DRIFTSPARK_A3}, // S_DRIFTSPARK_C2 (Loop back to A3) + {SPR_BDRF, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 5, 2, S_BRAKEDRIFT}, // S_BRAKEDRIFT + {SPR_DUST, 0, 3, {NULL}, 0, 0, S_DRIFTDUST2}, // S_DRIFTDUST1 {SPR_DUST, 1, 3, {NULL}, 0, 0, S_DRIFTDUST3}, // S_DRIFTDUST2 {SPR_DUST, FF_TRANS20|2, 3, {NULL}, 0, 0, S_DRIFTDUST4}, // S_DRIFTDUST3 @@ -2623,31 +2637,36 @@ state_t states[NUMSTATES] = {SPR_WIPD, 3, 3, {NULL}, 0, 0, S_WIPEOUTTRAIL5}, // S_WIPEOUTTRAIL4 {SPR_WIPD, 4, 3, {NULL}, 0, 0, S_NULL}, // S_WIPEOUTTRAIL5 - {SPR_FITM, FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM2}, // S_FAKEITEM1 - {SPR_FITM, 1|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM3}, // S_FAKEITEM2 - {SPR_FITM, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM4}, // S_FAKEITEM3 - {SPR_FITM, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM5}, // S_FAKEITEM4 - {SPR_FITM, 4|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM6}, // S_FAKEITEM5 - {SPR_FITM, 5|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM7}, // S_FAKEITEM6 - {SPR_FITM, 6|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM8}, // S_FAKEITEM7 - {SPR_FITM, 7|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM9}, // S_FAKEITEM8 - {SPR_FITM, 8|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM10}, // S_FAKEITEM9 - {SPR_FITM, 9|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM11}, // S_FAKEITEM10 - {SPR_FITM, 10|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM12}, // S_FAKEITEM11 - {SPR_FITM, 11|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM13}, // S_FAKEITEM12 - {SPR_FITM, 12|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM14}, // S_FAKEITEM13 - {SPR_FITM, 13|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM15}, // S_FAKEITEM14 - {SPR_FITM, 14|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM16}, // S_FAKEITEM15 - {SPR_FITM, 15|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM17}, // S_FAKEITEM16 - {SPR_FITM, 16|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM18}, // S_FAKEITEM17 - {SPR_FITM, 17|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM19}, // S_FAKEITEM18 - {SPR_FITM, 18|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM20}, // S_FAKEITEM19 - {SPR_FITM, 19|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM21}, // S_FAKEITEM20 - {SPR_FITM, 20|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM22}, // S_FAKEITEM21 - {SPR_FITM, 21|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM23}, // S_FAKEITEM22 // ***** - {SPR_FITM, 22|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM24}, // S_FAKEITEM23 // ***** - {SPR_FITM, 23|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_FAKEITEM1}, // S_FAKEITEM24 // ***** - {SPR_FITM, FF_FULLBRIGHT, 175, {NULL}, 0, 0, S_FAKEITEM1}, // S_DEADFAKEITEM + {SPR_RSHE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ROCKETSNEAKER_L + {SPR_RSHE, 1, -1, {NULL}, 0, 0, S_NULL}, // S_ROCKETSNEAKER_R + {SPR_RSHE, 2, -1, {NULL}, 0, 0, S_NULL}, // S_ROCKETSNEAKER_LVIBRATE + {SPR_RSHE, 3, -1, {NULL}, 0, 0, S_NULL}, // S_ROCKETSNEAKER_RVIBRATE + + {SPR_FITM, FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM2}, // S_EGGMANITEM1 + {SPR_FITM, 1|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM3}, // S_EGGMANITEM2 + {SPR_FITM, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM4}, // S_EGGMANITEM3 + {SPR_FITM, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM5}, // S_EGGMANITEM4 + {SPR_FITM, 4|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM6}, // S_EGGMANITEM5 + {SPR_FITM, 5|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM7}, // S_EGGMANITEM6 + {SPR_FITM, 6|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM8}, // S_EGGMANITEM7 + {SPR_FITM, 7|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM9}, // S_EGGMANITEM8 + {SPR_FITM, 8|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM10}, // S_EGGMANITEM9 + {SPR_FITM, 9|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM11}, // S_EGGMANITEM10 + {SPR_FITM, 10|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM12}, // S_EGGMANITEM11 + {SPR_FITM, 11|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM13}, // S_EGGMANITEM12 + {SPR_FITM, 12|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM14}, // S_EGGMANITEM13 + {SPR_FITM, 13|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM15}, // S_EGGMANITEM14 + {SPR_FITM, 14|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM16}, // S_EGGMANITEM15 + {SPR_FITM, 15|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM17}, // S_EGGMANITEM16 + {SPR_FITM, 16|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM18}, // S_EGGMANITEM17 + {SPR_FITM, 17|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM19}, // S_EGGMANITEM18 + {SPR_FITM, 18|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM20}, // S_EGGMANITEM19 + {SPR_FITM, 19|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM21}, // S_EGGMANITEM20 + {SPR_FITM, 20|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM22}, // S_EGGMANITEM21 + {SPR_FITM, 21|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM23}, // S_EGGMANITEM22 // ***** + {SPR_FITM, 22|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM24}, // S_EGGMANITEM23 // ***** + {SPR_FITM, 23|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EGGMANITEM1}, // S_EGGMANITEM24 // ***** + {SPR_FITM, FF_FULLBRIGHT, 175, {NULL}, 0, 0, S_EGGMANITEM1}, // S_EGGMANITEM_DEAD {SPR_BANA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BANANA {SPR_BANA, 0, 175, {NULL}, 0, 0, S_NULL}, // S_BANANA_DEAD @@ -2772,16 +2791,27 @@ state_t states[NUMSTATES] = {SPR_BHBM, FF_FULLBRIGHT|14, 1, {NULL}, 0, 0, S_BALLHOGBOOM16}, // S_BALLHOGBOOM15 {SPR_BHBM, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_NULL}, // S_BALLHOGBOOM16 - {SPR_BLIG, 0, 2, {NULL}, 0, 0, S_BLUELIGHTNING2}, // S_BLUELIGHTNING1 - {SPR_BLIG, 1, 2, {NULL}, 0, 0, S_BLUELIGHTNING3}, // S_BLUELIGHTNING2 - {SPR_BLIG, 2, 2, {NULL}, 0, 0, S_BLUELIGHTNING4}, // S_BLUELIGHTNING3 - {SPR_BLIG, 3, 2, {NULL}, 0, 0, S_NULL}, // S_BLUELIGHTNING4 - {SPR_SSMN, 0, 1, {A_MineExplode}, MT_BLUEEXPLOSION, 0, S_NULL}, // S_BLUEEXPLODE - - {SPR_LIGH, 0, 2, {NULL}, 0, 0, S_LIGHTNING2}, // S_LIGHTNING1 - {SPR_LIGH, 1, 2, {NULL}, 0, 0, S_LIGHTNING3}, // S_LIGHTNING2 - {SPR_LIGH, 2, 2, {NULL}, 0, 0, S_LIGHTNING4}, // S_LIGHTNING3 - {SPR_LIGH, 3, 2, {NULL}, 0, 0, S_NULL}, // S_LIGHTNING4 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB2}, // S_SPB1 + {SPR_SPBM, 1, 1, {A_SPBChase}, 0, 0, S_SPB3}, // S_SPB2 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB4}, // S_SPB3 + {SPR_SPBM, 2, 1, {A_SPBChase}, 0, 0, S_SPB5}, // S_SPB4 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB6}, // S_SPB5 + {SPR_SPBM, 3, 1, {A_SPBChase}, 0, 0, S_SPB7}, // S_SPB6 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB8}, // S_SPB7 + {SPR_SPBM, 4, 1, {A_SPBChase}, 0, 0, S_SPB9}, // S_SPB8 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB10}, // S_SPB9 + {SPR_SPBM, 5, 1, {A_SPBChase}, 0, 0, S_SPB11}, // S_SPB10 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB12}, // S_SPB11 + {SPR_SPBM, 6, 1, {A_SPBChase}, 0, 0, S_SPB13}, // S_SPB12 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB14}, // S_SPB13 + {SPR_SPBM, 7, 1, {A_SPBChase}, 0, 0, S_SPB15}, // S_SPB14 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB16}, // S_SPB15 + {SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB17}, // S_SPB16 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB18}, // S_SPB17 + {SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB19}, // S_SPB18 + {SPR_SPBM, 0, 1, {A_SPBChase}, 0, 0, S_SPB20}, // S_SPB19 + {SPR_SPBM, 8, 1, {A_SPBChase}, 0, 0, S_SPB1}, // S_SPB20 + {SPR_SPBM, 8, 175, {NULL}, 0, 0, S_NULL}, // S_SPB_DEAD {SPR_THNS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_THUNDERSHIELD2}, // S_THUNDERSHIELD1 {SPR_THNS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_THUNDERSHIELD3}, // S_THUNDERSHIELD2 @@ -3004,12 +3034,61 @@ state_t states[NUMSTATES] = {SPR_WANT, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_PLAYERARROW_WANTED7}, // S_PLAYERARROW_WANTED6 {SPR_WANT, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_PLAYERARROW_WANTED1}, // S_PLAYERARROW_WANTED7 - {SPR_PBOM, FF_ANIMATE, -1, {NULL}, 3, 3, S_NULL}, // S_PLAYERBOMB + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB2}, // S_PLAYERBOMB1 + {SPR_SPBM, 1, 1, {NULL}, 0, 0, S_PLAYERBOMB3}, // S_PLAYERBOMB2 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB4}, // S_PLAYERBOMB3 + {SPR_SPBM, 2, 1, {NULL}, 0, 0, S_PLAYERBOMB5}, // S_PLAYERBOMB4 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB6}, // S_PLAYERBOMB5 + {SPR_SPBM, 3, 1, {NULL}, 0, 0, S_PLAYERBOMB7}, // S_PLAYERBOMB6 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB8}, // S_PLAYERBOMB7 + {SPR_SPBM, 4, 1, {NULL}, 0, 0, S_PLAYERBOMB9}, // S_PLAYERBOMB8 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB10}, // S_PLAYERBOMB9 + {SPR_SPBM, 5, 1, {NULL}, 0, 0, S_PLAYERBOMB11}, // S_PLAYERBOMB10 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB12}, // S_PLAYERBOMB11 + {SPR_SPBM, 6, 1, {NULL}, 0, 0, S_PLAYERBOMB13}, // S_PLAYERBOMB12 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB14}, // S_PLAYERBOMB13 + {SPR_SPBM, 7, 1, {NULL}, 0, 0, S_PLAYERBOMB15}, // S_PLAYERBOMB14 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB16}, // S_PLAYERBOMB15 + {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_PLAYERBOMB17}, // S_PLAYERBOMB16 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB18}, // S_PLAYERBOMB17 + {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_PLAYERBOMB19}, // S_PLAYERBOMB18 + {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB20}, // S_PLAYERBOMB19 + {SPR_SPBM, 8, 1, {NULL}, 0, 0, S_PLAYERBOMB1}, // S_PLAYERBOMB20 {SPR_RNDM, FF_ANIMATE, -1, {NULL}, 23, 3, S_NULL}, // S_PLAYERITEM {SPR_FITM, FF_ANIMATE, -1, {NULL}, 23, 3, S_NULL}, // S_PLAYERFAKE - {SPR_PBOM, 4, -1, {NULL}, 0, 0, S_NULL}, // S_KARMAWHEEL - + {SPR_PBOM, 0, -1, {NULL}, 0, 0, S_NULL}, // S_KARMAWHEEL + + {SPR_HIT1, FF_FULLBRIGHT, 7, {NULL}, 0, 0, S_BATTLEPOINT1B}, // S_BATTLEPOINT1A + {SPR_HIT1, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEPOINT1C}, // S_BATTLEPOINT1B + {SPR_HIT1, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BATTLEPOINT1D}, // S_BATTLEPOINT1C + {SPR_HIT1, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEPOINT1E}, // S_BATTLEPOINT1D + {SPR_HIT1, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEPOINT1F}, // S_BATTLEPOINT1E + {SPR_HIT1, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BATTLEPOINT1G}, // S_BATTLEPOINT1F + {SPR_HIT1, FF_FULLBRIGHT|2, TICRATE, {NULL}, 0, 0, S_BATTLEPOINT1H}, // S_BATTLEPOINT1G + {SPR_HIT1, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_BATTLEPOINT1I}, // S_BATTLEPOINT1H + {SPR_HIT1, FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_NULL}, // S_BATTLEPOINT1I + + {SPR_HIT2, FF_FULLBRIGHT, 7, {NULL}, 0, 0, S_BATTLEPOINT2B}, // S_BATTLEPOINT2A + {SPR_HIT2, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEPOINT2C}, // S_BATTLEPOINT2B + {SPR_HIT2, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BATTLEPOINT2D}, // S_BATTLEPOINT2C + {SPR_HIT2, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEPOINT2E}, // S_BATTLEPOINT2D + {SPR_HIT2, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEPOINT2F}, // S_BATTLEPOINT2E + {SPR_HIT2, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BATTLEPOINT2G}, // S_BATTLEPOINT2F + {SPR_HIT2, FF_FULLBRIGHT|2, TICRATE, {NULL}, 0, 0, S_BATTLEPOINT2H}, // S_BATTLEPOINT2G + {SPR_HIT2, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_BATTLEPOINT2I}, // S_BATTLEPOINT2H + {SPR_HIT2, FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_NULL}, // S_BATTLEPOINT2I + + {SPR_HIT3, FF_FULLBRIGHT, 7, {NULL}, 0, 0, S_BATTLEPOINT3B}, // S_BATTLEPOINT3A + {SPR_HIT3, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEPOINT3C}, // S_BATTLEPOINT3B + {SPR_HIT3, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BATTLEPOINT3D}, // S_BATTLEPOINT3C + {SPR_HIT3, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEPOINT3E}, // S_BATTLEPOINT3D + {SPR_HIT3, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEPOINT3F}, // S_BATTLEPOINT3E + {SPR_HIT3, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BATTLEPOINT3G}, // S_BATTLEPOINT3F + {SPR_HIT3, FF_FULLBRIGHT|2, TICRATE, {NULL}, 0, 0, S_BATTLEPOINT3H}, // S_BATTLEPOINT3G + {SPR_HIT3, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_BATTLEPOINT3I}, // S_BATTLEPOINT3H + {SPR_HIT3, FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_NULL}, // S_BATTLEPOINT3I + // Oh no it's annoying lightning states....... // Lightning Sparks (it's the ones we'll use for the radius) {SPR_KSPK, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK2}, // S_KSPARK1 @@ -3025,7 +3104,7 @@ state_t states[NUMSTATES] = {SPR_KSPK, FF_TRANS50|FF_FULLBRIGHT|5, 2, {A_LightningFollowPlayer}, 0, 0, S_KSPARK12}, // S_KSPARK11 {SPR_NULL, FF_FULLBRIGHT, 1, {A_LightningFollowPlayer}, 0, 0, S_KSPARK13}, // S_KSPARK12 {SPR_KSPK, FF_TRANS60|FF_FULLBRIGHT|6, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_KSPARK13 - + // The straight bolt... {SPR_LZI1, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO12}, // S_LZIO11 {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO13}, // S_LZIO12 @@ -3033,33 +3112,305 @@ state_t states[NUMSTATES] = {SPR_LZI1, FF_FULLBRIGHT|1, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO15}, // S_LZIO14 {SPR_NULL, FF_FULLBRIGHT, 4, {A_LightningFollowPlayer}, 0, 0, S_LZIO16}, // S_LZIO15 {SPR_LZI1, FF_FULLBRIGHT|1, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO17}, // S_LZIO16 - {SPR_NULL, 0, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO18}, // S_LZIO17 + {SPR_NULL, 0, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO18}, // S_LZIO17 {SPR_LZI1, FF_TRANS50|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO19}, // S_LZIO18 - {SPR_LZI1, FF_TRANS70|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_LZIO19 - + {SPR_LZI1, FF_TRANS70|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_LZIO19 + {SPR_NULL, FF_FULLBRIGHT, 6, {A_LightningFollowPlayer}, 0, 0, S_LZIO22}, // S_LZIO21 {SPR_LZI2, FF_FULLBRIGHT|1, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO23}, // S_LZIO22 {SPR_LZI2, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO24}, // S_LZIO23 {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO25}, // S_LZIO24 {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO26}, // S_LZIO25 {SPR_NULL, FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO27}, // S_LZIO26 - {SPR_LZI2, FF_TRANS30|FF_FULLBRIGHT|2, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO28}, // S_LZIO27 - {SPR_NULL, 0, 4, {A_LightningFollowPlayer}, 0, 0, S_LZIO29}, // S_LZIO28 - {SPR_LZI2, FF_TRANS70|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_LZIO29 - + {SPR_LZI2, FF_TRANS30|FF_FULLBRIGHT|2, 2, {A_LightningFollowPlayer}, 0, 0, S_LZIO28}, // S_LZIO27 + {SPR_NULL, 0, 4, {A_LightningFollowPlayer}, 0, 0, S_LZIO29}, // S_LZIO28 + {SPR_LZI2, FF_TRANS70|FF_FULLBRIGHT, 2, {A_LightningFollowPlayer}, 0, 0, S_NULL}, // S_LZIO29 + // The slanted bolt. Man these states are boring as all heck to do. - {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT2}, // S_KLIT1 - {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT3}, // S_KLIT2 + {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT2}, // S_KLIT1 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT3}, // S_KLIT2 {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|1, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT4}, // S_KLIT3 - {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT5}, // S_KLIT4 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT5}, // S_KLIT4 {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|2, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT6}, // S_KLIT5 - {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT7}, // S_KLIT6 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT7}, // S_KLIT6 {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|3, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT8}, // S_KLIT7 - {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT9}, // S_KLIT8 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT9}, // S_KLIT8 {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|4, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT10}, // S_KLIT9 - {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT11}, // S_KLIT10 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT11}, // S_KLIT10 {SPR_KLIT, FF_FULLBRIGHT|FF_PAPERSPRITE|5, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT12}, // S_KLIT11 - {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT1}, // S_KLIT12 + {SPR_NULL, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightningFollowPlayer}, 0, 0, S_KLIT1}, // S_KLIT12 + + {SPR_FZSM, 0, 4, {NULL}, 0, 0, S_FZEROSMOKE2}, // S_FZEROSMOKE1 + {SPR_FZSM, 1, 4, {NULL}, 0, 0, S_FZEROSMOKE3}, // S_FZEROSMOKE2 + {SPR_FZSM, 2, 4, {NULL}, 0, 0, S_FZEROSMOKE4}, // S_FZEROSMOKE3 + {SPR_FZSM, 3, 4, {NULL}, 0, 0, S_FZEROSMOKE5}, // S_FZEROSMOKE4 + {SPR_FZSM, 4, 4, {NULL}, 0, 0, S_NULL}, // S_FZEROSMOKE5 + + {SPR_FZBM, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_FZEROBOOM2}, // S_FZEROBOOM1 + {SPR_FZBM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_FZEROBOOM3}, // S_FZEROBOOM2 + {SPR_FZBM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_FZEROBOOM4}, // S_FZEROBOOM3 + {SPR_FZBM, FF_FULLBRIGHT|3, 2, {A_FZBoomFlash}, 0, 0, S_FZEROBOOM5}, // S_FZEROBOOM4 + {SPR_FZBM, FF_FULLBRIGHT|2, 1, {A_FZBoomSmoke}, 0, 0, S_FZEROBOOM6}, // S_FZEROBOOM5 + {SPR_FZBM, FF_FULLBRIGHT|1, 1, {A_FZBoomSmoke}, 0, 0, S_FZEROBOOM7}, // S_FZEROBOOM6 + {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 1, 0, S_FZEROBOOM8}, // S_FZEROBOOM7 + {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 2, 0, S_FZEROBOOM9}, // S_FZEROBOOM8 + {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 3, 0, S_FZEROBOOM10}, // S_FZEROBOOM9 + {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 2, 0, S_FZEROBOOM11}, // S_FZEROBOOM10 + {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 1, 0, S_FZEROBOOM12}, // S_FZEROBOOM11 + {SPR_NULL, 0, 1, {A_FZBoomSmoke}, 0, 0, S_NULL}, // S_FZEROBOOM12 + + {SPR_SMOK, FF_TRANS30, 30, {NULL}, 0, 0, S_FZSLOWSMOKE2}, // S_FZSLOWSMOKE1 + {SPR_SMOK, FF_TRANS30|1, 30, {NULL}, 0, 0, S_FZSLOWSMOKE3}, // S_FZSLOWSMOKE2 + {SPR_SMOK, FF_TRANS30|2, 30, {NULL}, 0, 0, S_FZSLOWSMOKE4}, // S_FZSLOWSMOKE3 + {SPR_SMOK, FF_TRANS30|3, 30, {NULL}, 0, 0, S_FZSLOWSMOKE5}, // S_FZSLOWSMOKE4 + {SPR_SMOK, FF_TRANS30|4, 30, {NULL}, 0, 0, S_NULL}, // S_FZSLOWSMOKE5 + + // Various plants + {SPR_SBUS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SONICBUSH + {SPR_SHRB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRUB + {SPR_BUS2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_TALLBUSH + {SPR_TWEE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_AZURECITYTREE + + // Marble Zone + {SPR_MARB, FF_FULLBRIGHT|FF_ANIMATE|5, TICRATE, {NULL}, 3, 3, S_NULL}, // S_FLAMEPARTICLE + {SPR_MARB, FF_FULLBRIGHT|FF_ANIMATE, 8*3, {A_FlameParticle}, 3, 3, S_MARBLETORCH}, // S_MARBLETORCH + {SPR_MARB, FF_FULLBRIGHT|FF_TRANS80|4, -1, {NULL}, 1, 29, S_NULL}, // S_MARBLELIGHT + {SPR_MARB, 9, -1, {NULL}, 0, 0, S_NULL}, // S_MARBLEBURNER + + // CD Special Stage + {SPR_FUFO, 0, 1, {A_Thrust}, 5, 2, S_CDUFO}, // S_CDUFO + {SPR_FUFO, 0, 4, {A_BossScream}, 0, MT_EXPLODE, S_CDUFO_DIE}, // S_CDUFO_DIE + + // Rusty Rig + {SPR_RUST, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_RUSTYLAMP_ORANGE + {SPR_RUST, 1, -1, {NULL}, 0, 0, S_NULL}, // S_RUSTYCHAIN + + // D2 Balloon Panic + {SPR_BLON, FF_ANIMATE, -1, {NULL}, 2, 5, S_BALLOON}, // S_BALLOON + {SPR_BLON, FF_ANIMATE|3, 2, {NULL}, 1, 1, S_BALLOONPOP2}, // S_BALLOONPOP1 + {SPR_NULL, 0, 15*TICRATE, {NULL}, 0, 0, S_BALLOONPOP3}, // S_BALLOONPOP2 + {SPR_NULL, 0, 0, {A_SpawnFreshCopy}, 0, 0, S_NULL}, // S_BALLOONPOP3 + + // Smokin' & Vapin' (Don't try this at home, kids!) + {SPR_SMOK, 0, 1, {A_SetScale}, FRACUNIT/2, 0, S_PETSMOKE1}, // S_PETSMOKE0 + {SPR_SMOK, 0, 5, {A_SetScale}, FRACUNIT*2, 1, S_PETSMOKE2}, // S_PETSMOKE1 + {SPR_SMOK, 1, 5, {A_BubbleRise}, 0, 50096, S_PETSMOKE3}, // S_PETSMOKE2 + {SPR_SMOK, 2, 15, {A_BubbleRise}, 0, 50096, S_PETSMOKE4}, // S_PETSMOKE3 + {SPR_SMOK, 3, 25, {A_BubbleRise}, 0, 50096, S_PETSMOKE5}, // S_PETSMOKE4 + {SPR_SMOK, 4, 35, {A_BubbleRise}, 0, 50096, S_NULL}, // S_PETSMOKE5 + {SPR_VAPE, 0, 1, {NULL}, 0, 0, S_VVVAPING1}, // S_VVVAPING0 + {SPR_VAPE, 0, 5, {A_SetScale}, FRACUNIT*2, 1, S_VVVAPING2}, // S_VVVAPING1 + {SPR_VAPE, 1, 5, {A_BubbleRise}, 0, 50096, S_VVVAPING3}, // S_VVVAPING2 + {SPR_VAPE, 2, 15, {A_BubbleRise}, 0, 50096, S_VVVAPING4}, // S_VVVAPING3 + {SPR_VAPE, 3, 25, {A_BubbleRise}, 0, 50096, S_VVVAPING5}, // S_VVVAPING4 + {SPR_VAPE, 4, 35, {A_BubbleRise}, 0, 50096, S_NULL}, // S_VVVAPING5 + {SPR_VAPE, FF_ANIMATE|FF_TRANS30, -1, {NULL}, 6, 6, S_NULL}, // S_VVVAPE + + // Hill Top Zone + {SPR_HTZA, 0, -1, {A_SetScale}, 2*FRACUNIT, 0, S_NULL}, // S_HTZTREE + {SPR_HTZB, 0, -1, {A_SetScale}, 2*FRACUNIT, 0, S_NULL}, // S_HTZBUSH + + // Ports of gardens + {SPR_SGVA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SGVINE1 + {SPR_SGVB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SGVINE2 + {SPR_SGVC, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SGVINE3 + {SPR_PGTR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PGTREE + {SPR_PGF1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PGFLOWER1 + {SPR_PGF2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PGFLOWER2 + {SPR_PGF3, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PGFLOWER3 + {SPR_PGBH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PGBUSH + {SPR_DPLR, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DHPILLAR + + // Midnight Channel stuff, yay more boring states! + {SPR_SPTL, 0, -1, {NULL}, 0, 0, S_SPOTLIGHT}, // S_SPOTLIGHT + {SPR_ENM1, 0, 1, {A_RandomShadowFrame}, 0, 0, S_RANDOMSHADOW}, // S_RANDOMSHADOW + + {SPR_GARU, 0, 2, {NULL}, 0, 0, S_GARU2}, // S_GARU1 + {SPR_GARU, 1, 2, {NULL}, 0, 0, S_GARU3}, // S_GARU2 + {SPR_GARU, 2, 2, {NULL}, 0, 0, S_NULL}, // S_GARU3 + + {SPR_NULL, 0, 2, {NULL}, 0, 0, S_TGARU1}, // S_TGARU0 + {SPR_GARU, FF_TRANS30, 2, {NULL}, 0, 0, S_GARU2}, // S_TGARU1 + {SPR_GARU, 1|FF_TRANS30, 2, {NULL}, 0, 0, S_GARU3}, // S_TGARU2 + {SPR_GARU, 2|FF_TRANS30, 2, {NULL}, 0, 0, S_NULL}, // S_TGARU3 + + {SPR_ENM1, 2, 1, {A_RoamingShadowThinker}, 0, 0, S_ROAMINGSHADOW}, //S_ROAMINGSHADOW + + {SPR_MARR, 0, 1, {A_MayonakaArrow}, 0, 0, S_MAYONAKAARROW}, //S_MAYONAKAARROW + + // Mementos stuff + {SPR_NULL, 0, TICRATE*20, {NULL}, 0, 0, S_REAPER}, //S_REAPER_INVIS TODO: DON'T FORGET TO CHANGE THAT BACK TO 130*TICRATE WHEN TESTING IS OVER + {SPR_REAP, 0, 1, {A_ReaperThinker}, 0, 0, S_REAPER}, //S_REAPER + {SPR_NULL, 0, 1, {A_MementosTPParticles}, 0, 0, S_MEMENTOSTP}, //S_MEMENTOSTP + + // Jack In The Box + {SPR_JITB, 0, 4, {NULL}, 0, 0, S_JITB2}, // S_JITB1 + {SPR_JITB, 1, 4, {NULL}, 0, 0, S_JITB3}, // S_JITB2 + {SPR_JITB, 2, 4, {NULL}, 0, 0, S_JITB4}, // S_JITB3 + {SPR_JITB, 3, 4, {NULL}, 0, 0, S_JITB5}, // S_JITB4 + {SPR_JITB, 2, 4, {NULL}, 0, 0, S_JITB6}, // S_JITB5 + {SPR_JITB, 1, 4, {NULL}, 0, 0, S_JITB1}, // S_JITB6 + + // Color Drive Stuff: + {SPR_CDMO, 0, -1, {NULL}, 0, 0, S_CDMOONSP}, // S_CDMOONSP + {SPR_CDBU, 0, -1, {NULL}, 0, 0, S_CDBUSHSP}, // S_CDBUSHSP + {SPR_CDBU, 1, -1, {NULL}, 0, 0, S_CDTREEASP}, // S_CDTREEASP + {SPR_CDBU, 2, -1, {NULL}, 0, 0, S_CDTREEBSP}, // S_CDTREEBSP + + // Daytona Speedway + {SPR_PINE, 1, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE + {SPR_PINE, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_PINETREE_SIDE + + // Egg Zeppelin + {SPR_PPLR, 0, -1, {NULL}, 0, 0, S_EZZPROPELLER}, // S_EZZPROPELLER + {SPR_PPLR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_EZZPROPELLER_BLADE}, // S_EZZPROPELLER_BLADE + + // Desert Palace + {SPR_DPPT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DP_PALMTREE + + // Aurora Atoll + {SPR_AATR, 0, -1, {NULL}, 0, 0, S_AAZTREE_SEG}, // S_AAZTREE_SEG + {SPR_COCO, 0, -1, {NULL}, 0, 0, S_AAZTREE_COCONUT}, // S_AAZTREE_COCONUT + {SPR_AATR, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_AAZTREE_LEAF}, // S_AAZTREE_LEAF + + // Barren Badlands + {SPR_BDST, FF_TRANS80, 35, {NULL}, 0, 0, S_BBZDUST2}, // S_BBZDUST1 + {SPR_BDST, FF_TRANS80|1, 12, {NULL}, 0, 0, S_BBZDUST3}, // S_BBZDUST2 + {SPR_BDST, FF_TRANS80|2, 11, {NULL}, 0, 0, S_BBZDUST4}, // S_BBZDUST3 + {SPR_BDST, FF_TRANS80|3, 10, {NULL}, 0, 0, S_NULL}, // S_BBZDUST4 + + {SPR_FROG, 0, -1, {NULL}, 0, 0, S_FROGGER}, // S_FROGGER + {SPR_FROG, 1, -1, {NULL}, 0, 0, S_FROGGER_ATTACK}, // S_FROGGER_ATTACK + {SPR_FROG, 2, -1, {NULL}, 0, 0, S_FROGGER_JUMP}, // S_FROGGER_JUMP + + {SPR_FROG, 3, 7*TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_FROGTONGUE + {SPR_FROG, 4, 7*TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_FROGTONGUE_JOINT + + {SPR_HOLE, 0, 1, {NULL}, 0, 0, S_ROBRA}, // S_ROBRA + {SPR_CBRA, 0, 1, {NULL}, 0, 0, S_ROBRA_HEAD}, // S_ROBRA_HEAD + {SPR_CBRA, 1, -1, {NULL}, 0, 0, S_ROBRA_JOINT}, // S_ROBRA_JOINT + {SPR_CBRA, 2, -1, {NULL}, 1, 0, S_ROBRASHELL_INSIDE}, // S_ROBRASHELL_INSIDE + {SPR_CBRA, 3, -1, {NULL}, 0, 0, S_ROBRASHELL_OUTSIDE}, // S_ROBRASHELL_OUTSIDE + + {SPR_HOLE, 0, 1, {NULL}, 0, 0, S_BLUEROBRA}, // S_BLUEROBRA + {SPR_BBRA, 0, 1, {NULL}, 0, 0, S_BLUEROBRA_HEAD}, // S_BLUEROBRA_HEAD + {SPR_BBRA, 1, -1, {NULL}, 0, 0, S_BLUEROBRA_JOINT}, // S_BLUEROBRA_JOINT + + // Eerie Grove + {SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG2}, // S_EERIEFOG1 + {SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|1, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG3}, // S_EERIEFOG2 + {SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|2, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG4}, // S_EERIEFOG3 + {SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|3, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG5}, // S_EERIEFOG4 + {SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|4, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG1}, // S_EERIEFOG5 + + // SMK ports + {SPR_SMKP, 0, -1, {NULL}, 0, 0, S_SMK_PIPE1}, // S_SMK_PIPE1 + {SPR_SMKP, 1, -1, {NULL}, 0, 0, S_SMK_PIPE2}, // S_SMK_PIPE2 + {SPR_MTYM, 0, -1, {NULL}, 0, 0, S_SMK_MOLE}, // S_SMK_MOLE + {SPR_THWP, 0, -1, {NULL}, 0, 0, S_SMK_THWOMP}, // S_SMK_THWOMP + {SPR_SNOB, 0, -1, {NULL}, 0, 0, S_SMK_SNOWBALL}, // S_SMK_SNOWBALL + {SPR_ICEB, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SMK_ICEBLOCK + {SPR_ICEB, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_SMK_ICEBLOCK2 + {SPR_ICEB, 2, 10, {NULL}, 0, 0, S_SMK_ICEBLOCK_DEBRIS2}, // S_SMK_ICEBLOCK_DEBRIS + {SPR_ICEB, 3, 10, {NULL}, 0, 0, S_NULL}, // S_SMK_ICEBLOCK_DEBRIS2 + + // Ezo's maps + {SPR_CNDL, FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_BLUEFIRE2}, // S_BLUEFIRE1 + {SPR_CNDL, 1|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_BLUEFIRE3}, // S_BLUEFIRE2 + {SPR_CNDL, 2|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_BLUEFIRE4}, // S_BLUEFIRE3 + {SPR_CNDL, 3|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_BLUEFIRE1}, // S_BLUEFIRE4 + + {SPR_CNDL, 4|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_GREENFIRE2}, // S_GREENFIRE1 + {SPR_CNDL, 5|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_GREENFIRE3}, // S_GREENFIRE2 + {SPR_CNDL, 6|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_GREENFIRE4}, // S_GREENFIRE3 + {SPR_CNDL, 7|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_GREENFIRE1}, // S_GREENFIRE4 + + {SPR_CHES, 0, -1, {NULL}, 0, 0, S_NULL}, // S_REGALCHEST + {SPR_CHIM, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_CHIMERASTATUE + {SPR_DRGN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_DRAGONSTATUE + {SPR_LZMN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LIZARDMANSTATUE + {SPR_PGSS, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_PEGASUSSTATUE + + {SPR_ZTCH, FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_ZELDAFIRE2}, // S_ZELDAFIRE1 + {SPR_ZTCH, 1|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_ZELDAFIRE3}, // S_ZELDAFIRE2 + {SPR_ZTCH, 2|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_ZELDAFIRE4}, // S_ZELDAFIRE3 + {SPR_ZTCH, 3|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_ZELDAFIRE1}, // S_ZELDAFIRE4 + + {SPR_DOCH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GANBARETHING + {SPR_DUCK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GANBAREDUCK + {SPR_GTRE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_GANBARETREE + + {SPR_MKMA, 1, 2, {A_Look}, (256<<16)|1, 0, S_MONOIDLE}, // S_MONOIDLE + {SPR_MKMA, 0, 3, {A_Chase}, 3, 0, S_MONOCHASE2}, // S_MONOCHASE1 + {SPR_MKMA, 1, 3, {A_Chase}, 3, 0, S_MONOCHASE3}, // S_MONOCHASE2 + {SPR_MKMA, 2, 3, {A_Chase}, 3, 0, S_MONOCHASE4}, // S_MONOCHASE3 + {SPR_MKMA, 3, 3, {A_Chase}, 3, 0, S_MONOCHASE1}, // S_MONOCHASE4 + {SPR_MKMP, 0, 24, {A_Pain}, 3, 0, S_MONOIDLE}, // S_MONOPAIN + + {SPR_RTCH, FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_REDZELDAFIRE2}, // S_REDZELDAFIRE1 + {SPR_RTCH, 1|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_REDZELDAFIRE3}, // S_REDZELDAFIRE2 + {SPR_RTCH, 2|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_REDZELDAFIRE4}, // S_REDZELDAFIRE3 + {SPR_RTCH, 3|FF_FULLBRIGHT|FF_TRANS50, 3, {NULL}, 0, 0, S_REDZELDAFIRE1}, // S_REDZELDAFIRE4 + + {SPR_BOWL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BOWLINGPIN + {SPR_BOWH, 0, 4, {A_BunnyHop}, 5, 20, S_BOWLINGHIT2}, // S_BOWLINGHIT1 + {SPR_BOWH, 1, 2, {NULL}, 0, 0, S_BOWLINGHIT3}, // S_BOWLINGHIT2 + {SPR_BOWH, 2, 2, {NULL}, 0, 0, S_BOWLINGHIT4}, // S_BOWLINGHIT3 + {SPR_BOWH, 3, 2, {NULL}, 0, 0, S_NULL}, // S_BOWLINGHIT4 + + {SPR_TOAD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ARIDTOAD + {SPR_TOAH, 0, 4, {A_BunnyHop}, 10, 60, S_TOADHIT2}, // S_TOADHIT1 + {SPR_TOAH, 1, 3, {NULL}, 0, 0, S_TOADHIT3}, // S_TOADHIT2 + {SPR_TOAH, 2, 3, {NULL}, 0, 0, S_TOADHIT4}, // S_TOADHIT3 + {SPR_TOAH, 3, 3, {NULL}, 0, 0, S_EBARREL18}, // S_TOADHIT4 + + {SPR_BRRL, 0, 1, {A_Look}, (96<<16)|1, 0, S_EBARRELIDLE}, // S_EBARRELIDLE + {SPR_BRRR, 0, 4, {NULL}, 0, 0, S_EBARREL2}, // S_EBARREL1 + {SPR_BRRR, 1, 4, {NULL}, 0, 0, S_EBARREL3}, // S_EBARREL2 + {SPR_BRRR, 2, 4, {NULL}, 0, 0, S_EBARREL4}, // S_EBARREL3 + {SPR_BRRR, 3, 4, {NULL}, 0, 0, S_EBARREL5}, // S_EBARREL4 + {SPR_BRRR, 4, 4, {NULL}, 0, 0, S_EBARREL6}, // S_EBARREL5 + {SPR_BRRR, 5, 4, {NULL}, 0, 0, S_EBARREL7}, // S_EBARREL6 + {SPR_BRRR, 6, 4, {NULL}, 0, 0, S_EBARREL8}, // S_EBARREL7 + {SPR_BRRR, 7, 4, {NULL}, 0, 0, S_EBARREL9}, // S_EBARREL8 + {SPR_BRRR, 8, 4, {NULL}, 0, 0, S_EBARREL10}, // S_EBARREL9 + {SPR_BRRR, 9, 4, {NULL}, 0, 0, S_EBARREL11}, // S_EBARREL10 + {SPR_BRRR, 10, 4, {NULL}, 0, 0, S_EBARREL12}, // S_EBARREL11 + {SPR_BRRR, 11, 4, {NULL}, 0, 0, S_EBARREL13}, // S_EBARREL12 + {SPR_BRRR, 12, 4, {NULL}, 0, 0, S_EBARREL14}, // S_EBARREL13 + {SPR_BRRR, 13, 4, {NULL}, 0, 0, S_EBARREL15}, // S_EBARREL14 + {SPR_BRRR, 14, 4, {NULL}, 0, 0, S_EBARREL16}, // S_EBARREL15 + {SPR_BRRR, 15, 4, {NULL}, 0, 0, S_EBARREL17}, // S_EBARREL16 + {SPR_BRRR, 16, 4, {NULL}, 0, 0, S_EBARREL18}, // S_EBARREL17 + {SPR_BRRR, 16, 0, {A_MineExplode}, MT_MINEEXPLOSION, 0, S_NULL}, // S_EBARREL18 + + {SPR_HRSE, 0, 230, {A_PlaySeeSound}, 0, 0, S_MERRYHORSE}, // S_MERRYHORSE + + {SPR_BFRT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLUEFRUIT + {SPR_OFRT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ORANGEFRUIT + {SPR_RFRT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_REDFRUIT + {SPR_PFRT, 0, -1, {NULL}, 0, 0, S_NULL}, // S_PINKFRUIT + + {SPR_ASPK, 0, 50, {A_PlayAttackSound}, 0, 0, S_ADVENTURESPIKEA2}, // S_ADVENTURESPIKEA1 + {SPR_ASPK, 0, 50, {A_BunnyHop}, 20, 0, S_ADVENTURESPIKEA1}, // S_ADVENTURESPIKEA2 + {SPR_ASPK, 0, 50, {A_PlayAttackSound}, 0, 0, S_ADVENTURESPIKEB2}, // S_ADVENTURESPIKEB1 + {SPR_ASPK, 0, 35, {A_BunnyHop}, 15, 0, S_ADVENTURESPIKEB1}, // S_ADVENTURESPIKEB2 + {SPR_ASPK, 0, 50, {A_PlayAttackSound}, 0, 0, S_ADVENTURESPIKEC2}, // S_ADVENTURESPIKEC1 + {SPR_ASPK, 0, 65, {A_BunnyHop}, 25, 0, S_ADVENTURESPIKEC1}, // S_ADVENTURESPIKEC1 + + {SPR_HBST, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_BOOSTPROMPT2}, // S_BOOSTPROMPT1 + {SPR_HBST, 1|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_BOOSTPROMPT1}, // S_BOOSTPROMPT2 + + {SPR_HBSF, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_BOOSTOFF2}, // S_BOOSTOFF1 + {SPR_HBSF, 1|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_BOOSTOFF1}, // S_BOOSTOFF2 + + {SPR_HBSO, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_BOOSTON2}, // S_BOOSTON1 + {SPR_HBSO, 1|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_BOOSTON1}, // S_BOOSTON2 + + {SPR_WBLZ, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LIZARDMAN + {SPR_WBLN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LIONMAN + {SPR_MSMF, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_MOUSEMAN2}, // S_MOUSEMAN1 + {SPR_MSMF, 1|FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_MOUSEMAN1}, // S_MOUSEMAN2 #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK @@ -9052,7 +9403,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // deathsound 25*FRACUNIT, // speed 16*FRACUNIT, // radius - 40*FRACUNIT, // height + 64*FRACUNIT, // height 0, // display offset 100, // mass 1, // damage @@ -9061,6 +9412,114 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SNOWMANHAT + 1853, // doomednum + S_SNOWMANHAT, // 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 + 25*FRACUNIT, // speed + 16*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_SLIDEME|MF_SOLID|MF_PUSHABLE, // flags + S_NULL // raisestate + }, + + { // MT_LAMPPOST1 + 1854, // doomednum + S_LAMPPOST1, // 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 + 120*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_LAMPPOST2 + 1855, // doomednum + S_LAMPPOST2, // 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 + 120*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_HANGSTAR + 1856, // doomednum + S_HANGSTAR, // 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 + FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + // No, I did not do all of this by hand. // I made a script to make all of these for me. // Ha HA. ~Inuyasha @@ -14776,6 +15235,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BRAKEDRIFT + -1, // doomednum + S_BRAKEDRIFT, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_DRIFTDUST -1, // doomednum S_DRIFTDUST1, // spawnstate @@ -14803,12 +15289,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_FAKESHIELD + { // MT_ROCKETSNEAKER -1, // doomednum - S_FAKEITEM1, // spawnstate - 1000, // spawnhealth + S_ROCKETSNEAKER_L, // spawnstate + 1, // spawnhealth S_NULL, // seestate - sfx_None, // seesound + sfx_tossed, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate @@ -14816,23 +15302,23 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_DEADFAKEITEM, // deathstate + S_NULL, // deathstate S_NULL, // xdeathstate - sfx_kc2e, // deathsound - 8, // speed + sfx_s3k5d, // deathsound + 0, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 16*FRACUNIT, // height 0, // display offset - 100, // mass - 1, // damage - sfx_None, // activesound - MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + 0, // mass + 0, // damage + sfx_s3kc0s, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, - { // MT_FAKEITEM + { // MT_EGGMANITEM -1, // doomednum - S_FAKEITEM1, // spawnstate + S_EGGMANITEM1, // spawnstate 2, // spawnhealth S_NULL, // seestate sfx_tossed, // seesound @@ -14843,7 +15329,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_DEADFAKEITEM, // deathstate + S_EGGMANITEM_DEAD, // deathstate S_NULL, // xdeathstate sfx_kc2e, // deathsound 0, // speed @@ -14857,6 +15343,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_EGGMANITEM_SHIELD + -1, // doomednum + S_EGGMANITEM1, // 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_EGGMANITEM_DEAD, // deathstate + S_NULL, // xdeathstate + sfx_kc2e, // deathsound + 8, // speed + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_BANANA -1, // doomednum S_BANANA, // spawnstate @@ -15109,7 +15622,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 320*FRACUNIT, // painchance + 288*FRACUNIT, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate @@ -15316,34 +15829,34 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_BLUELIGHTNING + { // MT_SPB -1, // doomednum - S_BLUELIGHTNING1, // spawnstate - 1000, // spawnhealth + S_SPB1, // spawnstate + 1, // spawnhealth S_NULL, // seestate - sfx_None, // seesound + sfx_tossed, // seesound 8, // reactiontime - sfx_None, // attacksound + sfx_kc57, // attacksound S_NULL, // painstate 0, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_NULL, // deathstate + S_SPB_DEAD, // deathstate S_NULL, // xdeathstate - sfx_None, // deathsound - 8, // speed - 64*FRACUNIT, // radius - 64*FRACUNIT, // height + sfx_s3k5d, // deathsound + 64*FRACUNIT, // speed + 24*FRACUNIT, // radius + 48*FRACUNIT, // height 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + 100, // mass + 1, // damage + sfx_kc64, // activesound + MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, - { // MT_BLUEEXPLOSION + { // MT_SPBEXPLOSION -1, // doomednum S_INVISIBLE, // spawnstate 1, // spawnhealth @@ -15352,7 +15865,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - 256*FRACUNIT, // painchance + 288*FRACUNIT, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate @@ -15370,33 +15883,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_LIGHTNING - -1, // doomednum - S_LIGHTNING1, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 8, // speed - 64*FRACUNIT, // radius - 64*FRACUNIT, // height - 0, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags - S_NULL // raisestate - }, - { // MT_THUNDERSHIELD -1, // doomednum S_THUNDERSHIELD1, // spawnstate @@ -15980,14 +16466,14 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound - 8, // speed + 0, // speed 16*FRACUNIT, // radius - 40*FRACUNIT, // height + 189*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 0, // damage sfx_None, // activesound - MF_NOCLIP|MF_SCENERY, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags S_NULL // raisestate }, @@ -16332,13 +16818,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 1048576, // radius - 2097152, // height + 91*FRACUNIT, // radius + 166*FRACUNIT, // height 0, // display offset - 100, // mass + 0, // mass 0, // damage sfx_None, // activesound - 33554944, // flags + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -17127,7 +17613,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_KARMAHITBOX -1, // doomednum - S_PLAYERBOMB, // spawnstate + S_PLAYERBOMB1, // spawnstate 1000, // spawnhealth S_PLAYERITEM, // seestate sfx_kc2e, // seesound @@ -17142,7 +17628,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 26*FRACUNIT, // radius + 24*FRACUNIT, // radius 52*FRACUNIT, // height -1, // display offset 0, // mass @@ -17179,6 +17665,2762 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BATTLEPOINT + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + -1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_FZEROBOOM + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_kc31, // seesound + 8, // reactiontime + sfx_kc51, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_SONICBUSH, + 715, // doomednum + S_SONICBUSH, // 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 + 192*FRACUNIT, // radius + 922*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_SHRUB, + 4022, // doomednum + S_SHRUB, // 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 + 91*FRACUNIT, // radius + 166*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_TALLBUSH, + 1485, // doomednum + S_TALLBUSH, // 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 + 91*FRACUNIT, // radius + 166*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_AZURECITYTREE, + 1486, // doomednum + S_AZURECITYTREE,// 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 + 91*FRACUNIT, // radius + 166*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_FLAMEPARTICLE + -1, // doomednum + S_FLAMEPARTICLE,// 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_MARBLETORCH + 1969, // doomednum + S_MARBLETORCH, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + MT_FLAMEPARTICLE,// painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 12*FRACUNIT, // radius + 45*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOGRAVITY|MF_FIRE|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_MARBLELIGHT + -1, // doomednum + S_MARBLELIGHT, // 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 + FRACUNIT, // radius + FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags + S_NULL // raisestate + }, + + { // MT_MARBLEBURNER + 1970, // doomednum + S_MARBLEBURNER, // 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 + 24*FRACUNIT, // radius + 96*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_SOLID, // flags + S_NULL // raisestate + }, + + { // MT_CDUFO + 4050, // doomednum + S_CDUFO, // spawnstate + 1, // 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_CDUFO_DIE, // deathstate + S_NULL, // xdeathstate + sfx_cdfm19, // deathsound + 0, // speed + 70*FRACUNIT, // radius + 70*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_RUSTYLAMP_ORANGE + 1988, // doomednum + S_RUSTYLAMP_ORANGE, // 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 + 12*FRACUNIT, // radius + 45*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_RUSTYCHAIN + 1989, // doomednum + S_RUSTYCHAIN, // 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 + 12*FRACUNIT, // radius + 45*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_BALLOON + 462, // doomednum + S_BALLOON, // 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_BALLOONPOP1, // deathstate + S_NULL, // xdeathstate + sfx_s3k77, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PETSMOKER + 2018, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 24*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_PETSMOKE + -1, // doomednum + S_PETSMOKE0, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_VVVAPING0, // 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 + 12*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_VVVAPE + 1600, // doomednum + S_VVVAPE, // 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 + 16*FRACUNIT, // radius + 64*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOGRAVITY|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + + { // MT_HTZTREE + 716, // doomednum + S_HTZTREE, // 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 + 5*FRACUNIT, // radius + 204*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_SOLID|MF_RUNSPAWNFUNC|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_HTZBUSH + 717, // doomednum + S_HTZBUSH, // 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 + 24*FRACUNIT, // radius + 38*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTHINK|MF_SCENERY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_SGVINE1 + 718, // doomednum + S_SGVINE1, // 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 + 32*FRACUNIT, // radius + 256*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_SGVINE2 + 719, // doomednum + S_SGVINE2, // 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 + 17*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTHINK|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_SGVINE3 + 720, // doomednum + S_SGVINE3, // 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 + 17*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTHINK|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PGTREE + 711, // doomednum + S_PGTREE, // 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 + 30*FRACUNIT, // radius + 504*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PGFLOWER1 + 712, // doomednum + S_PGFLOWER1, // 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 + 17*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTHINK|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PGFLOWER2 + 713, // doomednum + S_PGFLOWER2, // 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 + 17*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTHINK|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PGFLOWER3 + 714, // doomednum + S_PGFLOWER3, // 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 + 17*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTHINK|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_PGBUSH + 715, // doomednum + S_PGBUSH, // 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 + 384*FRACUNIT, // radius + 922*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_DHPILLAR + 1960, // doomednum + S_DHPILLAR, // 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 + 58*FRACUNIT, // radius + 256*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIP, // flags + S_NULL // raisestate + }, + + // Midnight Channel stuff: + { // MT_SPOTLIGHT + 3124, // doomednum + S_SPOTLIGHT, // 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 + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOTHINK|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_RANDOMSHADOW + 3120, // doomednum + S_RANDOMSHADOW, // 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 + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_PAIN, // flags + S_NULL // raisestate + }, + + { // MT_ROAMINGSHADOW + 3121, // doomednum + S_ROAMINGSHADOW,// 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 + 16*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_PAIN|MF_SPECIAL|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + { // MT_MAYONAKAARROW + 3122, // doomednum + S_MAYONAKAARROW,// spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 64*FRACUNIT, // radius + 128*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags + S_NULL // raisestate + }, + + // Mementos stuff + { // MT_REAPERWAYPOINT + 3199, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 64*FRACUNIT, // radius + 128*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_REAPER + 3202, // doomednum + S_REAPER_INVIS, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 64*FRACUNIT, // radius + 128*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY, // flags + S_NULL // raisestate + }, + + { // MT_MEMENTOSTP + 3201, // doomednum + S_MEMENTOSTP, // 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 + 512*FRACUNIT, // radius + 16*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_SPECIAL, // flags + S_NULL // raisestate + }, + + { // MT_MEMENTOSPARTICLE + -1, // doomednum + S_THOK, // 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 + 32< 2)) newodds = 0; + if ((!cv_invincibility.value) || (pinvin >= 2)) newodds = 0; break; case KITEM_BANANA: if (!cv_banana.value) newodds = 0; @@ -700,7 +700,7 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed) break; case KITEM_GROW: POWERITEMODDS(newodds); - if ((!cv_grow.value) || (pinvin > 2)) newodds = 0; + if ((!cv_grow.value) || (pinvin >= 2)) newodds = 0; break; case KITEM_SHRINK: POWERITEMODDS(newodds); @@ -894,7 +894,35 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // This makes the roulette produce the random noises. if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsLocalPlayer(player)) - S_StartSound(NULL, sfx_mkitm1 + ((player->kartstuff[k_itemroulette] / 3) % 8)); + { +#define PLAYROULETTESND S_StartSound(NULL, sfx_mkitm1 + ((player->kartstuff[k_itemroulette] / 3) % 8)); + if (splitscreen) + { + if (players[displayplayer].kartstuff[k_itemroulette]) + { + if (player == &players[displayplayer]) + PLAYROULETTESND; + } + else if (players[secondarydisplayplayer].kartstuff[k_itemroulette]) + { + if (player == &players[secondarydisplayplayer]) + PLAYROULETTESND; + } + else if (players[thirddisplayplayer].kartstuff[k_itemroulette] && splitscreen > 1) + { + if (player == &players[thirddisplayplayer]) + PLAYROULETTESND; + } + else if (players[fourthdisplayplayer].kartstuff[k_itemroulette] && splitscreen > 2) + { + if (player == &players[fourthdisplayplayer]) + PLAYROULETTESND; + } + } + else + PLAYROULETTESND; +#undef PLAYROULETTESND + } roulettestop = TICRATE + (3*(pingame - player->kartstuff[k_position])); @@ -1022,7 +1050,6 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj_t *fx; fixed_t momdifx, momdify; fixed_t distx, disty; - //fixed_t nobumpx = 0, nobumpy = 0; fixed_t dot, p; fixed_t mass1, mass2; @@ -1071,20 +1098,28 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) momdify = FixedMul((25*mapheaderinfo[gamemap-1]->mobj_scale), normalisedy); } - /*if (mass1 == 0 && mass2 > 0) - { - nobumpx = mobj2->momx; - nobumpy = mobj2->momy; - } - else if (mass2 == 0 && mass1 > 0) - { - nobumpx = mobj1->momx; - nobumpy = mobj1->momy; - }*/ - + // Adds the OTHER player's momentum, so that it reduces the chance of you being "inside" the other object distx = (mobj1->x + mobj2->momx) - (mobj2->x + mobj1->momx); disty = (mobj1->y + mobj2->momy) - (mobj2->y + mobj1->momy); + { // Don't allow dist to get WAY too low, that it pushes you stupidly huge amounts, or backwards... + fixed_t dist = P_AproxDistance(distx, disty); + fixed_t nx = FixedDiv(distx, dist); + fixed_t ny = FixedDiv(disty, dist); + + if (P_AproxDistance(distx, disty) < (3*mobj1->radius)/4) + { + distx = FixedMul((3*mobj1->radius)/4, nx); + disty = FixedMul((3*mobj1->radius)/4, ny); + } + + if (P_AproxDistance(distx, disty) < (3*mobj2->radius)/4) + { + distx = FixedMul((3*mobj2->radius)/4, nx); + disty = FixedMul((3*mobj2->radius)/4, ny); + } + } + 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 @@ -1241,7 +1276,7 @@ static void K_UpdateOffroad(player_t *player) } // These have to go earlier than its sisters because of K_RespawnChecker... -static void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master) +void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master) { // flipping mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP)|(master->eflags & MFE_VERTICALFLIP); @@ -1295,6 +1330,23 @@ static void K_SpawnDashDustRelease(player_t *player) } } +static void K_SpawnBrakeDriftSparks(player_t *player) // Be sure to update the mobj thinker case too! +{ + mobj_t *sparks; + + I_Assert(player != NULL); + I_Assert(player->mo != NULL); + I_Assert(!P_MobjWasRemoved(player->mo)); + + // Position & etc are handled in its thinker, and its spawned invisible. + // This avoids needing to dupe code if we don't need it. + sparks = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BRAKEDRIFT); + P_SetTarget(&sparks->target, player->mo); + P_SetScale(sparks, (sparks->destscale = player->mo->scale)); + K_MatchGenericExtraFlags(sparks, player->mo); + sparks->flags2 |= MF2_DONTDRAW; +} + /** \brief Calculates the respawn timer and drop-boosting \param player player object passed from K_KartPlayerThink @@ -1327,8 +1379,8 @@ void K_RespawnChecker(player_t *player) fixed_t newx, newy, newz; newangle = FixedAngle(((360/8)*i)*FRACUNIT); - newx = player->mo->x + P_ReturnThrustX(player->mo, newangle, 31*player->mo->scale); - newy = player->mo->y + P_ReturnThrustY(player->mo, newangle, 31*player->mo->scale); + newx = player->mo->x + P_ReturnThrustX(player->mo, newangle, 31<mo->y + P_ReturnThrustY(player->mo, newangle, 31<mo->eflags & MFE_VERTICALFLIP) newz = player->mo->z + player->mo->height; else @@ -1348,11 +1400,19 @@ void K_RespawnChecker(player_t *player) } else if (player->kartstuff[k_respawn] == 1) { - if (!P_IsObjectOnGround(player->mo)) + if (player->kartstuff[k_growshrinktimer] < 0) + { + player->mo->scalespeed = mapheaderinfo[gamemap-1]->mobj_scale/TICRATE; + player->mo->destscale = 6*(mapheaderinfo[gamemap-1]->mobj_scale)/8; + if (cv_kartdebugshrink.value && !player->bot) + player->mo->destscale = 6*player->mo->destscale/8; + } + + if (!P_IsObjectOnGround(player->mo) && !mapreset) { player->powers[pw_flashing] = 2; - // Sal: That's stupid and prone to accidental usage. + // Sal: The old behavior was stupid and prone to accidental usage. // Let's rip off Mania instead, and turn this into a Drop Dash! if (cmd->buttons & BT_ACCELERATE) @@ -1741,6 +1801,32 @@ void K_DoInstashield(player_t *player) P_SetTarget(&layerb->target, player->mo); } +void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount) +{ + statenum_t st; + mobj_t *pt; + + if (!source || !source->mo) + return; + + if (amount == 1) + st = S_BATTLEPOINT1A; + else if (amount == 2) + st = S_BATTLEPOINT2A; + else if (amount == 3) + st = S_BATTLEPOINT3A; + else + return; // NO STATE! + + pt = P_SpawnMobj(source->mo->x, source->mo->y, source->mo->z, MT_BATTLEPOINT); + P_SetTarget(&pt->target, source->mo); + P_SetMobjState(pt, st); + if (victim && victim->skincolor) + pt->color = victim->skincolor; + else + pt->color = source->skincolor; +} + void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem) { UINT8 scoremultiply = 1; @@ -1774,6 +1860,7 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem if (source && source->player && player != source->player) { P_AddPlayerScore(source->player, scoremultiply); + K_SpawnBattlePoints(source->player, player, scoremultiply); if (!trapitem) { source->player->kartstuff[k_wanted] -= wantedreduce; @@ -1812,19 +1899,15 @@ void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem player->kartstuff[k_spinouttype] = type; - if (player->kartstuff[k_spinouttype] <= 0) + if (player->kartstuff[k_spinouttype] <= 0) // type 0 is spinout, type 1 is wipeout { - player->kartstuff[k_spinouttimer] = 3*TICRATE/2; // Banana Spinout - // At spinout, player speed is increased to 1/4 their regular speed, moving them forward if (player->speed < K_GetKartSpeed(player, true)/4) P_InstaThrust(player->mo, player->mo->angle, FixedMul(K_GetKartSpeed(player, true)/4, player->mo->scale)); - S_StartSound(player->mo, sfx_slip); } - else - player->kartstuff[k_spinouttimer] = TICRATE+20; // Wipeout + player->kartstuff[k_spinouttimer] = (3*TICRATE/2)+2; player->powers[pw_flashing] = K_GetKartFlashing(player); if (player->mo->state != &states[S_KART_SPIN]) @@ -1868,6 +1951,7 @@ void K_SquishPlayer(player_t *player, mobj_t *source) if (source && source->player && player != source->player) { P_AddPlayerScore(source->player, scoremultiply); + K_SpawnBattlePoints(source->player, player, scoremultiply); source->player->kartstuff[k_wanted] -= wantedreduce; player->kartstuff[k_wanted] -= (wantedreduce/2); } @@ -1901,7 +1985,7 @@ void K_SquishPlayer(player_t *player, mobj_t *source) K_CheckBumpers(); } - player->kartstuff[k_squishedtimer] = 2*TICRATE; + player->kartstuff[k_squishedtimer] = TICRATE; player->powers[pw_flashing] = K_GetKartFlashing(player); @@ -1920,7 +2004,7 @@ void K_SquishPlayer(player_t *player, mobj_t *source) return; } -void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer +void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A bit of a hack, we just throw the player up higher here and extend their spinout timer { UINT8 scoremultiply = 1; if (G_BattleGametype()) @@ -1934,8 +2018,8 @@ void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we ju if (player->health <= 0) return; - if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 - || player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 + if (/*player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 // Explosions should combo, because of SPB and Eggman + ||*/player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0 || (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1))) { K_DoInstashield(player); @@ -1951,11 +2035,13 @@ void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we ju player->kartstuff[k_sneakertimer] = 0; player->kartstuff[k_driftboost] = 0; - if (G_BattleGametype()) + // This is the only part that SHOULDN'T combo :VVVVV + if (G_BattleGametype() && !(player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0)) { if (source && source->player && player != source->player) { P_AddPlayerScore(source->player, scoremultiply); + K_SpawnBattlePoints(source->player, player, scoremultiply); source->player->kartstuff[k_wanted] -= wantedreduce; player->kartstuff[k_wanted] -= (wantedreduce/2); } @@ -1994,6 +2080,12 @@ void K_ExplodePlayer(player_t *player, mobj_t *source) // A bit of a hack, we ju player->powers[pw_flashing] = K_GetKartFlashing(player); + if (inflictor && inflictor->type == MT_SPBEXPLOSION && inflictor->extravalue1) + { + player->kartstuff[k_spinouttimer] = ((3*player->kartstuff[k_spinouttimer])/2)+1; + player->mo->momz *= 2; + } + if (player->mo->state != &states[S_KART_SPIN]) P_SetPlayerMobjState(player->mo, S_KART_SPIN); @@ -2042,13 +2134,8 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force) } } - if (netgame) - { - if (player->kartstuff[k_bumper] <= 0) - CONS_Printf(M_GetText("%s is back in the game!\n"), player_names[player-players]); - else if (cv_hazardlog.value) - CONS_Printf(M_GetText("%s stole a bumper from %s!\n"), player_names[player-players], player_names[victim-players]); - } + if (netgame && player->kartstuff[k_bumper] <= 0) + CONS_Printf(M_GetText("%s is back in the game!\n"), player_names[player-players]); newbumper = player->kartstuff[k_bumper]; if (newbumper <= 1) @@ -2169,9 +2256,6 @@ void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 mobj->momy = FixedMul(FixedDiv(mobjy - y, dist), FixedDiv(dist, 6*FRACUNIT)); mobj->momz = FixedMul(FixedDiv(mobjz - z, dist), FixedDiv(dist, 6*FRACUNIT)); - mobj->flags |= MF_NOCLIPTHING; - mobj->flags &= ~MF_SPECIAL; - P_SetTarget(&mobj->target, source); } } @@ -2190,7 +2274,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) height = source->height>>FRACBITS; if (!color) - color = SKINCOLOR_RED; + color = SKINCOLOR_KETCHUP; for (i = 0; i < 32; i++) { @@ -2198,7 +2282,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) dust->angle = (ANGLE_180/16) * i; P_SetScale(dust, source->scale); dust->destscale = source->scale*10; - dust->scalespeed = FixedMul(dust->scalespeed, source->scale); + dust->scalespeed = source->scale/12; P_InstaThrust(dust, dust->angle, FixedMul(20*FRACUNIT, source->scale)); truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT, @@ -2206,7 +2290,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMEXPLODE); P_SetScale(truc, source->scale); truc->destscale = source->scale*6; - truc->scalespeed = FixedMul(truc->scalespeed, source->scale); + truc->scalespeed = source->scale/12; speed = FixedMul(10*FRACUNIT, source->scale)>>FRACBITS; truc->momx = P_RandomRange(-speed, speed)*FRACUNIT; truc->momy = P_RandomRange(-speed, speed)*FRACUNIT; @@ -2222,7 +2306,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) source->z + P_RandomRange(0, height)*FRACUNIT, MT_SMOKE); P_SetScale(dust, source->scale); dust->destscale = source->scale*10; - dust->scalespeed = FixedMul(dust->scalespeed, source->scale); + dust->scalespeed = source->scale/12; dust->tics = 30; dust->momz = P_RandomRange(FixedMul(3*FRACUNIT, source->scale)>>FRACBITS, FixedMul(7*FRACUNIT, source->scale)>>FRACBITS)*FRACUNIT; @@ -2231,7 +2315,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMPARTICLE); P_SetScale(truc, source->scale); truc->destscale = source->scale*5; - truc->scalespeed = FixedMul(truc->scalespeed, source->scale); + truc->scalespeed = source->scale/12; speed = FixedMul(20*FRACUNIT, source->scale)>>FRACBITS; truc->momx = P_RandomRange(-speed, speed)*FRACUNIT; truc->momy = P_RandomRange(-speed, speed)*FRACUNIT; @@ -2630,7 +2714,7 @@ void K_DriftDustHandling(mobj_t *spawner) dust->momz = P_MobjFlip(spawner) * (P_RandomRange(1, 4) * (spawner->scale)); P_SetScale(dust, spawner->scale/2); dust->destscale = spawner->scale * 3; - dust->scalespeed = FixedMul(dust->scalespeed, spawner->scale); + dust->scalespeed = spawner->scale/12; if (leveltime % 6 == 0) S_StartSound(spawner, sfx_screec); @@ -2733,7 +2817,7 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map } else { - if (dir == -1) + if (dir == -1 && mapthing != MT_SPB) { // Shoot backward mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180, 0, PROJSPEED/4); @@ -2967,35 +3051,66 @@ static void K_DoHyudoroSteal(player_t *player) } } -void K_DoSneaker(player_t *player, boolean doPFlag) +void K_DoSneaker(player_t *player, INT32 type) { - const fixed_t prevboost = player->kartstuff[k_speedboost]; + fixed_t intendedboost; + + switch (gamespeed) + { + case 0: + intendedboost = 53740+768; + break; + case 2: + intendedboost = 17294+768; + break; + default: + intendedboost = 32768; + break; + } if (!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) { S_StartSound(player->mo, sfx_cdfm01); K_SpawnDashDustRelease(player); + if (intendedboost > player->kartstuff[k_speedboost]) + player->kartstuff[k_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->kartstuff[k_speedboost]), intendedboost)); } if (!player->kartstuff[k_sneakertimer]) { - mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME); - P_SetTarget(&overlay->target, player->mo); - overlay->destscale = player->mo->scale; - P_SetScale(overlay, player->mo->scale); + if (type == 2) + { + if (player->mo->hnext) + { + mobj_t *cur = player->mo->hnext; + while (cur && !P_MobjWasRemoved(cur)) + { + if (!cur->tracer) + { + mobj_t *overlay = P_SpawnMobj(cur->x, cur->y, cur->z, MT_BOOSTFLAME); + P_SetTarget(&overlay->target, cur); + P_SetTarget(&cur->tracer, overlay); + P_SetScale(overlay, (overlay->destscale = 3*cur->scale/4)); + } + cur = cur->hnext; + } + } + } + else + { + mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME); + P_SetTarget(&overlay->target, player->mo); + P_SetScale(overlay, (overlay->destscale = player->mo->scale)); + } } player->kartstuff[k_sneakertimer] = sneakertime; - if (doPFlag) + if (type != 0) { player->pflags |= PF_ATTACKDOWN; K_PlayBoostTaunt(player->mo); } - - K_GetKartBoostPower(player); - if (player->kartstuff[k_speedboost] > prevboost) - player->kartstuff[k_destboostcam] = FRACUNIT; } static void K_DoShrink(player_t *player) @@ -3016,38 +3131,6 @@ static void K_DoShrink(player_t *player) } } -static void K_DoSPB(player_t *victim) -{ - //INT32 i; - S_StartSound(victim->mo, sfx_bkpoof); // Sound the BANG! - - /*for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - P_FlashPal(&players[i], PAL_NUKE, 10); - }*/ - - if (!victim->mo || !victim->mo->health || victim->spectator) - return; - - { - mobj_t *spbexplode; - - if (!victim->kartstuff[k_invincibilitytimer] && !victim->kartstuff[k_growshrinktimer]) - { - K_DropHnextList(victim); - K_StripItems(victim); - - victim->powers[pw_flashing] = 0; - } - - spbexplode = P_SpawnMobj(victim->mo->x, victim->mo->y, victim->mo->z, MT_BLUEEXPLOSION); - - if (playeringame[spbplayer] && !players[spbplayer].spectator && players[spbplayer].mo) - P_SetTarget(&spbexplode->target, players[spbplayer].mo); - } -} - void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) { const fixed_t vscale = mapheaderinfo[gamemap-1]->mobj_scale + (mo->scale - mapheaderinfo[gamemap-1]->mobj_scale); @@ -3200,12 +3283,13 @@ void K_DropHnextList(player_t *player) dropall = false; type = MT_SSMINE; break; - case MT_FAKESHIELD: + case MT_EGGMANITEM_SHIELD: orbit = false; - type = MT_FAKEITEM; + type = MT_EGGMANITEM; break; // intentionally do nothing case MT_SINK_SHIELD: + case MT_ROCKETSNEAKER: return; default: continue; @@ -3302,8 +3386,6 @@ void K_DropItems(player_t *player) drop->destscale = (3*drop->destscale)/2;; drop->angle = player->mo->angle + ANGLE_90; - drop->momx = player->mo->momx>>1; - drop->momy = player->mo->momy>>1; P_Thrust(drop, FixedAngle(P_RandomFixed()*180) + player->mo->angle + ANGLE_90, 8*(mapheaderinfo[gamemap-1]->mobj_scale)); @@ -3471,7 +3553,7 @@ static void K_MoveHeldObjects(player_t *player) break; case MT_BANANA_SHIELD: // Kart trailing items case MT_SSMINE_SHIELD: - case MT_FAKESHIELD: + case MT_EGGMANITEM_SHIELD: case MT_SINK_SHIELD: { mobj_t *cur = player->mo->hnext; @@ -3553,6 +3635,93 @@ static void K_MoveHeldObjects(player_t *player) } } break; + case MT_ROCKETSNEAKER: // Special rocket sneaker stuff + { + mobj_t *cur = player->mo->hnext; + INT32 num = 0; + + while (cur && !P_MobjWasRemoved(cur)) + { + const fixed_t radius = FixedHypot(player->mo->radius, player->mo->radius) + FixedHypot(cur->radius, cur->radius); + boolean vibrate = ((leveltime & 1) && !cur->tracer); + angle_t angoffset; + fixed_t targx, targy, targz; + + cur->flags &= ~MF_NOCLIPTHING; + + if (player->kartstuff[k_rocketsneakertimer] <= TICRATE && (leveltime & 1)) + cur->flags2 |= MF2_DONTDRAW; + else + cur->flags2 &= ~MF2_DONTDRAW; + + if (num & 1) + P_SetMobjStateNF(cur, (vibrate ? S_ROCKETSNEAKER_LVIBRATE : S_ROCKETSNEAKER_L)); + else + P_SetMobjStateNF(cur, (vibrate ? S_ROCKETSNEAKER_RVIBRATE : S_ROCKETSNEAKER_R)); + + if (!player->kartstuff[k_rocketsneakertimer] || cur->extravalue2 || !cur->health) + { + num = (num+1) % 2; + cur = cur->hnext; + continue; + } + + if (cur->extravalue1 < radius) + cur->extravalue1 += FixedMul(P_AproxDistance(cur->extravalue1, radius), FRACUNIT/12); + if (cur->extravalue1 > radius) + cur->extravalue1 = radius; + + // Shrink your items if the player shrunk too. + P_SetScale(cur, (cur->destscale = FixedMul(FixedDiv(cur->extravalue1, radius), player->mo->scale))); + +#if 1 + { + angle_t input = player->frameangle - cur->angle; + boolean invert = (input > ANGLE_180); + if (invert) + input = InvAngle(input); + + input = FixedAngle(AngleFixed(input)/4); + if (invert) + input = InvAngle(input); + + cur->angle = cur->angle + input; + } +#else + cur->angle = player->frameangle; +#endif + + angoffset = ANGLE_90 + (ANGLE_180 * num); + + targx = player->mo->x + P_ReturnThrustX(cur, cur->angle + angoffset, cur->extravalue1); + targy = player->mo->y + P_ReturnThrustY(cur, cur->angle + angoffset, cur->extravalue1); + + { // bobbing, copy pasted from my kimokawaiii entry + const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK); + targz = (player->mo->z + (player->mo->height/2)) + sine; + } + + if (cur->tracer) + { + fixed_t diffx, diffy, diffz; + + diffx = targx - cur->x; + diffy = targy - cur->y; + diffz = targz - cur->z; + + P_TeleportMove(cur->tracer, cur->tracer->x + diffx + P_ReturnThrustX(cur, cur->angle + angoffset, 6*cur->scale), + cur->tracer->y + diffy + P_ReturnThrustY(cur, cur->angle + angoffset, 6*cur->scale), cur->tracer->z + diffz); + P_SetScale(cur->tracer, (cur->tracer->destscale = 3*cur->scale/4)); + } + + P_TeleportMove(cur, targx, targy, targz); + + num = (num+1) % 2; + cur = cur->hnext; + } + } + break; default: break; } @@ -3756,9 +3925,15 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) fast->momx = 3*player->mo->momx/4; fast->momy = 3*player->mo->momy/4; fast->momz = 3*player->mo->momz/4; + K_MatchGenericExtraFlags(fast, player->mo); } - if (player->kartstuff[k_eggmanexplode]) // You're gonna diiiiie + if (player->playerstate == PST_DEAD || player->kartstuff[k_respawn] > 1) // Ensure these are set correctly here + { + player->mo->colorized = false; + player->mo->color = player->skincolor; + } + else if (player->kartstuff[k_eggmanexplode]) // You're gonna diiiiie { const INT32 flashtime = 4<<(player->kartstuff[k_eggmanexplode]/TICRATE); if (player->kartstuff[k_eggmanexplode] == 1 || (player->kartstuff[k_eggmanexplode] % (flashtime/2) != 0)) @@ -3833,6 +4008,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) //CONS_Printf("cam: %d, dest: %d\n", player->kartstuff[k_boostcam], player->kartstuff[k_destboostcam]); } + player->kartstuff[k_timeovercam] = 0; + + // Make ABSOLUTELY SURE that your flashing tics don't get set WHILE you're still in hit animations. + if (player->kartstuff[k_spinouttimer] != 0 + || player->kartstuff[k_wipeoutslow] != 0 + || player->kartstuff[k_squishedtimer] != 0) + { + player->powers[pw_flashing] = K_GetKartFlashing(player); + } + else if (player->powers[pw_flashing] == K_GetKartFlashing(player)) + { + player->powers[pw_flashing]--; + } + if (player->kartstuff[k_spinouttimer]) { if ((P_IsObjectOnGround(player->mo) || player->kartstuff[k_spinouttype] == 1) @@ -3860,9 +4049,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } - if (player->kartstuff[k_spinouttimer] == 0 && player->powers[pw_flashing] == K_GetKartFlashing(player)) - player->powers[pw_flashing]--; - /*if (player->kartstuff[k_thunderanim]) player->kartstuff[k_thunderanim]--;*/ @@ -3885,11 +4071,13 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_invincibilitytimer]) player->kartstuff[k_invincibilitytimer]--; - if (player->kartstuff[k_growshrinktimer] > 0) - player->kartstuff[k_growshrinktimer]--; - - if (player->kartstuff[k_growshrinktimer] < 0) - player->kartstuff[k_growshrinktimer]++; + if (!player->kartstuff[k_respawn]) + { + if (player->kartstuff[k_growshrinktimer] > 0) + player->kartstuff[k_growshrinktimer]--; + if (player->kartstuff[k_growshrinktimer] < 0) + player->kartstuff[k_growshrinktimer]++; + } if (player->kartstuff[k_growshrinktimer] == 1 || player->kartstuff[k_growshrinktimer] == -1) { @@ -3923,16 +4111,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_justbumped]) player->kartstuff[k_justbumped]--; - if (player->kartstuff[k_deathsentence]) - { - if (player->kartstuff[k_deathsentence] == 1) - K_DoSPB(player); - player->kartstuff[k_deathsentence]--; - } - if (player->kartstuff[k_lapanimation]) player->kartstuff[k_lapanimation]--; + if (player->kartstuff[k_yougotem]) + player->kartstuff[k_yougotem]--; + if (G_BattleGametype() && (player->exiting || player->kartstuff[k_comebacktimer])) { if (player->exiting) @@ -3990,8 +4174,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_eggmanexplode] <= 0) { mobj_t *eggsexplode; - player->powers[pw_flashing] = 0; - eggsexplode = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BLUEEXPLOSION); + //player->powers[pw_flashing] = 0; + eggsexplode = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SPBEXPLOSION); if (player->kartstuff[k_eggmanblame] >= 0 && player->kartstuff[k_eggmanblame] < MAXPLAYERS && playeringame[player->kartstuff[k_eggmanblame]] @@ -4320,7 +4504,8 @@ static void K_KartDrift(player_t *player, boolean onground) if (player->kartstuff[k_spinouttimer] > 0 // banana peel || player->speed < FixedMul(10<<16, player->mo->scale)) // you're too slow! { - player->kartstuff[k_drift] = player->kartstuff[k_driftcharge] = player->kartstuff[k_aizdriftstrat] = 0; + player->kartstuff[k_drift] = player->kartstuff[k_driftcharge] = 0; + player->kartstuff[k_aizdriftstrat] = player->kartstuff[k_brakedrift] = 0; } if ((!player->kartstuff[k_sneakertimer]) @@ -4334,6 +4519,18 @@ static void K_KartDrift(player_t *player, boolean onground) } else if (player->kartstuff[k_aizdriftstrat] && !player->kartstuff[k_drift]) K_SpawnAIZDust(player); + + if (player->kartstuff[k_drift] + && ((player->cmd.buttons & BT_BRAKE) + || !(player->cmd.buttons & BT_ACCELERATE)) + && P_IsObjectOnGround(player->mo)) + { + if (!player->kartstuff[k_brakedrift]) + K_SpawnBrakeDriftSparks(player); + player->kartstuff[k_brakedrift] = 1; + } + else + player->kartstuff[k_brakedrift] = 0; } // // K_KartUpdatePosition @@ -4528,7 +4725,8 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (cmd->buttons & BT_ATTACK) player->pflags |= PF_ATTACKDOWN; - if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) && player->kartstuff[k_spinouttimer] == 0) + if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset) + && player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_squishedtimer] == 0 && player->kartstuff[k_respawn] == 0) { // First, the really specific, finicky items that function without the item being directly in your item slot. // Karma item dropping @@ -4543,7 +4741,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } else { - newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FAKEITEM); + newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM); if (player->kartstuff[k_eggmanblame] >= 0 && player->kartstuff[k_eggmanblame] < MAXPLAYERS && playeringame[player->kartstuff[k_eggmanblame]] @@ -4569,7 +4767,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) // Eggman Monitor throwing else if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanheld]) { - K_ThrowKartItem(player, false, MT_FAKEITEM, -1, 0); + K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0); K_PlayAttackTaunt(player->mo); player->kartstuff[k_eggmanheld] = 0; K_UpdateHnextList(player, true); @@ -4578,9 +4776,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO && player->kartstuff[k_rocketsneakertimer] > 1) { - K_DoSneaker(player, true); + K_DoSneaker(player, 2); K_PlayBoostTaunt(player->mo); - player->kartstuff[k_rocketsneakertimer] -= 5; + player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE; if (player->kartstuff[k_rocketsneakertimer] < 1) player->kartstuff[k_rocketsneakertimer] = 1; } @@ -4595,7 +4793,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) case KITEM_SNEAKER: if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO) { - K_DoSneaker(player, true); + K_DoSneaker(player, 1); K_PlayBoostTaunt(player->mo); player->kartstuff[k_itemamount]--; } @@ -4604,10 +4802,33 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO && player->kartstuff[k_rocketsneakertimer] == 0) { - K_DoSneaker(player, true); + INT32 moloop; + mobj_t *mo = NULL; + mobj_t *prev = player->mo; + K_PlayBoostTaunt(player->mo); - player->kartstuff[k_rocketsneakertimer] = itemtime; + //player->kartstuff[k_itemheld] = 1; + S_StartSound(player->mo, sfx_s3k3a); + + //K_DoSneaker(player, 2); + + player->kartstuff[k_rocketsneakertimer] = (itemtime*3); player->kartstuff[k_itemamount]--; + K_UpdateHnextList(player, true); + + for (moloop = 0; moloop < 2; moloop++) + { + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER); + mo->flags |= MF_NOCLIPTHING; + mo->angle = player->mo->angle; + mo->threshold = 10; + mo->movecount = moloop%2; + mo->movedir = mo->lastlook = moloop+1; + P_SetTarget(&mo->target, player->mo); + P_SetTarget(&mo->hprev, prev); + P_SetTarget(&prev->hnext, mo); + prev = mo; + } } break; case KITEM_INVINCIBILITY: @@ -4672,7 +4893,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_itemamount]--; player->kartstuff[k_eggmanheld] = 1; S_StartSound(player->mo, sfx_s254); - mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FAKESHIELD); + mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD); if (mo) { mo->flags |= MF_NOCLIPTHING; @@ -4799,45 +5020,14 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { player->kartstuff[k_itemamount]--; K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0); - S_StartSound(player->mo, sfx_mario7); K_PlayAttackTaunt(player->mo); } break; case KITEM_SPB: if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { - UINT8 ploop; - UINT8 bestrank = 0; - fixed_t dist = 0; - - for (ploop = 0; ploop < MAXPLAYERS; ploop++) - { - fixed_t thisdist; - if (!playeringame[ploop] || players[ploop].spectator) - continue; - if (&players[ploop] == player) - continue; - if (!players[ploop].mo) - continue; - if (players[ploop].exiting) - continue; - thisdist = R_PointToDist2(player->mo->x, player->mo->y, players[ploop].mo->x, players[ploop].mo->y); - if (bestrank == 0 || players[ploop].kartstuff[k_position] < bestrank) - { - bestrank = players[ploop].kartstuff[k_position]; - dist = thisdist; - } - } - - if (dist == 0) - spbincoming = 6*TICRATE; // If you couldn't find anyone, just set an abritary timer - else - spbincoming = (tic_t)max(1, FixedDiv(dist, 64*FRACUNIT)/FRACUNIT); - - spbplayer = player-players; - player->kartstuff[k_itemamount]--; - + K_ThrowKartItem(player, true, MT_SPB, 1, 0); K_PlayAttackTaunt(player->mo); } break; @@ -4846,7 +5036,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage { K_PlayPowerGloatSound(player->mo); - player->mo->scalespeed = FRACUNIT/TICRATE; + player->mo->scalespeed = mapheaderinfo[gamemap-1]->mobj_scale/TICRATE; player->mo->destscale = 3*(mapheaderinfo[gamemap-1]->mobj_scale)/2; if (cv_kartdebugshrink.value && !player->bot) player->mo->destscale = 6*player->mo->destscale/8; @@ -4867,11 +5057,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_THUNDERSHIELD: - if (player->kartstuff[k_curshield] <= 0) + if (player->kartstuff[k_curshield] != 1) { mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD); P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); P_SetTarget(&shield->target, player->mo); + S_StartSound(shield, sfx_s3k41); player->kartstuff[k_curshield] = 1; } if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) @@ -4949,8 +5140,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_itemtype] == KITEM_SPB || player->kartstuff[k_itemtype] == KITEM_SHRINK - || player->kartstuff[k_growshrinktimer] < 0 - || spbincoming) + || player->kartstuff[k_growshrinktimer] < 0) indirectitemcooldown = 20*TICRATE; if (player->kartstuff[k_hyudorotimer] > 0) @@ -4970,8 +5160,10 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->mo->eflags |= MFE_DRAWONLYFORP3; else if (player == &players[fourthdisplayplayer] && splitscreen > 2) player->mo->eflags |= MFE_DRAWONLYFORP4; - else + else if (player == &players[consoleplayer]) player->mo->eflags |= MFE_DRAWONLYFORP1; + else + player->mo->flags2 |= MF2_DONTDRAW; } else player->mo->eflags &= ~(MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4); @@ -5113,7 +5305,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_boostcharge] <= 36) { player->kartstuff[k_startboost] = 0; - K_DoSneaker(player, false); + K_DoSneaker(player, 0); player->kartstuff[k_sneakertimer] = 70; // PERFECT BOOST!! if (!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) // Let everyone hear this one @@ -5324,6 +5516,8 @@ void K_CheckSpectateStatus(void) UINT8 respawnlist[MAXPLAYERS]; UINT8 i, numingame = 0, numjoiners = 0; + if (!cv_allowteamchange.value) return; + // Get the number of players in game, and the players to be de-spectated. for (i = 0; i < MAXPLAYERS; i++) { @@ -5339,7 +5533,7 @@ void K_CheckSpectateStatus(void) return; if (numingame < 2 || leveltime < starttime || mapreset) // Allow if the match hasn't started yet continue; - if (leveltime > 20*TICRATE) // DON'T allow if the match is 20 seconds in + if (leveltime > (starttime + 20*TICRATE)) // DON'T allow if the match is 20 seconds in return; if (G_RaceGametype() && players[i].laps) // DON'T allow if the race is at 2 laps return; @@ -5389,19 +5583,16 @@ static patch_t *kp_karmasticker; static patch_t *kp_splitkarmabomb; static patch_t *kp_timeoutsticker; -static patch_t *kp_startcountdown[8]; -static patch_t *kp_racefinish[2]; +static patch_t *kp_startcountdown[16]; +static patch_t *kp_racefinish[6]; static patch_t *kp_positionnum[NUMPOSNUMS][NUMPOSFRAMES]; static patch_t *kp_winnernum[NUMPOSFRAMES]; -static patch_t *kp_facenull; -static patch_t *kp_facefirst; -static patch_t *kp_facesecond; -static patch_t *kp_facethird; -static patch_t *kp_facefourth; +static patch_t *kp_facenum[MAXPLAYERS+1]; static patch_t *kp_rankbumper; +static patch_t *kp_tinybumpera, *kp_tinybumperb; static patch_t *kp_ranknobumpers; static patch_t *kp_battlewin; @@ -5436,7 +5627,6 @@ static patch_t *kp_sadface[2]; static patch_t *kp_check[6]; -static patch_t *kp_spbwarning[2]; static patch_t *kp_eggnum[4]; static patch_t *kp_fpview[3]; @@ -5448,6 +5638,9 @@ static patch_t *kp_lapanim_lap[7]; static patch_t *kp_lapanim_final[11]; static patch_t *kp_lapanim_number[10][3]; static patch_t *kp_lapanim_emblem; +static patch_t *kp_lapanim_hand[3]; + +static patch_t *kp_yougotem; void K_LoadKartHUDGraphics(void) { @@ -5478,9 +5671,25 @@ void K_LoadKartHUDGraphics(void) kp_startcountdown[5] = W_CachePatchName("K_CNT2B", PU_HUDGFX); kp_startcountdown[6] = W_CachePatchName("K_CNT1B", PU_HUDGFX); kp_startcountdown[7] = W_CachePatchName("K_CNTGOB", PU_HUDGFX); + // Splitscreen + kp_startcountdown[8] = W_CachePatchName("K_SMC3A", PU_HUDGFX); + kp_startcountdown[9] = W_CachePatchName("K_SMC2A", PU_HUDGFX); + kp_startcountdown[10] = W_CachePatchName("K_SMC1A", PU_HUDGFX); + kp_startcountdown[11] = W_CachePatchName("K_SMCGOA", PU_HUDGFX); + kp_startcountdown[12] = W_CachePatchName("K_SMC3B", PU_HUDGFX); + kp_startcountdown[13] = W_CachePatchName("K_SMC2B", PU_HUDGFX); + kp_startcountdown[14] = W_CachePatchName("K_SMC1B", PU_HUDGFX); + kp_startcountdown[15] = W_CachePatchName("K_SMCGOB", PU_HUDGFX); + // Finish kp_racefinish[0] = W_CachePatchName("K_FINA", PU_HUDGFX); kp_racefinish[1] = W_CachePatchName("K_FINB", PU_HUDGFX); + // Splitscreen + kp_racefinish[2] = W_CachePatchName("K_SMFINA", PU_HUDGFX); + kp_racefinish[3] = W_CachePatchName("K_SMFINB", PU_HUDGFX); + // 2P splitscreen + kp_racefinish[4] = W_CachePatchName("K_2PFINA", PU_HUDGFX); + kp_racefinish[5] = W_CachePatchName("K_2PFINB", PU_HUDGFX); // Position numbers sprintf(buffer, "K_POSNxx"); @@ -5502,14 +5711,18 @@ void K_LoadKartHUDGraphics(void) kp_winnernum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); } - kp_facenull = W_CachePatchName("K_PFACE0", PU_HUDGFX); - kp_facefirst = W_CachePatchName("K_PFACE1", PU_HUDGFX); - kp_facesecond = W_CachePatchName("K_PFACE2", PU_HUDGFX); - kp_facethird = W_CachePatchName("K_PFACE3", PU_HUDGFX); - kp_facefourth = W_CachePatchName("K_PFACE4", PU_HUDGFX); + sprintf(buffer, "OPPRNKxx"); + for (i = 0; i <= MAXPLAYERS; i++) + { + buffer[6] = '0'+(i/10); + buffer[7] = '0'+(i%10); + kp_facenum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } // Extra ranking icons kp_rankbumper = W_CachePatchName("K_BLNICO", PU_HUDGFX); + kp_tinybumpera = W_CachePatchName("K_BLNA", PU_HUDGFX); + kp_tinybumperb = W_CachePatchName("K_BLNB", PU_HUDGFX); kp_ranknobumpers = W_CachePatchName("K_NOBLNS", PU_HUDGFX); // Battle graphics @@ -5593,10 +5806,6 @@ void K_LoadKartHUDGraphics(void) kp_check[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); } - // SPB warning - kp_spbwarning[0] = W_CachePatchName("K_SPBW1", PU_HUDGFX); - kp_spbwarning[1] = W_CachePatchName("K_SPBW2", PU_HUDGFX); - // Eggman warning numbers sprintf(buffer, "K_EGGNx"); for (i = 0; i < 4; i++) @@ -5655,6 +5864,15 @@ void K_LoadKartHUDGraphics(void) } kp_lapanim_emblem = (patch_t *) W_CachePatchName("K_LAPE00", PU_HUDGFX); + + sprintf(buffer, "K_LAPH0x"); + for (i = 0; i < 3; i++) + { + buffer[7] = '0'+(i+1); + kp_lapanim_hand[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + kp_yougotem = (patch_t *) W_CachePatchName("YOUGOTEM", PU_HUDGFX); } // For the item toggle menu @@ -5718,7 +5936,6 @@ INT32 FACE_X, FACE_Y; // Top-four Faces INT32 STCD_X, STCD_Y; // Starting countdown INT32 CHEK_Y; // CHECK graphic INT32 MINI_X, MINI_Y; // Minimap -INT32 SPBW_X, SPBW_Y; // SPB warning INT32 WANT_X, WANT_Y; // Battle WANTED poster static void K_initKartHUD(void) @@ -5784,9 +6001,6 @@ static void K_initKartHUD(void) // Minimap MINI_X = BASEVIDWIDTH - 50; // 270 MINI_Y = (BASEVIDHEIGHT/2)-16; // 84 - // Blue Shell warning - SPBW_X = BASEVIDWIDTH/2; // 270 - SPBW_Y = BASEVIDHEIGHT- 24; // 176 // Battle WANTED poster WANT_X = BASEVIDWIDTH - 55; // 270 WANT_Y = BASEVIDHEIGHT- 71; // 176 @@ -5804,8 +6018,6 @@ static void K_initKartHUD(void) MINI_Y = (BASEVIDHEIGHT/2); - SPBW_Y = (BASEVIDHEIGHT/2)-8; - WANT_X = BASEVIDWIDTH-8; WANT_Y = (BASEVIDHEIGHT/2)-12; @@ -5824,8 +6036,6 @@ static void K_initKartHUD(void) MINI_X = (3*BASEVIDWIDTH/4); MINI_Y = (3*BASEVIDHEIGHT/4); - SPBW_X = BASEVIDWIDTH/4; - WANT_X = (BASEVIDWIDTH/2)-8; if (splitscreen > 2) // 4P-only @@ -6023,9 +6233,10 @@ static void K_drawKartItem(void) // Extensible meter, currently only used for rocket sneaker... if (itembar && hudtrans) { - const INT32 barlength = (splitscreen > 1 ? 12 : 24); - const INT32 max = itemtime; // timer's normal highest value - const INT32 length = min(barlength, (itembar * barlength) / max); + const INT32 barlength = (splitscreen > 1 ? 12 : 26); + const INT32 maxl = (itemtime*3) - barlength; // timer's normal highest value + const INT32 fill = ((itembar*barlength)/maxl); + const INT32 length = min(barlength, fill); const INT32 height = (offset ? 1 : 2); const INT32 x = (offset ? 17 : 11), y = (offset ? 27 : 35); @@ -6179,7 +6390,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, bo } V_DrawRightAlignedString(workx, worky, splitflags, targettext); - workx -= 72; //69; -- good night sweet prince + workx -= 67; V_DrawSmallScaledPatch(workx + 4, worky, splitflags, W_CachePatchName("NEEDIT", PU_CACHE)); break; @@ -6192,7 +6403,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, bo splitflags = (splitflags &~ V_HUDTRANSHALF)|V_HUDTRANS; while (curemb--) { - workx -= 16; + workx -= 12; V_DrawSmallMappedPatch(workx + 4, worky, splitflags, emblempic[curemb], emblemcol[curemb]); } } @@ -6274,12 +6485,11 @@ static boolean K_drawKartPositionFaces(void) // FACE_Y = 72; // 72 INT32 Y = FACE_Y+9; // +9 to offset where it's being drawn if there are more than one - INT32 i, j, ranklines; + INT32 i, j, ranklines, strank = 0; boolean completed[MAXPLAYERS]; INT32 rankplayer[MAXPLAYERS]; INT32 bumperx, numplayersingame = 0; UINT8 *colormap; - patch_t *localpatch = kp_facenull; ranklines = 0; memset(completed, 0, sizeof (completed)); @@ -6300,32 +6510,62 @@ static boolean K_drawKartPositionFaces(void) for (j = 0; j < numplayersingame; j++) { + UINT8 lowestposition = MAXPLAYERS; for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && completed[i] == false && players[i].mo && !players[i].spectator - && (rankplayer[ranklines] < 0 || players[i].kartstuff[k_position] < players[rankplayer[ranklines]].kartstuff[k_position])) - { - rankplayer[ranklines] = i; - } + if (completed[i] || !playeringame[i] || players[i].spectator || !players[i].mo) + continue; + + if (players[i].kartstuff[k_position] >= lowestposition) + continue; + + rankplayer[ranklines] = i; + lowestposition = players[i].kartstuff[k_position]; } + i = rankplayer[ranklines]; completed[i] = true; - if (ranklines == 4) - break; // Only draw the top 4 players + if (players+i == stplyr) + strank = ranklines; + + //if (ranklines == 5) + //break; // Only draw the top 5 players -- we do this a different way now... ranklines++; } - Y -= (9*ranklines); + if (ranklines < 5) + Y -= (9*ranklines); + else + Y -= (9*5); - for (i = 0; i < ranklines; i++) + if (G_BattleGametype() || strank <= 2) // too close to the top, or playing battle? { - if (players[rankplayer[i]].spectator) continue; // Spectators are ignored + i = 0; + if (ranklines > 5) // could be both... + ranklines = 5; + } + else if (strank+3 > ranklines) // too close to the bottom? + { + i = ranklines - 5; + if (i < 0) + i = 0; + } + else + { + i = strank-2; + ranklines = strank+3; + } + + for (; i < ranklines; i++) + { + if (!playeringame[rankplayer[i]]) continue; + if (players[rankplayer[i]].spectator) continue; if (!players[rankplayer[i]].mo) continue; - bumperx = FACE_X+18; + bumperx = FACE_X+19; if (players[rankplayer[i]].mo->color) { @@ -6335,31 +6575,28 @@ static boolean K_drawKartPositionFaces(void) else colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE); - V_DrawSmallMappedPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, faceprefix[players[rankplayer[i]].skin], colormap); + V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, facerankprefix[players[rankplayer[i]].skin], colormap); if (G_BattleGametype() && players[rankplayer[i]].kartstuff[k_bumper] > 0) { - for (j = 0; j < players[rankplayer[i]].kartstuff[k_bumper]; j++) + V_DrawMappedPatch(bumperx-2, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumpera, colormap); + for (j = 1; j < players[rankplayer[i]].kartstuff[k_bumper]; j++) { - V_DrawSmallMappedPatch(bumperx, Y+10, V_HUDTRANS|V_SNAPTOLEFT, kp_rankbumper, colormap); - bumperx += 3; + bumperx += 5; + V_DrawMappedPatch(bumperx, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumperb, colormap); } } } - // Draws the little number over the face - switch (players[rankplayer[i]].kartstuff[k_position]) - { - case 1: localpatch = kp_facefirst; break; - case 2: localpatch = kp_facesecond; break; - case 3: localpatch = kp_facethird; break; - case 4: localpatch = kp_facefourth; break; - default: break; - } - if (G_BattleGametype() && players[rankplayer[i]].kartstuff[k_bumper] <= 0) - V_DrawSmallScaledPatch(FACE_X-2, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_ranknobumpers); + V_DrawScaledPatch(FACE_X-4, Y-3, V_HUDTRANS|V_SNAPTOLEFT, kp_ranknobumpers); else - V_DrawSmallScaledPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, localpatch); + { + INT32 pos = players[rankplayer[i]].kartstuff[k_position]; + if (pos < 0 || pos > MAXPLAYERS) + pos = 0; + // Draws the little number over the face + V_DrawScaledPatch(FACE_X-5, Y+10, V_HUDTRANS|V_SNAPTOLEFT, kp_facenum[pos]); + } Y += 18; } @@ -6367,6 +6604,103 @@ static boolean K_drawKartPositionFaces(void) return false; } +// +// HU_DrawTabRankings -- moved here to take advantage of kart stuff! +// +void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol) +{ + INT32 i, rightoffset = 240; + const UINT8 *colormap; + INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2; + + //this function is designed for 9 or less score lines only + //I_Assert(scorelines <= 9); -- not today bitch, kart fixed it up + + V_DrawFill(1-duptweak, 26, dupadjust-2, 1, 0); // Draw a horizontal line because it looks nice! + if (scorelines > 8) + { + V_DrawFill(160, 26, 1, 147, 0); // Draw a vertical line to separate the two sides. + V_DrawFill(1-duptweak, 173, dupadjust-2, 1, 0); // And a horizontal line near the bottom. + rightoffset = (BASEVIDWIDTH/2) - 4 - x; + } + + for (i = 0; i < scorelines; i++) + { + char strtime[MAXPLAYERNAME+1]; + + if (players[tab[i].num].spectator || !players[tab[i].num].mo) + continue; //ignore them. + + if (netgame // don't draw it offline + && tab[i].num != serverplayer) + HU_drawPing(x + ((i < 8) ? -19 : rightoffset + 13), y+2, playerpingtable[tab[i].num], false); + + if (scorelines > 8) + strlcpy(strtime, tab[i].name, 6); + else + STRBUFCPY(strtime, tab[i].name); + + V_DrawString(x + 20, y, + ((tab[i].num == whiteplayer) + ? hilicol|V_ALLOWLOWERCASE + : V_ALLOWLOWERCASE), + strtime); + + if (players[tab[i].num].mo->color) + { + colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); + if (players[tab[i].num].mo->colorized) + colormap = R_GetTranslationColormap(TC_RAINBOW, players[tab[i].num].mo->color, GTC_CACHE); + else + colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE); + + V_DrawMappedPatch(x, y-4, 0, facerankprefix[players[tab[i].num].skin], colormap); + /*if (G_BattleGametype() && players[tab[i].num].kartstuff[k_bumper] > 0) -- not enough space for this + { + INT32 bumperx = x+19; + V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumpera, colormap); + for (j = 1; j < players[tab[i].num].kartstuff[k_bumper]; j++) + { + bumperx += 5; + V_DrawMappedPatch(bumperx, y-4, 0, kp_tinybumperb, colormap); + } + }*/ + } + + if (G_BattleGametype() && players[tab[i].num].kartstuff[k_bumper] <= 0) + V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers); + else + { + INT32 pos = players[tab[i].num].kartstuff[k_position]; + if (pos < 0 || pos > MAXPLAYERS) + pos = 0; + // Draws the little number over the face + V_DrawScaledPatch(x-5, y+6, 0, kp_facenum[pos]); + } + + if (G_RaceGametype()) + { +#define timestring(time) va("%i'%02i\"%02i", G_TicsToMinutes(time, true), G_TicsToSeconds(time), G_TicsToCentiseconds(time)) + if (players[tab[i].num].exiting) + V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime)); + else if (players[tab[i].num].pflags & PF_TIMEOVER) + V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST."); + else if (circuitmap) + V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count)); +#undef timestring + } + else + V_DrawRightAlignedString(x+rightoffset, y, 0, va("%u", tab[i].count)); + + y += 18; + if (i == 7) + { + y = 33; + x = (BASEVIDWIDTH/2) + 4; + } + } +} + static void K_drawKartLaps(void) { INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT); @@ -6423,7 +6757,7 @@ static void K_drawKartBumpersOrKarma(void) if (stplyr->kartstuff[k_bumper] <= 0) { V_DrawMappedPatch(LAPS_X, LAPS_Y-1, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap); - V_DrawString(LAPS_X+13, LAPS_Y+1, V_HUDTRANS|splitflags, va("%d/3", stplyr->kartstuff[k_comebackpoints])); + V_DrawString(LAPS_X+13, LAPS_Y+1, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints])); } else { @@ -6436,7 +6770,7 @@ static void K_drawKartBumpersOrKarma(void) if (stplyr->kartstuff[k_bumper] <= 0) { V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_karmasticker, colormap); - V_DrawKartString(LAPS_X+59, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/3", stplyr->kartstuff[k_comebackpoints])); + V_DrawKartString(LAPS_X+59, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints])); } else { @@ -6449,23 +6783,6 @@ static void K_drawKartBumpersOrKarma(void) } } -static void K_drawSPBWarning(void) -{ - patch_t *localpatch = kp_nodraw; - INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM); - - if (!(stplyr->kartstuff[k_deathsentence] > 0 - || (spbincoming > 0 && spbincoming < 2*TICRATE && stplyr->kartstuff[k_position] == 1))) - return; - - if (leveltime % 8 > 3) - localpatch = kp_spbwarning[1]; - else - localpatch = kp_spbwarning[0]; - - V_DrawScaledPatch(SPBW_X, SPBW_Y, splitflags, localpatch); -} - fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fixed_t my) { fixed_t dist, x; @@ -6502,7 +6819,7 @@ static void K_drawKartWanted(void) if (splitscreen) // Can't fit the poster on screen, sadly { if (K_IsPlayerWanted(stplyr) && leveltime % 10 > 3) - V_DrawRightAlignedString(WANT_X, WANT_Y, K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS|V_REDMAP), "WANTED"); + V_DrawRightAlignedString(WANT_X, WANT_Y, K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS|V_ORANGEMAP), "WANTED"); return; } @@ -6522,7 +6839,7 @@ static void K_drawKartWanted(void) for (i = 0; i < numwanted; i++) { - INT32 x = WANT_X+7, y = WANT_Y+20; + INT32 x = WANT_X+8, y = WANT_Y+21; fixed_t scale = FRACUNIT/2; player_t *p = &players[battlewanted[i]]; @@ -6530,24 +6847,19 @@ static void K_drawKartWanted(void) break; if (numwanted == 1) - { - x++; //y++; scale = FRACUNIT; - } else { if (i & 1) - x += 18; + x += 16; if (i > 1) - y += 17; + y += 16; } - if (players[battlewanted[i]].skincolor == 0) - V_DrawFixedPatch(x<skin], NULL); - else + if (players[battlewanted[i]].skincolor) { colormap = R_GetTranslationColormap(TC_RAINBOW, p->skincolor, GTC_CACHE); - V_DrawFixedPatch(x<skin], colormap); + V_DrawFixedPatch(x<skin] : facerankprefix[p->skin]), colormap); } } } @@ -6602,35 +6914,6 @@ static void K_drawKartPlayerCheck(void) } } -void K_LoadIconGraphics(char *facestr, INT32 skinnum) -{ - char namelump[9]; - - // hack: make sure base face name is no more than 8 chars - if (strlen(facestr) > 8) - facestr[8] = '\0'; - strcpy(namelump, facestr); // copy base name - - iconprefix[skinnum] = W_CachePatchName(namelump, PU_HUDGFX); - iconfreed[skinnum] = false; -} - -#if 0 //unused -static void K_UnLoadIconGraphics(INT32 skinnum) -{ - Z_Free(iconprefix[skinnum]); - iconfreed[skinnum] = true; -} -#endif - -void K_ReloadSkinIconGraphics(void) -{ - INT32 i; - - for (i = 0; i < numskins; i++) - K_LoadIconGraphics(skins[i].iconprefix, i); -} - static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, patch_t *AutomapPic) { // amnum xpos & ypos are the icon's speed around the HUD. @@ -6697,18 +6980,18 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat if (encoremode) amnumxpos = -amnumxpos; - amxpos = amnumxpos + ((x + AutomapPic->width/2 - (iconprefix[skin]->width/2))<height/2 - (iconprefix[skin]->height/2))<width/2 - (facemmapprefix[skin]->width/2))<height/2 - (facemmapprefix[skin]->height/2))<width/2 + (iconprefix[skin]->width/2))<width/2 + (facemmapprefix[skin]->width/2))<color) // 'default' color - V_DrawSciencePatch(amxpos, amypos, flags, iconprefix[skin], FRACUNIT); + V_DrawSciencePatch(amxpos, amypos, flags, facemmapprefix[skin], FRACUNIT); else { UINT8 *colormap; @@ -6716,7 +6999,7 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat colormap = R_GetTranslationColormap(TC_RAINBOW, mo->color, 0); else colormap = R_GetTranslationColormap(skin, mo->color, 0); - V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, iconprefix[skin], colormap); + V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, facemmapprefix[skin], colormap); } } @@ -6841,11 +7124,10 @@ static void K_drawKartStartCountdown(void) pnum++; if ((leveltime % (2*5)) / 5) // blink pnum += 4; + if (splitscreen) // splitscreen + pnum += 8; - if (splitscreen) - V_DrawSmallScaledPatch(STCD_X - (SHORT(kp_startcountdown[pnum]->width)/4), STCD_Y - (SHORT(kp_startcountdown[pnum]->height)/4), splitflags, kp_startcountdown[pnum]); - else - V_DrawScaledPatch(STCD_X - (SHORT(kp_startcountdown[pnum]->width)/2), STCD_Y - (SHORT(kp_startcountdown[pnum]->height)/2), splitflags, kp_startcountdown[pnum]); + V_DrawScaledPatch(STCD_X - (SHORT(kp_startcountdown[pnum]->width)/2), STCD_Y - (SHORT(kp_startcountdown[pnum]->height)/2), splitflags, kp_startcountdown[pnum]); } static void K_drawKartFinish(void) @@ -6858,12 +7140,14 @@ static void K_drawKartFinish(void) if ((stplyr->kartstuff[k_cardanimation] % (2*5)) / 5) // blink pnum = 1; - if (splitscreen > 1) - { - V_DrawTinyScaledPatch(STCD_X - (SHORT(kp_racefinish[pnum]->width)/8), STCD_Y - (SHORT(kp_racefinish[pnum]->height)/8), splitflags, kp_racefinish[pnum]); - return; - } + if (splitscreen > 1) // small splitscreen + pnum += 2; + else if (splitscreen == 1) // wide splitscreen + pnum += 4; + if (splitscreen > 1) // Stationary FIN + V_DrawScaledPatch(STCD_X - (SHORT(kp_racefinish[pnum]->width)/2), STCD_Y - (SHORT(kp_racefinish[pnum]->height)/2), splitflags, kp_racefinish[pnum]); + else // Scrolling FINISH { INT32 scaleshift = (FRACBITS - splitscreen); // FRACUNIT or FRACUNIT/2 INT32 x = ((vid.width<width)<exiting) + { + if (stplyr == &players[secondarydisplayplayer]) + x = BASEVIDWIDTH-96; + else + x = 96; + } else - x = 96; + scale /= 2; } } @@ -6925,7 +7214,7 @@ static void K_drawBattleFullscreen(void) { if (stplyr->kartstuff[k_position] == 1) V_DrawFixedPatch(x<kartstuff[k_lapanimation]; + UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, 0); - V_DrawScaledPatch(BASEVIDWIDTH/2 + (32*max(0, stplyr->kartstuff[k_lapanimation]-76)), - 64 - (32*max(0, progress-76)), - 0, kp_lapanim_emblem); + V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->kartstuff[k_lapanimation]-76)))*FRACUNIT, + (48 - (32*max(0, progress-76)))*FRACUNIT, + FRACUNIT, V_HUDTRANS, + kp_lapanim_emblem, colormap); + + if (stplyr->kartstuff[k_laphand] >= 1 && stplyr->kartstuff[k_laphand] <= 3) + { + V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->kartstuff[k_lapanimation]-76)))*FRACUNIT, + (48 - (32*max(0, progress-76)) + + 4 - abs((leveltime % 8) - 4))*FRACUNIT, + FRACUNIT, V_HUDTRANS, + kp_lapanim_hand[stplyr->kartstuff[k_laphand]-1], NULL); + } if (stplyr->laps == (UINT8)(cv_numlaps.value - 1)) { - V_DrawScaledPatch(27 - (32*max(0, progress-76)), - 40, - 0, kp_lapanim_final[min(progress/2, 10)]); + V_DrawFixedPatch((62 - (32*max(0, progress-76)))*FRACUNIT, // 27 + (-6)*FRACUNIT, // 24 + FRACUNIT, V_HUDTRANS, + kp_lapanim_final[min(progress/2, 10)], NULL); if (progress/2-12 >= 0) { - V_DrawScaledPatch(194 + (32*max(0, progress-76)), - 40, - 0, kp_lapanim_lap[min(progress/2-12, 6)]); + V_DrawFixedPatch((188 + (32*max(0, progress-76)))*FRACUNIT, // 194 + (-6)*FRACUNIT, // 24 + FRACUNIT, V_HUDTRANS, + kp_lapanim_lap[min(progress/2-12, 6)], NULL); } } else { - V_DrawScaledPatch(61 - (32*max(0, progress-76)), - 40, - 0, kp_lapanim_lap[min(progress/2, 6)]); + V_DrawFixedPatch((82 - (32*max(0, progress-76)))*FRACUNIT, // 61 + (-6)*FRACUNIT, // 24 + FRACUNIT, V_HUDTRANS, + kp_lapanim_lap[min(progress/2, 6)], NULL); if (progress/2-8 >= 0) { - V_DrawScaledPatch(194 + (32*max(0, progress-76)), - 40, - 0, kp_lapanim_number[(((UINT32)stplyr->laps+1) / 10)][min(progress/2-8, 2)]); + V_DrawFixedPatch((188 + (32*max(0, progress-76)))*FRACUNIT, // 194 + (-6)*FRACUNIT, // 24 + FRACUNIT, V_HUDTRANS, + kp_lapanim_number[(((UINT32)stplyr->laps+1) / 10)][min(progress/2-8, 2)], NULL); if (progress/2-10 >= 0) { - V_DrawScaledPatch(221 + (32*max(0, progress-76)), - 40, - 0, kp_lapanim_number[(((UINT32)stplyr->laps+1) % 10)][min(progress/2-10, 2)]); + V_DrawFixedPatch((208 + (32*max(0, progress-76)))*FRACUNIT, // 221 + (-6)*FRACUNIT, // 24 + FRACUNIT, V_HUDTRANS, + kp_lapanim_number[(((UINT32)stplyr->laps+1) % 10)][min(progress/2-10, 2)], NULL); } } } @@ -7421,20 +7726,11 @@ void K_drawKartHUD(void) || ((splitscreen > 2 && stplyr == &players[fourthdisplayplayer]) && !camera4.chase)) K_drawKartFirstPerson(); - // Draw a white fade on level opening - if (leveltime < 15 && stplyr == &players[displayplayer]) - { - if (leveltime <= 5) - V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,120); // Pure white on first few frames, to hide SRB2's awful level load artifacts - else - V_DrawFadeScreen(120, 15-leveltime); // Then gradually fade out from there - } - if (splitscreen == 2) // Player 4 in 3P is the minimap :p K_drawKartMinimap(); // Draw full screen stuff that turns off the rest of the HUD - if (mapreset) + if (mapreset && stplyr == &players[displayplayer]) { K_drawChallengerScreen(); return; @@ -7504,9 +7800,6 @@ void K_drawKartHUD(void) // Draw the input UI K_drawInput(); } - - // You're about to DIEEEEE - K_drawSPBWarning(); } else if (G_BattleGametype()) // Battle-only { @@ -7541,6 +7834,9 @@ void K_drawKartHUD(void) K_drawLapStartAnim(); } + if (G_BattleGametype() && !splitscreen && (stplyr->kartstuff[k_yougotem] % 2)) // * YOU GOT EM * + V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem); + // Draw FREE PLAY. if (isfreeplay && !stplyr->spectator && timeinmap > 113) K_drawKartFreePlay(leveltime); @@ -7550,6 +7846,13 @@ void K_drawKartHUD(void) if (cv_kartdebugcheckpoint.value) K_drawCheckpointDebugger(); + + if (cv_kartdebugnodes.value) + { + UINT8 p; + for (p = 0; p < MAXPLAYERS; p++) + V_DrawString(8, 64+(8*p), V_YELLOWMAP, va("%d - %d", p, playernode[p])); + } } //} diff --git a/src/k_kart.h b/src/k_kart.h index 7cab42a5..67229330 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -21,14 +21,16 @@ void K_RegisterKartStuff(void); boolean K_IsPlayerLosing(player_t *player); boolean K_IsPlayerWanted(player_t *player); void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); +void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master); void K_RespawnChecker(player_t *player); void K_KartMoveAnimation(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); void K_KartPlayerAfterThink(player_t *player); void K_DoInstashield(player_t *player); +void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount); void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, boolean trapitem); void K_SquishPlayer(player_t *player, mobj_t *source); -void K_ExplodePlayer(player_t *player, mobj_t *source); +void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor); void K_StealBumper(player_t *player, player_t *victim, boolean force); 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); @@ -36,7 +38,7 @@ void K_SpawnBoostTrail(player_t *player); void K_SpawnSparkleTrail(mobj_t *mo); void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent); void K_DriftDustHandling(mobj_t *spawner); -void K_DoSneaker(player_t *player, boolean doPFlag); +void K_DoSneaker(player_t *player, INT32 type); void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound); void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); void K_UpdateHnextList(player_t *player, boolean clean); @@ -66,8 +68,6 @@ fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fixed_t my void K_drawKartHUD(void); void K_drawKartFreePlay(UINT32 flashtime); void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, boolean playing); -void K_LoadIconGraphics(char *facestr, INT32 skinnum); -void K_ReloadSkinIconGraphics(void); // ========================================================================= #endif // __K_KART__ diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 240db71c..05facf18 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -92,6 +92,7 @@ static int lib_print(lua_State *L) static int lib_chatprint(lua_State *L) { const char *str = luaL_checkstring(L, 1); // retrieve string + boolean sound = luaL_checkboolean(L, 2); // retrieve sound boolean int len; if (str == NULL) // error if we don't have a string! return luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("chatprint")); @@ -99,12 +100,7 @@ static int lib_chatprint(lua_State *L) if (len > 255) // string is too long!!! return luaL_error(L, "String exceeds the 255 characters limit of the chat buffer."); - HU_AddChatText(str); - - if OLDCHAT - CONS_Printf("%s\n", str); - else - CON_LogMessage(str); // save to log.txt + HU_AddChatText(str, sound); return 0; } @@ -115,6 +111,7 @@ static int lib_chatprintf(lua_State *L) int n = lua_gettop(L); /* number of arguments */ player_t *plr; const char *str; + boolean sound = luaL_checkboolean(L, 3); int len; if (n < 2) return luaL_error(L, "chatprintf requires at least two arguments: player and text."); @@ -132,12 +129,7 @@ static int lib_chatprintf(lua_State *L) if (len > 255) // string is too long!!! return luaL_error(L, "String exceeds the 255 characters limit of the chat buffer."); - HU_AddChatText(str); - - if OLDCHAT - CONS_Printf("%s\n", str); - else - CON_LogMessage(str); // save to log.txt + HU_AddChatText(str, sound); return 0; } @@ -2094,6 +2086,19 @@ static int lib_kKartBouncing(lua_State *L) return 0; } +static int lib_kMatchGenericExtraFlags(lua_State *L) +{ + mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *master = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + NOHUD + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + if (!master) + return LUA_ErrInvalid(L, "mobj_t"); + K_MatchGenericExtraFlags(mo, master); + return 0; +} + static int lib_kDoInstashield(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2104,6 +2109,20 @@ static int lib_kDoInstashield(lua_State *L) return 0; } +static int lib_kSpawnBattlePoints(lua_State *L) +{ + player_t *source = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + player_t *victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + UINT8 amount = (UINT8)luaL_checkinteger(L, 3); + NOHUD + if (!source) + return LUA_ErrInvalid(L, "player_t"); + if (!victim) + return LUA_ErrInvalid(L, "player_t"); + K_SpawnBattlePoints(source, victim, amount); + return 0; +} + static int lib_kSpinPlayer(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2136,12 +2155,15 @@ static int lib_kExplodePlayer(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); mobj_t *source = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ)); + mobj_t *inflictor = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); NOHUD if (!player) return LUA_ErrInvalid(L, "player_t"); if (!source) return LUA_ErrInvalid(L, "mobj_t"); - K_ExplodePlayer(player, source); + if (!inflictor) + return LUA_ErrInvalid(L, "mobj_t"); + K_ExplodePlayer(player, source, inflictor); return 0; } @@ -2222,11 +2244,11 @@ static int lib_kDriftDustHandling(lua_State *L) static int lib_kDoSneaker(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - boolean doPFlag = luaL_checkboolean(L, 2); + INT32 type = luaL_checkinteger(L, 2); NOHUD if (!player) return LUA_ErrInvalid(L, "player_t"); - K_DoSneaker(player, doPFlag); + K_DoSneaker(player, type); return 0; } @@ -2490,7 +2512,9 @@ static luaL_Reg lib[] = { {"K_IsPlayerLosing",lib_kIsPlayerLosing}, {"K_IsPlayerWanted",lib_kIsPlayerWanted}, {"K_KartBouncing",lib_kKartBouncing}, + {"K_MatchGenericExtraFlags",lib_kMatchGenericExtraFlags}, {"K_DoInstashield",lib_kDoInstashield}, + {"K_SpawnBattlePoints",lib_kSpawnBattlePoints}, {"K_SpinPlayer",lib_kSpinPlayer}, {"K_SquishPlayer",lib_kSquishPlayer}, {"K_ExplodePlayer",lib_kExplodePlayer}, diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index a267d998..7223e8db 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -27,9 +27,9 @@ enum skin { skin_flags, skin_realname, skin_hudname, - skin_charsel, - skin_face, - skin_superface, + skin_facerank, + skin_facewant, + skin_facemmap, skin_ability, skin_ability2, skin_thokitem, @@ -61,9 +61,9 @@ static const char *const skin_opt[] = { "flags", "realname", "hudname", - "charsel", - "face", - "superface", + "facerank", + "facewant", + "facemmap", "ability", "ability2", "thokitem", @@ -121,23 +121,23 @@ static int skin_get(lua_State *L) case skin_hudname: lua_pushstring(L, skin->hudname); break; - case skin_charsel: + case skin_facerank: for (i = 0; i < 8; i++) - if (!skin->charsel[i]) + if (!skin->facerank[i]) break; - lua_pushlstring(L, skin->charsel, i); + lua_pushlstring(L, skin->facerank, i); break; - case skin_face: + case skin_facewant: for (i = 0; i < 8; i++) - if (!skin->face[i]) + if (!skin->facewant[i]) break; - lua_pushlstring(L, skin->face, i); + lua_pushlstring(L, skin->facewant, i); break; - case skin_superface: + case skin_facemmap: for (i = 0; i < 8; i++) - if (!skin->superface[i]) + if (!skin->facemmap[i]) break; - lua_pushlstring(L, skin->superface, i); + lua_pushlstring(L, skin->facemmap, i); break; case skin_ability: lua_pushinteger(L, skin->ability); diff --git a/src/m_cond.c b/src/m_cond.c index 80b86331..3e2baa1f 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -33,64 +33,64 @@ conditionset_t conditionSets[MAXCONDITIONSETS]; emblem_t emblemlocations[MAXEMBLEMS] = { // SILVER TIME TROPHIES - {ET_TIME, 0,0,0, 1, 'T', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // Green Hills Zone - Time: 1:30 - {ET_TIME, 0,0,0, 2, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Pipe Speedway Zone - Time: 1:50 - {ET_TIME, 0,0,0, 3, 'T', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Dark Race - 2:15 - {ET_TIME, 0,0,0, 4, 'T', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // Darkvile Garden Zone - 1:45 - {ET_TIME, 0,0,0, 5, 'T', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Northern District Zone - 2:20 - {ET_TIME, 0,0,0, 6, 'T', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Sonic Speedway Zone - 2:00 - {ET_TIME, 0,0,0, 7, 'T', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Egg Zeppelin Zone - 2:00 - {ET_TIME, 0,0,0, 8, 'T', SKINCOLOR_GREY, 95*TICRATE, "", 0}, // Hill Top Zone - 1:35 - {ET_TIME, 0,0,0, 9, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Sunbeam Paradise Zone - 1:50 - {ET_TIME, 0,0,0, 10, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Diamond Square Zone - 1:50 - {ET_TIME, 0,0,0, 11, 'T', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Misty Maze Zone - 2:30 - {ET_TIME, 0,0,0, 12, 'T', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Midnight Meadow Zone - 2:00 - {ET_TIME, 0,0,0, 13, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Megablock Castle Zone - 2:10 - {ET_TIME, 0,0,0, 14, 'T', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Sub-Zero Peak Zone - 2:30 - {ET_TIME, 0,0,0, 15, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Sapphire Coast Zone - 1:50 - {ET_TIME, 0,0,0, 16, 'T', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Silvercloud Island Zone - 2:20 - {ET_TIME, 0,0,0, 17, 'T', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Petroleum Refinery Zone - 2:15 - {ET_TIME, 0,0,0, 18, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Canyon Rush Zone - 2:10 - {ET_TIME, 0,0,0, 19, 'T', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Blue Mountain Zone - 2:40 - {ET_TIME, 0,0,0, 20, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Casino Resort Zone - 1:50 - {ET_TIME, 0,0,0, 21, 'T', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // Desert Palace Zone - 1:45 - {ET_TIME, 0,0,0, 22, 'T', SKINCOLOR_GREY, 165*TICRATE, "", 0}, // Red Barrage Area - 2:45 - {ET_TIME, 0,0,0, 23, 'T', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // Vanilla Hotel Zone - 1:45 - {ET_TIME, 0,0,0, 24, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Twinkle Cart - 1:50 - {ET_TIME, 0,0,0, 25, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Pleasure Castle - 1:50 - {ET_TIME, 0,0,0, 26, 'T', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Aurora Atoll Zone - 2:20 - {ET_TIME, 0,0,0, 27, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Barren Badlands Zone - 2:10 - {ET_TIME, 0,0,0, 28, 'T', SKINCOLOR_GREY, 155*TICRATE, "", 0}, // Toxic Palace Zone - 2:35 - {ET_TIME, 0,0,0, 29, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Ancient Tomb Zone - 2:10 - {ET_TIME, 0,0,0, 30, 'T', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Cloud Cradle Zone K - 2:00 - {ET_TIME, 0,0,0, 31, 'T', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Kodachrome Void Zone - 1:50 - {ET_TIME, 0,0,0, 32, 'T', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Egg Quarters - 2:20 - {ET_TIME, 0,0,0, 33, 'T', SKINCOLOR_GREY, 115*TICRATE, "", 0}, // Boiling Bedrock Zone - 1:55 - {ET_TIME, 0,0,0, 34, 'T', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Virtual Highway Zone - 2:20 - {ET_TIME, 0,0,0, 35, 'T', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Eggman's Nightclub Zone - 2:00 - {ET_TIME, 0,0,0, 36, 'T', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // KKR Ganbare Dochu 2 - 1:30 - {ET_TIME, 0,0,0, 37, 'T', SKINCOLOR_GREY, 80*TICRATE, "", 0}, // CK Chao Circuit 1 - 1:20 - {ET_TIME, 0,0,0, 38, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // CK Chao Circuit 2 - 2:10 - {ET_TIME, 0,0,0, 39, 'T', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // CK Cloud Tops 2 - 1:40 - {ET_TIME, 0,0,0, 40, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // CK Regal Raceway - 2:10 - {ET_TIME, 0,0,0, 41, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // SM Dimension Heist - 2:10 - {ET_TIME, 0,0,0, 42, 'T', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // SRB2 Frozen Night - 1:40 - {ET_TIME, 0,0,0, 43, 'T', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // MKSC Sky Garden - 1:40 - {ET_TIME, 0,0,0, 44, 'T', SKINCOLOR_GREY, 95*TICRATE, "", 0}, // MKDS Peach Gardens - 1:35 - {ET_TIME, 0,0,0, 45, 'T', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // MKSC Rainbow Road - 1:45 - {ET_TIME, 0,0,0, 46, 'T', SKINCOLOR_GREY, 70*TICRATE, "", 0}, // SMK Mario Circuit 1 - 1:10 - {ET_TIME, 0,0,0, 47, 'T', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // SMK Donut Plains 1 - 1:30 - {ET_TIME, 0,0,0, 48, 'T', SKINCOLOR_GREY, 75*TICRATE, "", 0}, // SMK Ghost Valley 2 - 1:15 - {ET_TIME, 0,0,0, 49, 'T', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // SMK Mario Circuit 3 - 1:45 - {ET_TIME, 0,0,0, 50, 'T', SKINCOLOR_GREY, 130*TICRATE, "", 0} // SMK Rainbow Road - 2:10 + {ET_TIME, 0,0,0, 1, 'B', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // Green Hills Zone - Time: 1:30 + {ET_TIME, 0,0,0, 2, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Pipe Speedway Zone - Time: 1:50 + {ET_TIME, 0,0,0, 3, 'B', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Dark Race - 2:15 + {ET_TIME, 0,0,0, 4, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // Darkvile Garden Zone - 1:45 + {ET_TIME, 0,0,0, 5, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Northern District Zone - 2:20 + {ET_TIME, 0,0,0, 6, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Sonic Speedway Zone - 2:00 + {ET_TIME, 0,0,0, 7, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Egg Zeppelin Zone - 2:00 + {ET_TIME, 0,0,0, 8, 'B', SKINCOLOR_GREY, 95*TICRATE, "", 0}, // Hill Top Zone - 1:35 + {ET_TIME, 0,0,0, 9, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Sunbeam Paradise Zone - 1:50 + {ET_TIME, 0,0,0, 10, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Diamond Square Zone - 1:50 + {ET_TIME, 0,0,0, 11, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Misty Maze Zone - 2:30 + {ET_TIME, 0,0,0, 12, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Midnight Meadow Zone - 2:00 + {ET_TIME, 0,0,0, 13, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Megablock Castle Zone - 2:10 + {ET_TIME, 0,0,0, 14, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Sub-Zero Peak Zone - 2:30 + {ET_TIME, 0,0,0, 15, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Sapphire Coast Zone - 1:50 + {ET_TIME, 0,0,0, 16, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Silvercloud Island Zone - 2:20 + {ET_TIME, 0,0,0, 17, 'B', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Petroleum Refinery Zone - 2:15 + {ET_TIME, 0,0,0, 18, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Canyon Rush Zone - 2:10 + {ET_TIME, 0,0,0, 19, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Blue Mountain Zone - 2:40 + {ET_TIME, 0,0,0, 20, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Casino Resort Zone - 1:50 + {ET_TIME, 0,0,0, 21, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // Desert Palace Zone - 1:45 + {ET_TIME, 0,0,0, 22, 'B', SKINCOLOR_GREY, 165*TICRATE, "", 0}, // Red Barrage Area - 2:45 + {ET_TIME, 0,0,0, 23, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // Vanilla Hotel Zone - 1:45 + {ET_TIME, 0,0,0, 24, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Twinkle Cart - 1:50 + {ET_TIME, 0,0,0, 25, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Pleasure Castle - 1:50 + {ET_TIME, 0,0,0, 26, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Aurora Atoll Zone - 2:20 + {ET_TIME, 0,0,0, 27, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Barren Badlands Zone - 2:10 + {ET_TIME, 0,0,0, 28, 'B', SKINCOLOR_GREY, 155*TICRATE, "", 0}, // Toxic Palace Zone - 2:35 + {ET_TIME, 0,0,0, 29, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Ancient Tomb Zone - 2:10 + {ET_TIME, 0,0,0, 30, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Cloud Cradle Zone K - 2:00 + {ET_TIME, 0,0,0, 31, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Kodachrome Void Zone - 1:50 + {ET_TIME, 0,0,0, 32, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Egg Quarters - 2:20 + {ET_TIME, 0,0,0, 33, 'B', SKINCOLOR_GREY, 115*TICRATE, "", 0}, // Boiling Bedrock Zone - 1:55 + {ET_TIME, 0,0,0, 34, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Virtual Highway Zone - 2:20 + {ET_TIME, 0,0,0, 35, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Eggman's Nightclub Zone - 2:00 + {ET_TIME, 0,0,0, 36, 'B', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // KKR Ganbare Dochu 2 - 1:30 + {ET_TIME, 0,0,0, 37, 'B', SKINCOLOR_GREY, 80*TICRATE, "", 0}, // CK Chao Circuit 1 - 1:20 + {ET_TIME, 0,0,0, 38, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // CK Chao Circuit 2 - 2:10 + {ET_TIME, 0,0,0, 39, 'B', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // CK Cloud Tops 2 - 1:40 + {ET_TIME, 0,0,0, 40, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // CK Regal Raceway - 2:10 + {ET_TIME, 0,0,0, 41, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // SM Dimension Heist - 2:10 + {ET_TIME, 0,0,0, 42, 'B', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // SRB2 Frozen Night - 1:40 + {ET_TIME, 0,0,0, 43, 'B', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // MKSC Sky Garden - 1:40 + {ET_TIME, 0,0,0, 44, 'B', SKINCOLOR_GREY, 95*TICRATE, "", 0}, // MKDS Peach Gardens - 1:35 + {ET_TIME, 0,0,0, 45, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // MKSC Rainbow Road - 1:45 + {ET_TIME, 0,0,0, 46, 'B', SKINCOLOR_GREY, 70*TICRATE, "", 0}, // SMK Mario Circuit 1 - 1:10 + {ET_TIME, 0,0,0, 47, 'B', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // SMK Donut Plains 1 - 1:30 + {ET_TIME, 0,0,0, 48, 'B', SKINCOLOR_GREY, 75*TICRATE, "", 0}, // SMK Ghost Valley 2 - 1:15 + {ET_TIME, 0,0,0, 49, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // SMK Mario Circuit 3 - 1:45 + {ET_TIME, 0,0,0, 50, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0} // SMK Rainbow Road - 2:10 // GOLD DEV TIME TROPHIES - // ...none yet! + // ...none yet! uses 'A' }; // Default Extra Emblems extraemblem_t extraemblems[MAXEXTRAEMBLEMS] = { - {"Experienced Driver", "Play 100 Matches", 10, 'X', SKINCOLOR_BLUE, 0}, + {"Experienced Driver", "Play 100 Matches", 10, 'C', SKINCOLOR_RED, 0}, }; // Default Unlockables @@ -101,10 +101,11 @@ unlockable_t unlockables[MAXUNLOCKABLES] = /* 02 */ {"SMK Cup", "", -1, 2, SECRET_NONE, 0, false, false, 0}, /* 03 */ {"Chao Cup", "", -1, 3, SECRET_NONE, 0, false, false, 0}, - /* 04 */ {"Encore Mode", "", 3, 4, SECRET_ENCORE, 0, false, false, 0}, - /* 05 */ {"Hell Attack", "", 5, 5, SECRET_HELLATTACK, 0, false, false, 0}, + /* 04 */ {"Hard Game Speed", "", -1, 4, SECRET_HARDSPEED, 0, false, false, 0}, + /* 05 */ {"Encore Mode", "", 4, 5, SECRET_ENCORE, 0, false, false, 0}, + /* 06 */ {"Hell Attack", "", 6, 6, SECRET_HELLATTACK, 0, false, false, 0}, - /* 06 */ {"Record Attack", "", -1, -1, SECRET_RECORDATTACK, 0, true, true, 0}, + /* 07 */ {"Record Attack", "", -1, -1, SECRET_RECORDATTACK, 0, true, true, 0}, }; // Default number of emblems and extra emblems @@ -120,23 +121,27 @@ void M_SetupDefaultConditionSets(void) M_AddRawCondition(1, 1, UC_TOTALEMBLEMS, 5, 0, 0); M_AddRawCondition(1, 2, UC_MATCHESPLAYED, 10, 0, 0); - // -- 2: Collect 15 emblems OR play 25 matches - M_AddRawCondition(2, 1, UC_TOTALEMBLEMS, 15, 0, 0); + // -- 2: Collect 10 emblems OR play 25 matches + M_AddRawCondition(2, 1, UC_TOTALEMBLEMS, 10, 0, 0); M_AddRawCondition(2, 2, UC_MATCHESPLAYED, 25, 0, 0); - // -- 3: Collect 30 emblems OR play 50 matches - M_AddRawCondition(3, 1, UC_TOTALEMBLEMS, 30, 0, 0); + // -- 3: Collect 20 emblems OR play 50 matches + M_AddRawCondition(3, 1, UC_TOTALEMBLEMS, 20, 0, 0); M_AddRawCondition(3, 2, UC_MATCHESPLAYED, 50, 0, 0); - // -- 4: Collect 40 emblems OR play 150 matches - M_AddRawCondition(4, 1, UC_TOTALEMBLEMS, 40, 0, 0); - M_AddRawCondition(4, 2, UC_MATCHESPLAYED, 150, 0, 0); + // -- 4: Collect 30 emblems OR play 100 matches + M_AddRawCondition(4, 1, UC_TOTALEMBLEMS, 30, 0, 0); + M_AddRawCondition(4, 2, UC_MATCHESPLAYED, 100, 0, 0); - // -- 5: Collect 50 emblems ONLY - M_AddRawCondition(5, 1, UC_TOTALEMBLEMS, 50, 0, 0); + // -- 5: Collect 40 emblems OR play 150 matches + M_AddRawCondition(5, 1, UC_TOTALEMBLEMS, 40, 0, 0); + M_AddRawCondition(5, 2, UC_MATCHESPLAYED, 150, 0, 0); - // -- 10: Play 100 matches - M_AddRawCondition(10, 1, UC_MATCHESPLAYED, 100, 0, 0); + // -- 6: Collect 50 emblems ONLY + M_AddRawCondition(6, 1, UC_TOTALEMBLEMS, 50, 0, 0); + + // -- 10: Play 300 matches + M_AddRawCondition(10, 1, UC_MATCHESPLAYED, 300, 0, 0); } void M_AddRawCondition(UINT8 set, UINT8 id, conditiontype_t c, INT32 r, INT16 x1, INT16 x2) diff --git a/src/m_cond.h b/src/m_cond.h index 81b6803c..f48e6fbe 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -113,7 +113,7 @@ typedef struct } unlockable_t; // I have NO idea why these are going negative, but whatever. -#define SECRET_NONE -6 // Does nil. Use with levels locked by UnlockRequired +#define SECRET_NONE -6 // Does nil. Use with levels locked by UnlockRequired #define SECRET_ITEMFINDER -5 // Enables Item Finder/Emblem Radar #define SECRET_EMBLEMHINTS -4 // Enables Emblem Hints #define SECRET_PANDORA -3 // Enables Pandora's Box @@ -124,8 +124,9 @@ typedef struct #define SECRET_WARP 2 // Selectable warp #define SECRET_SOUNDTEST 3 // Sound Test #define SECRET_CREDITS 4 // Enables Credits -#define SECRET_ENCORE 5 // Enables Encore mode cvar -#define SECRET_HELLATTACK 6 // Map Hell in record attack +#define SECRET_ENCORE 5 // Enables Encore mode cvar +#define SECRET_HELLATTACK 6 // Map Hell in record attack +#define SECRET_HARDSPEED 7 // Enables Hard gamespeed // If you have more secrets than these variables allow in your game, // you seriously need to get a life. diff --git a/src/m_menu.c b/src/m_menu.c index 2f848a2a..9c6635e1 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -151,8 +151,8 @@ description_t description[32] = {"???", "", ""}, {"???", "", ""} }; -static char *char_notes = NULL; -static fixed_t char_scroll = 0; +//static char *char_notes = NULL; +//static fixed_t char_scroll = 0; boolean menuactive = false; boolean fromlevelselect = false; @@ -173,7 +173,7 @@ static char joystickInfo[8][25]; static UINT32 serverlistpage; #endif -static saveinfo_t savegameinfo[MAXSAVEGAMES]; // Extra info about the save games. +//static saveinfo_t savegameinfo[MAXSAVEGAMES]; // Extra info about the save games. INT16 startmap; // Mario, NiGHTS, or just a plain old normal game? @@ -219,10 +219,10 @@ menu_t SPauseDef; //static void M_CustomLevelSelect(INT32 choice); //static void M_CustomWarp(INT32 choice); FUNCNORETURN static ATTRNORETURN void M_UltimateCheat(INT32 choice); -static void M_LoadGameLevelSelect(INT32 choice); +//static void M_LoadGameLevelSelect(INT32 choice); static void M_GetAllEmeralds(INT32 choice); static void M_DestroyRobots(INT32 choice); -static void M_LevelSelectWarp(INT32 choice); +//static void M_LevelSelectWarp(INT32 choice); static void M_Credits(INT32 choice); static void M_PandorasBox(INT32 choice); static void M_EmblemHints(INT32 choice); @@ -242,11 +242,12 @@ static void M_ConfirmSpectate(INT32 choice); static void M_ConfirmEnterGame(INT32 choice); static void M_ConfirmTeamScramble(INT32 choice); static void M_ConfirmTeamChange(INT32 choice); +static void M_ConfirmSpectateChange(INT32 choice); //static void M_SecretsMenu(INT32 choice); -static void M_SetupChoosePlayer(INT32 choice); +//static void M_SetupChoosePlayer(INT32 choice); static void M_QuitSRB2(INT32 choice); menu_t SP_MainDef, MP_MainDef, OP_MainDef; -menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; +menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef, MISC_ChangeSpectateDef; // Single Player //static void M_LoadGame(INT32 choice); @@ -261,7 +262,7 @@ static void M_ChooseTimeAttack(INT32 choice); static void M_ModeAttackRetry(INT32 choice); static void M_ModeAttackEndGame(INT32 choice); static void M_SetGuestReplay(INT32 choice); -static void M_ChoosePlayer(INT32 choice); +//static void M_ChoosePlayer(INT32 choice); menu_t SP_LevelStatsDef; static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; //static menu_t SP_NightsAttackDef, SP_NightsReplayDef, SP_NightsGuestReplayDef, SP_NightsGhostDef; @@ -271,7 +272,7 @@ static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef; static void M_StartServerMenu(INT32 choice); static void M_ConnectMenu(INT32 choice); #endif -static void M_StartSplitServerMenu(INT32 choice); +static void M_StartOfflineServerMenu(INT32 choice); static void M_StartServer(INT32 choice); #ifndef NONET static void M_Refresh(INT32 choice); @@ -280,33 +281,27 @@ static void M_ChooseRoom(INT32 choice); #endif static void M_SetupMultiPlayer(INT32 choice); static void M_SetupMultiPlayer2(INT32 choice); -#ifndef NOFOURPLAYER static void M_SetupMultiPlayer3(INT32 choice); static void M_SetupMultiPlayer4(INT32 choice); -#endif +static void M_SetupMultiHandler(INT32 choice); // Options // Split into multiple parts due to size // Controls menu_t OP_ControlsDef, OP_AllControlsDef; menu_t OP_MouseOptionsDef, OP_Mouse2OptionsDef; -menu_t OP_Joystick1Def, OP_Joystick2Def; -#ifndef NOFOURPLAYER -menu_t OP_Joystick3Def, OP_Joystick4Def; -#endif +menu_t OP_Joystick1Def, OP_Joystick2Def, OP_Joystick3Def, OP_Joystick4Def; static void M_VideoModeMenu(INT32 choice); static void M_Setup1PControlsMenu(INT32 choice); static void M_Setup2PControlsMenu(INT32 choice); -#ifndef NOFOURPLAYER static void M_Setup3PControlsMenu(INT32 choice); static void M_Setup4PControlsMenu(INT32 choice); -#endif + static void M_Setup1PJoystickMenu(INT32 choice); static void M_Setup2PJoystickMenu(INT32 choice); -#ifndef NOFOURPLAYER static void M_Setup3PJoystickMenu(INT32 choice); static void M_Setup4PJoystickMenu(INT32 choice); -#endif + static void M_AssignJoystick(INT32 choice); static void M_ChangeControl(INT32 choice); @@ -319,7 +314,7 @@ menu_t OP_SoundOptionsDef; static void M_ToggleSFX(INT32 choice); static void M_ToggleDigital(INT32 choice); //static void M_ToggleMIDI(INT32 choice); -static void M_RestartAudio(void); +//static void M_RestartAudio(void); //Misc menu_t /*OP_DataOptionsDef,*/ OP_ScreenshotOptionsDef, OP_EraseDataDef; @@ -347,11 +342,11 @@ static void M_DrawPauseMenu(void); static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade); static void M_DrawServerMenu(void); static void M_DrawImageDef(void); -static void M_DrawLoad(void); +//static void M_DrawLoad(void); static void M_DrawLevelStats(void); static void M_DrawTimeAttackMenu(void); //static void M_DrawNightsAttackMenu(void); -static void M_DrawSetupChoosePlayerMenu(void); +//static void M_DrawSetupChoosePlayerMenu(void); static void M_DrawControl(void); static void M_DrawVideoMenu(void); static void M_DrawHUDOptions(void); @@ -361,9 +356,9 @@ static void M_DrawMonitorToggles(void); static void M_OGL_DrawFogMenu(void); static void M_OGL_DrawColorMenu(void); #endif +static void M_DrawMPMainMenu(void); #ifndef NONET static void M_DrawConnectMenu(void); -static void M_DrawMPMainMenu(void); static void M_DrawRoomMenu(void); #endif static void M_DrawJoystick(void); @@ -378,7 +373,7 @@ static boolean M_QuitMultiPlayerMenu(void); static void M_HandleAddons(INT32 choice); static void M_HandleSoundTest(INT32 choice); static void M_HandleImageDef(INT32 choice); -static void M_HandleLoadSave(INT32 choice); +//static void M_HandleLoadSave(INT32 choice); static void M_HandleLevelStats(INT32 choice); #ifndef NONET static void M_HandleConnectIP(INT32 choice); @@ -393,6 +388,7 @@ static void M_HandleMonitorToggles(INT32 choice); // Consvar onchange functions static void Nextmap_OnChange(void); static void Newgametype_OnChange(void); +static void Dummymenuplayer_OnChange(void); //static void Dummymares_OnChange(void); static void Dummystaff_OnChange(void); @@ -460,13 +456,13 @@ consvar_t cv_ghost_staff = {"ghost_staff", "Show", CV_SAVE, ghost2_cons_ //Console variables used solely in the menu system. //todo: add a way to use non-console variables in the menu // or make these consvars legitimate like color or skin. -#ifndef NOFOURPLAYER -static void Dummysplitplayers_OnChange(void); -static CV_PossibleValue_t dummysplitplayers_cons_t[] = {{2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; -static consvar_t cv_dummysplitplayers = {"dummysplitplayers", "Two", CV_HIDEN|CV_CALL, dummysplitplayers_cons_t, Dummysplitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; -#endif +static void Splitplayers_OnChange(void); +CV_PossibleValue_t splitplayers_cons_t[] = {{1, "One"}, {2, "Two"}, {3, "Three"}, {4, "Four"}, {0, NULL}}; +consvar_t cv_splitplayers = {"splitplayers", "One", CV_CALL, splitplayers_cons_t, Splitplayers_OnChange, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t dummymenuplayer_cons_t[] = {{0, "NOPE"}, {1, "P1"}, {2, "P2"}, {3, "P3"}, {4, "P4"}, {0, NULL}}; static CV_PossibleValue_t dummyteam_cons_t[] = {{0, "Spectator"}, {1, "Red"}, {2, "Blue"}, {0, NULL}}; +static CV_PossibleValue_t dummyspectate_cons_t[] = {{0, "Spectator"}, {1, "Playing"}, {0, NULL}}; static CV_PossibleValue_t dummyscramble_cons_t[] = {{0, "Random"}, {1, "Points"}, {0, NULL}}; static CV_PossibleValue_t ringlimit_cons_t[] = {{0, "MIN"}, {9999, "MAX"}, {0, NULL}}; static CV_PossibleValue_t liveslimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NULL}}; @@ -475,7 +471,9 @@ static CV_PossibleValue_t liveslimit_cons_t[] = {{0, "MIN"}, {99, "MAX"}, {0, NU };*/ static CV_PossibleValue_t dummystaff_cons_t[] = {{0, "MIN"}, {100, "MAX"}, {0, NULL}}; +static consvar_t cv_dummymenuplayer = {"dummymenuplayer", "P1", CV_HIDEN|CV_CALL, dummymenuplayer_cons_t, Dummymenuplayer_OnChange, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummyteam = {"dummyteam", "Spectator", CV_HIDEN, dummyteam_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static consvar_t cv_dummyspectate = {"dummyspectate", "Spectator", CV_HIDEN, dummyspectate_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummyscramble = {"dummyscramble", "Random", CV_HIDEN, dummyscramble_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummyrings = {"dummyrings", "0", CV_HIDEN, ringlimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static consvar_t cv_dummylives = {"dummylives", "0", CV_HIDEN, liveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -499,12 +497,7 @@ static menuitem_t MainMenu[] = { {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_UnlockChecklistDef, 76}, {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, -#ifdef NONET -M_StartSplitServerMenu - {IT_CALL |IT_STRING, NULL, "Splitscreen", M_StartSplitServerMenu, 92}, -#else {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, -#endif {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108}, {IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116}, @@ -554,15 +547,14 @@ static menuitem_t MPauseMenu[] = {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,40}, {IT_CALL | IT_STRING, NULL, "P1 Setup...", M_SetupMultiPlayer, 48}, // splitscreen {IT_CALL | IT_STRING, NULL, "P2 Setup...", M_SetupMultiPlayer2, 56}, // splitscreen -#ifndef NOFOURPLAYER {IT_CALL | IT_STRING, NULL, "P3 Setup...", M_SetupMultiPlayer3, 64}, // splitscreen {IT_CALL | IT_STRING, NULL, "P4 Setup...", M_SetupMultiPlayer4, 72}, // splitscreen -#endif - {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, - {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, - {IT_STRING | IT_CALL, NULL, "Cancel Join", M_ConfirmSpectate, 48}, + {IT_STRING | IT_CALL, NULL, "Spectate", M_ConfirmSpectate, 48}, // alone + {IT_STRING | IT_CALL, NULL, "Enter Game", M_ConfirmEnterGame, 48}, // alone + {IT_STRING | IT_CALL, NULL, "Cancel Join", M_ConfirmSpectate, 48}, // alone {IT_STRING | IT_SUBMENU, NULL, "Switch Team...", &MISC_ChangeTeamDef, 48}, + {IT_STRING | IT_SUBMENU, NULL, "Enter/Spectate...", &MISC_ChangeSpectateDef,48}, {IT_CALL | IT_STRING, NULL, "Player Setup...", M_SetupMultiPlayer, 56}, // alone {IT_CALL | IT_STRING, NULL, "Options", M_Options, 64}, @@ -579,14 +571,14 @@ typedef enum mpause_continue, mpause_psetupsplit, mpause_psetupsplit2, -#ifndef NOFOURPLAYER mpause_psetupsplit3, mpause_psetupsplit4, -#endif + mpause_spectate, mpause_entergame, mpause_canceljoin, mpause_switchteam, + mpause_switchspectate, mpause_psetup, mpause_options, @@ -602,7 +594,7 @@ static menuitem_t SPauseMenu[] = // Pandora's Box will be shifted up if both options are available {IT_CALL | IT_STRING, NULL, "Pandora's Box...", M_PandorasBox, 16}, {IT_CALL | IT_STRING, NULL, "Emblem Hints...", M_EmblemHints, 24}, - {IT_CALL | IT_STRING, NULL, "Level Select...", M_LoadGameLevelSelect, 32}, + //{IT_CALL | IT_STRING, NULL, "Level Select...", M_LoadGameLevelSelect, 32}, {IT_CALL | IT_STRING, NULL, "Continue", M_SelectableClearMenus,48}, {IT_CALL | IT_STRING, NULL, "Retry", M_Retry, 56}, @@ -616,7 +608,7 @@ typedef enum { spause_pandora = 0, spause_hints, - spause_levelselect, + //spause_levelselect, spause_continue, spause_retry, @@ -637,10 +629,18 @@ static menuitem_t MISC_ScrambleTeamMenu[] = static menuitem_t MISC_ChangeTeamMenu[] = { - {IT_STRING|IT_CVAR, NULL, "Select Team", &cv_dummyteam, 30}, + {IT_STRING|IT_CVAR, NULL, "Player", &cv_dummymenuplayer, 30}, + {IT_STRING|IT_CVAR, NULL, "Team", &cv_dummyteam, 40}, {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmTeamChange, 90}, }; +static menuitem_t MISC_ChangeSpectateMenu[] = +{ + {IT_STRING|IT_CVAR, NULL, "Player", &cv_dummymenuplayer, 30}, + {IT_STRING|IT_CVAR, NULL, "Status", &cv_dummyspectate, 40}, + {IT_WHITESTRING|IT_CALL, NULL, "Confirm", M_ConfirmSpectateChange, 90}, +}; + static menuitem_t MISC_ChangeLevelMenu[] = { {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, @@ -726,11 +726,11 @@ static menuitem_t SR_MainMenu[] = }; -static menuitem_t SR_LevelSelectMenu[] = +/*static menuitem_t SR_LevelSelectMenu[] = { {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, {IT_WHITESTRING|IT_CALL, NULL, "Start", M_LevelSelectWarp, 130}, -}; +};*/ static menuitem_t SR_UnlockChecklistMenu[] = { @@ -766,7 +766,7 @@ enum }; // Single Player Load Game -static menuitem_t SP_LoadGameMenu[] = +/*static menuitem_t SP_LoadGameMenu[] = { {IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleLoadSave, '\0'}, // dummy menuitem for the control func }; @@ -776,7 +776,7 @@ static menuitem_t SP_LevelSelectMenu[] = { {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, {IT_WHITESTRING|IT_CALL, NULL, "Start", M_LevelSelectWarp, 130}, -}; +};*/ // Single Player Time Attack static menuitem_t SP_TimeAttackMenu[] = @@ -906,6 +906,7 @@ static menuitem_t SP_LevelStatsMenu[] = // A rare case. // External files modify this menu, so we can't call it static. // And I'm too lazy to go through and rename it everywhere. ARRGH! +#define M_ChoosePlayer NULL menuitem_t PlayerMenu[32] = { {IT_CALL, NULL, NULL, M_ChoosePlayer, 0}, @@ -947,29 +948,40 @@ menuitem_t PlayerMenu[32] = // ----------------------------------- // Prefix: MP_ -#ifndef NONET - static menuitem_t MP_MainMenu[] = { - {IT_HEADER, NULL, "Host a game", NULL, 0}, - {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 10}, - {IT_STRING|IT_CALL, NULL, "Splitscreen...", M_StartSplitServerMenu, 18}, - {IT_HEADER, NULL, "Join a game", NULL, 32}, - {IT_STRING|IT_CALL, NULL, "Server browser...", M_ConnectMenu, 42}, - {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 50}, - {IT_HEADER, NULL, "Player setup", NULL, 80}, - {IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, + {IT_HEADER, NULL, "Players", NULL, 0}, + {IT_STRING|IT_CVAR, NULL, "Number of local players", &cv_splitplayers, 10}, + + {IT_STRING|IT_KEYHANDLER,NULL, "Player setup...", M_SetupMultiHandler,18}, + + {IT_HEADER, NULL, "Host a game", NULL, 100-24}, +#ifndef NONET + {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 110-24}, +#else + {IT_GRAYEDOUT, NULL, "Internet/LAN...", NULL, 110-24}, +#endif + {IT_STRING|IT_CALL, NULL, "Offline...", M_StartOfflineServerMenu, 118-24}, + + {IT_HEADER, NULL, "Join a game", NULL, 132-24}, +#ifndef NONET + {IT_STRING|IT_CALL, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, + {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, +#else + {IT_GRAYEDOUT, NULL, "Internet server browser...",M_ConnectMenu, 142-24}, + {IT_GRAYEDOUT, NULL, "Specify IPv4 address:", M_HandleConnectIP, 150-24}, +#endif + //{IT_HEADER, NULL, "Player setup", NULL, 80}, + //{IT_STRING|IT_CALL, NULL, "Name, character, color...", M_SetupMultiPlayer, 90}, }; -#endif +#ifndef NONET static menuitem_t MP_ServerMenu[] = { {IT_STRING|IT_CVAR, NULL, "Max. Player Count", &cv_maxplayers, 10}, -#ifndef NONET {IT_STRING|IT_CALL, NULL, "Room...", M_RoomMenu, 20}, {IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Server Name", &cv_servername, 30}, -#endif {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, @@ -977,43 +989,17 @@ static menuitem_t MP_ServerMenu[] = {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; -// Separated splitscreen and normal servers. -static menuitem_t MP_SplitServerMenu[] = -{ -#ifndef NOFOURPLAYER - {IT_STRING|IT_CVAR, NULL, "Number of players", &cv_dummysplitplayers, 10}, #endif +// Separated offline and normal servers. +static menuitem_t MP_OfflineServerMenu[] = +{ {IT_STRING|IT_CVAR, NULL, "Game Type", &cv_newgametype, 68}, {IT_STRING|IT_CVAR, NULL, "Level", &cv_nextmap, 78}, -#ifdef NOFOURPLAYER - {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 110}, - {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 120}, -#else - {IT_STRING|IT_CALL, NULL, "P1 Setup...", M_SetupMultiPlayer, 90}, - {IT_STRING|IT_CALL, NULL, "P2 Setup... ", M_SetupMultiPlayer2, 100}, - {IT_GRAYEDOUT, NULL, "P3 Setup...", M_SetupMultiPlayer3, 110}, - {IT_GRAYEDOUT, NULL, "P4 Setup... ", M_SetupMultiPlayer4, 120}, -#endif + {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 130}, }; -#ifndef NOFOURPLAYER -static void Dummysplitplayers_OnChange(void) -{ - UINT8 i = 2; // player 2 is the last unchanging setup - - while (i < 4) - { - if (i < cv_dummysplitplayers.value) - MP_SplitServerMenu[3+i].status = IT_STRING|IT_CALL; - else - MP_SplitServerMenu[3+i].status = IT_GRAYEDOUT; - i++; - } -} -#endif - static menuitem_t MP_PlayerSetupMenu[] = { {IT_KEYHANDLER | IT_STRING, NULL, "Name", M_HandleSetupMultiPlayer, 0}, @@ -1102,14 +1088,10 @@ static menuitem_t OP_ControlsMenu[] = {IT_CALL | IT_STRING, NULL, "Player 1 Controls...", M_Setup1PControlsMenu, 10}, {IT_CALL | IT_STRING, NULL, "Player 2 Controls...", M_Setup2PControlsMenu, 20}, -#ifdef NOFOURPLAYER - {IT_STRING | IT_CVAR, NULL, "Controls per key", &cv_controlperkey, 40}, -#else {IT_CALL | IT_STRING, NULL, "Player 3 Controls...", &M_Setup3PControlsMenu, 30}, {IT_CALL | IT_STRING, NULL, "Player 4 Controls...", &M_Setup4PControlsMenu, 40}, {IT_STRING | IT_CVAR, NULL, "Controls per key", &cv_controlperkey, 60}, -#endif }; static menuitem_t OP_AllControlsMenu[] = @@ -1177,7 +1159,6 @@ static menuitem_t OP_Joystick2Menu[] = {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis2 , 90}, }; -#ifndef NOFOURPLAYER static menuitem_t OP_Joystick3Menu[] = { {IT_STRING | IT_CALL, NULL, "Select Gamepad..." , M_Setup3PJoystickMenu, 10}, @@ -1201,7 +1182,6 @@ static menuitem_t OP_Joystick4Menu[] = {IT_STRING | IT_CVAR, NULL, "Use Item" , &cv_fireaxis4 , 80}, {IT_STRING | IT_CVAR, NULL, "Look Up/Down" , &cv_lookaxis4 , 90}, }; -#endif static menuitem_t OP_JoystickSetMenu[] = { @@ -1262,7 +1242,8 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 90}, #ifdef HWRENDER - {IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 105}, + {IT_STRING | IT_CVAR, NULL, "3D models", &cv_grmd2, 105}, + {IT_SUBMENU|IT_STRING, NULL, "OpenGL Options...", &OP_OpenGLOptionsDef, 115}, #endif }; @@ -1292,18 +1273,19 @@ static menuitem_t OP_VideoModeMenu[] = #ifdef HWRENDER static menuitem_t OP_OpenGLOptionsMenu[] = { - {IT_STRING|IT_CVAR, NULL, "Field of View", &cv_grfov, 10}, - {IT_STRING|IT_CVAR, NULL, "Quality", &cv_scr_depth, 20}, - {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 30}, - {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode,40}, -#ifdef _WINDOWS + {IT_SUBMENU|IT_STRING, NULL, "Fog...", &OP_OpenGLFogDef, 10}, + {IT_SUBMENU|IT_STRING, NULL, "Gamma...", &OP_OpenGLColorDef, 20}, + + {IT_STRING|IT_CVAR, NULL, "Field of View", &cv_grfov, 35}, + {IT_STRING|IT_CVAR, NULL, "Quality", &cv_scr_depth, 45}, + {IT_STRING|IT_CVAR, NULL, "Texture Filter", &cv_grfiltermode, 55}, + {IT_STRING|IT_CVAR, NULL, "Anisotropic", &cv_granisotropicmode, 65}, +/*#ifdef _WINDOWS {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 50}, #endif #ifdef ALAM_LIGHTING {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 70}, -#endif - {IT_SUBMENU|IT_STRING, NULL, "Fog...", &OP_OpenGLFogDef, 80}, - {IT_SUBMENU|IT_STRING, NULL, "Gamma...", &OP_OpenGLColorDef, 90}, +#endif*/ }; #ifdef ALAM_LIGHTING @@ -1336,7 +1318,7 @@ static menuitem_t OP_SoundOptionsMenu[] = { {IT_KEYHANDLER|IT_STRING, NULL, "SFX", M_ToggleSFX, 10}, {IT_STRING|IT_CVAR|IT_CV_SLIDER, - NULL, "SFX Volume", &cv_soundvolume, 18}, + NULL, "SFX Volume", &cv_soundvolume, 18}, {IT_KEYHANDLER|IT_STRING, NULL, "Music", M_ToggleDigital, 30}, {IT_STRING|IT_CVAR|IT_CV_SLIDER, @@ -1351,16 +1333,16 @@ static menuitem_t OP_SoundOptionsMenu[] = NULL, "CD Volume", &cd_volume, 40}, #endif*/ - {IT_STRING|IT_CALL, NULL, "Restart Audio System", M_RestartAudio, 50}, + //{IT_STRING|IT_CALL, NULL, "Restart Audio System", M_RestartAudio, 50}, - {IT_STRING|IT_CVAR, NULL, "Reverse L/R Channels", &stereoreverse, 65}, - {IT_STRING|IT_CVAR, NULL, "Surround Sound", &surround, 75}, + {IT_STRING|IT_CVAR, NULL, "Reverse L/R Channels", &stereoreverse, 50}, + {IT_STRING|IT_CVAR, NULL, "Surround Sound", &surround, 60}, - {IT_STRING|IT_CVAR, NULL, "Chat sounds", &cv_chatnotifications, 90}, - {IT_STRING|IT_CVAR, NULL, "Character voices", &cv_kartvoices, 100}, - {IT_STRING|IT_CVAR, NULL, "Powerup Warning", &cv_kartinvinsfx, 110}, + {IT_STRING|IT_CVAR, NULL, "Chat sounds", &cv_chatnotifications, 75}, + {IT_STRING|IT_CVAR, NULL, "Character voices", &cv_kartvoices, 85}, + {IT_STRING|IT_CVAR, NULL, "Powerup Warning", &cv_kartinvinsfx, 95}, - {IT_KEYHANDLER|IT_STRING, NULL, "Sound Test", M_HandleSoundTest, 125}, + {IT_KEYHANDLER|IT_STRING, NULL, "Sound Test", M_HandleSoundTest, 110}, }; /*static menuitem_t OP_DataOptionsMenu[] = @@ -1596,6 +1578,7 @@ menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72); // Misc Main Menu menu_t MISC_ScrambleTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ScrambleTeamMenu, &MPauseDef, 27, 40); menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeTeamMenu, &MPauseDef, 27, 40); +menu_t MISC_ChangeSpectateDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeSpectateMenu, &MPauseDef, 27, 40); menu_t MISC_ChangeLevelDef = MAPICONMENUSTYLE(NULL, MISC_ChangeLevelMenu, &MPauseDef); menu_t MISC_HelpDef = IMAGEDEF(MISC_HelpMenu); @@ -1666,6 +1649,13 @@ inline static void M_GetGametypeColor(void) highlightflags = V_YELLOWMAP; // FALLBACK } +// excuse me but I'm extremely lazy: +INT32 HU_GetHighlightColor(void) +{ + M_GetGametypeColor(); // update flag colour reguardless of the menu being opened or not. + return highlightflags; +} + // Sky Room menu_t SR_PandoraDef = { @@ -1690,7 +1680,7 @@ menu_t SR_MainDef = NULL }; -menu_t SR_LevelSelectDef = MAPICONMENUSTYLE(NULL, SR_LevelSelectMenu, &SR_MainDef); +//menu_t SR_LevelSelectDef = MAPICONMENUSTYLE(NULL, SR_LevelSelectMenu, &SR_MainDef); menu_t SR_UnlockChecklistDef = { @@ -1717,7 +1707,7 @@ menu_t SR_EmblemHintDef = // Single Player menu_t SP_MainDef = CENTERMENUSTYLE(NULL, SP_MainMenu, &MainDef, 72); -menu_t SP_LoadDef = +/*menu_t SP_LoadDef = { "M_PICKG", 1, @@ -1728,7 +1718,7 @@ menu_t SP_LoadDef = 0, NULL }; -menu_t SP_LevelSelectDef = MAPICONMENUSTYLE(NULL, SP_LevelSelectMenu, &SP_LoadDef); +menu_t SP_LevelSelectDef = MAPICONMENUSTYLE(NULL, SP_LevelSelectMenu, &SP_LoadDef);*/ menu_t SP_LevelStatsDef = { @@ -1833,7 +1823,7 @@ static menu_t SP_NightsGhostDef = };*/ -menu_t SP_PlayerDef = +/*menu_t SP_PlayerDef = { "M_PICKP", sizeof (PlayerMenu)/sizeof (menuitem_t),//player_end, @@ -1843,7 +1833,7 @@ menu_t SP_PlayerDef = 24, 32, 0, NULL -}; +};*/ #ifndef NONET // Multiplayer @@ -1854,13 +1844,13 @@ menu_t MP_MainDef = &MainDef, MP_MainMenu, M_DrawMPMainMenu, - 42, 50, + 42, 30, 0, M_CancelConnect }; menu_t MP_ServerDef = MAPICONMENUSTYLE("M_MULTI", MP_ServerMenu, &MP_MainDef); #endif -menu_t MP_SplitServerDef = MAPICONMENUSTYLE("M_MULTI", MP_SplitServerMenu, &MP_MainDef); +menu_t MP_OfflineServerDef = MAPICONMENUSTYLE("M_MULTI", MP_OfflineServerMenu, &MP_MainDef); #ifndef NONET menu_t MP_ConnectDef = { @@ -1914,10 +1904,8 @@ menu_t OP_ControlsDef = DEFAULTMENUSTYLE("M_CONTRO", OP_ControlsMenu, &OP_MainDe menu_t OP_AllControlsDef = CONTROLMENUSTYLE(OP_AllControlsMenu, &OP_ControlsDef); menu_t OP_Joystick1Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick1Menu, &OP_AllControlsDef, 60, 30); menu_t OP_Joystick2Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick2Menu, &OP_AllControlsDef, 60, 30); -#ifndef NOFOURPLAYER menu_t OP_Joystick3Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick3Menu, &OP_AllControlsDef, 60, 30); menu_t OP_Joystick4Def = DEFAULTMENUSTYLE("M_CONTRO", OP_Joystick4Menu, &OP_AllControlsDef, 60, 30); -#endif menu_t OP_JoystickSetDef = { "M_CONTRO", @@ -2131,6 +2119,14 @@ static void Nextmap_OnChange(void) } } +static void Dummymenuplayer_OnChange(void) +{ + if (cv_dummymenuplayer.value < 1) + CV_StealthSetValue(&cv_dummymenuplayer, splitscreen+1); + else if (cv_dummymenuplayer.value > splitscreen+1) + CV_StealthSetValue(&cv_dummymenuplayer, 1); +} + /*static void Dummymares_OnChange(void) { if (!nightsrecords[cv_nextmap.value-1]) @@ -2636,21 +2632,21 @@ boolean M_Responder(event_t *ev) case KEY_DOWNARROW: M_NextOpt(); S_StartSound(NULL, sfx_menu1); - if (currentMenu == &SP_PlayerDef) + /*if (currentMenu == &SP_PlayerDef) { Z_Free(char_notes); char_notes = NULL; - } + }*/ return true; case KEY_UPARROW: M_PrevOpt(); S_StartSound(NULL, sfx_menu1); - if (currentMenu == &SP_PlayerDef) + /*if (currentMenu == &SP_PlayerDef) { Z_Free(char_notes); char_notes = NULL; - } + }*/ return true; case KEY_LEFTARROW: @@ -2865,18 +2861,18 @@ void M_StartControlPanel(void) } else if (!(netgame || multiplayer)) // Single Player { - if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff. + if (gamestate != GS_LEVEL /*|| ultimatemode*/) // intermission, so gray out stuff. { SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_GRAYEDOUT) : (IT_DISABLED); SPauseMenu[spause_retry].status = IT_GRAYEDOUT; } else { - INT32 numlives = 2; + //INT32 numlives = 2; SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); - if (&players[consoleplayer]) + /*if (&players[consoleplayer]) { numlives = players[consoleplayer].lives; if (players[consoleplayer].playerstate != PST_LIVE) @@ -2887,12 +2883,12 @@ void M_StartControlPanel(void) // for me to want to use the short if statement syntax if (numlives <= 1 || G_IsSpecialStage(gamemap)) SPauseMenu[spause_retry].status = (IT_GRAYEDOUT); - else + else*/ SPauseMenu[spause_retry].status = (IT_STRING | IT_CALL); } // We can always use level select though. :33 - SPauseMenu[spause_levelselect].status = (gamecomplete) ? (IT_STRING | IT_CALL) : (IT_DISABLED); + //SPauseMenu[spause_levelselect].status = (gamecomplete) ? (IT_STRING | IT_CALL) : (IT_DISABLED); // And emblem hints. SPauseMenu[spause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED); @@ -2914,19 +2910,23 @@ void M_StartControlPanel(void) MPauseMenu[mpause_scramble].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit2].status = IT_DISABLED; -#ifndef NOFOURPLAYER MPauseMenu[mpause_psetupsplit3].status = IT_DISABLED; MPauseMenu[mpause_psetupsplit4].status = IT_DISABLED; -#endif MPauseMenu[mpause_spectate].status = IT_DISABLED; MPauseMenu[mpause_entergame].status = IT_DISABLED; MPauseMenu[mpause_canceljoin].status = IT_DISABLED; MPauseMenu[mpause_switchteam].status = IT_DISABLED; + MPauseMenu[mpause_switchspectate].status = IT_DISABLED; MPauseMenu[mpause_psetup].status = IT_DISABLED; + MISC_ChangeTeamMenu[0].status = IT_DISABLED; + MISC_ChangeSpectateMenu[0].status = IT_DISABLED; // Reset these in case splitscreen messes things up + MPauseMenu[mpause_switchteam].alphaKey = 48; + MPauseMenu[mpause_switchspectate].alphaKey = 48; MPauseMenu[mpause_options].alphaKey = 64; MPauseMenu[mpause_title].alphaKey = 80; MPauseMenu[mpause_quit].alphaKey = 88; + Dummymenuplayer_OnChange(); if ((server || IsPlayerAdmin(consoleplayer))) { @@ -2939,28 +2939,44 @@ void M_StartControlPanel(void) if (splitscreen) { MPauseMenu[mpause_psetupsplit].status = MPauseMenu[mpause_psetupsplit2].status = IT_STRING | IT_CALL; + MISC_ChangeTeamMenu[0].status = MISC_ChangeSpectateMenu[0].status = IT_STRING|IT_CVAR; + + if (netgame) + { + if (G_GametypeHasTeams()) + { + MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; + MPauseMenu[mpause_switchteam].alphaKey += ((splitscreen+1) * 8); + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; + } + else if (G_GametypeHasSpectators()) + { + MPauseMenu[mpause_switchspectate].status = IT_STRING | IT_SUBMENU; + MPauseMenu[mpause_switchspectate].alphaKey += ((splitscreen+1) * 8); + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; + } + } -#ifndef NOFOURPLAYER if (splitscreen > 1) { MPauseMenu[mpause_psetupsplit3].status = IT_STRING | IT_CALL; - if (splitscreen == 2) - { - MPauseMenu[mpause_options].alphaKey = 72; - MPauseMenu[mpause_title].alphaKey = 88; - MPauseMenu[mpause_quit].alphaKey = 96; - } + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; - if (splitscreen == 3) + if (splitscreen > 2) { MPauseMenu[mpause_psetupsplit4].status = IT_STRING | IT_CALL; - MPauseMenu[mpause_options].alphaKey = 80; - MPauseMenu[mpause_title].alphaKey = 96; - MPauseMenu[mpause_quit].alphaKey = 104; + MPauseMenu[mpause_options].alphaKey += 8; + MPauseMenu[mpause_title].alphaKey += 8; + MPauseMenu[mpause_quit].alphaKey += 8; } } -#endif } else { @@ -3085,10 +3101,10 @@ void M_Init(void) return; // Menu hacks -#ifndef NOFOURPLAYER - CV_RegisterVar(&cv_dummysplitplayers); -#endif + CV_RegisterVar(&cv_splitplayers); + CV_RegisterVar(&cv_dummymenuplayer); CV_RegisterVar(&cv_dummyteam); + CV_RegisterVar(&cv_dummyspectate); CV_RegisterVar(&cv_dummyscramble); CV_RegisterVar(&cv_dummyrings); CV_RegisterVar(&cv_dummylives); @@ -3364,7 +3380,7 @@ static void M_DrawMapEmblems(INT32 mapnum, INT32 x, INT32 y) V_DrawSmallScaledPatch(x, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); emblem = M_GetLevelEmblems(-1); - x -= 12; + x -= 8; } } @@ -4871,11 +4887,11 @@ static void M_ConfirmSpectate(INT32 choice) static void M_ConfirmEnterGame(INT32 choice) { (void)choice; - /*if (!cv_allowteamchange.value) + if (!cv_allowteamchange.value) { M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); return; - }*/ + } M_ClearMenus(true); COM_ImmedExecute("changeteam playing"); } @@ -4885,20 +4901,16 @@ static void M_ConfirmTeamScramble(INT32 choice) (void)choice; M_ClearMenus(true); - switch (cv_dummyscramble.value) - { - case 0: - COM_ImmedExecute("teamscramble 1"); - break; - case 1: - COM_ImmedExecute("teamscramble 2"); - break; - } + COM_ImmedExecute(va("teamscramble %d", cv_dummyscramble.value+1)); } static void M_ConfirmTeamChange(INT32 choice) { (void)choice; + + if (cv_dummymenuplayer.value > splitscreen+1) + return; + if (!cv_allowteamchange.value && cv_dummyteam.value) { M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); @@ -4907,16 +4919,53 @@ static void M_ConfirmTeamChange(INT32 choice) M_ClearMenus(true); - switch (cv_dummyteam.value) + switch (cv_dummymenuplayer.value) { - case 0: - COM_ImmedExecute("changeteam spectator"); - break; case 1: - COM_ImmedExecute("changeteam red"); + default: + COM_ImmedExecute(va("changeteam %s", cv_dummyteam.string)); break; case 2: - COM_ImmedExecute("changeteam blue"); + COM_ImmedExecute(va("changeteam2 %s", cv_dummyteam.string)); + break; + case 3: + COM_ImmedExecute(va("changeteam3 %s", cv_dummyteam.string)); + break; + case 4: + COM_ImmedExecute(va("changeteam4 %s", cv_dummyteam.string)); + break; + } +} + +static void M_ConfirmSpectateChange(INT32 choice) +{ + (void)choice; + + if (cv_dummymenuplayer.value > splitscreen+1) + return; + + if (!cv_allowteamchange.value && cv_dummyspectate.value) + { + M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING); + return; + } + + M_ClearMenus(true); + + switch (cv_dummymenuplayer.value) + { + case 1: + default: + COM_ImmedExecute(va("changeteam %s", cv_dummyspectate.string)); + break; + case 2: + COM_ImmedExecute(va("changeteam2 %s", cv_dummyspectate.string)); + break; + case 3: + COM_ImmedExecute(va("changeteam3 %s", cv_dummyspectate.string)); + break; + case 4: + COM_ImmedExecute(va("changeteam4 %s", cv_dummyspectate.string)); break; } } @@ -4962,7 +5011,7 @@ static void M_RetryResponse(INT32 ch) static void M_Retry(INT32 choice) { (void)choice; - M_StartMessage(M_GetText("Retry this act from the last starpost?\n\n(Press 'Y' to confirm)\n"),M_RetryResponse,MM_YESNO); + M_StartMessage(M_GetText("Start this race over?\n\n(Press 'Y' to confirm)\n"),M_RetryResponse,MM_YESNO); } static void M_SelectableClearMenus(INT32 choice) @@ -5009,7 +5058,7 @@ static void M_DestroyRobots(INT32 choice) M_StartMessage(M_GetText("Do you want to destroy all\nrobots in the current level?\n\n(Press 'Y' to confirm)\n"),M_DestroyRobotsResponse,MM_YESNO); } -static void M_LevelSelectWarp(INT32 choice) +/*static void M_LevelSelectWarp(INT32 choice) { boolean fromloadgame = (currentMenu == &SP_LevelSelectDef); @@ -5032,7 +5081,7 @@ static void M_LevelSelectWarp(INT32 choice) cursaveslot = -1; M_SetupChoosePlayer(0); } -} +}*/ // ======== // SKY ROOM @@ -5096,7 +5145,7 @@ static void M_DrawChecklist(void) { if (unlockables[i].name[0] == 0 || unlockables[i].nochecklist || !unlockables[i].conditionset || unlockables[i].conditionset > MAXCONDITIONSETS - || !M_Achieved(unlockables[i].showconditionset - 1)) + || (!M_Achieved(unlockables[i].showconditionset - 1) && !unlockables[i].unlocked)) continue; ++line; @@ -5377,7 +5426,7 @@ static void M_HandleSoundTest(INT32 choice) // NEW GAME FUNCTIONS // ================== -INT32 ultimate_selectable = false; +/*INT32 ultimate_selectable = false; static void M_NewGame(void) { @@ -5387,7 +5436,7 @@ static void M_NewGame(void) CV_SetValue(&cv_newgametype, GT_RACE); // SRB2kart M_SetupChoosePlayer(0); -} +}*/ /*static void M_CustomWarp(INT32 choice) { @@ -5438,7 +5487,7 @@ static void M_SinglePlayerMenu(INT32 choice) M_SetupNextMenu(&SP_MainDef); } -static void M_LoadGameLevelSelect(INT32 choice) +/*static void M_LoadGameLevelSelect(INT32 choice) { (void)choice; levellistmode = LLM_LEVELSELECT; @@ -5453,13 +5502,13 @@ static void M_LoadGameLevelSelect(INT32 choice) M_PrepareLevelSelect(); M_SetupNextMenu(&SP_LevelSelectDef); -} +}*/ // ============== // LOAD GAME MENU // ============== -static INT32 saveSlotSelected = 0; +/*static INT32 saveSlotSelected = 0; static short menumovedir = 0; static void M_DrawLoadGameData(void) @@ -5858,13 +5907,13 @@ static void M_HandleLoadSave(INT32 choice) // // Selected from SRB2 menu // -/*static void M_LoadGame(INT32 choice) +static void M_LoadGame(INT32 choice) { (void)choice; M_ReadSaveStrings(); M_SetupNextMenu(&SP_LoadDef); -}*/ +} // // Used by cheats to force the save menu to a specific spot. @@ -6081,11 +6130,7 @@ static void M_ChoosePlayer(INT32 choice) G_DeferedInitNew(false, G_BuildMapName(startmap), (UINT8)skinnum, 0, fromlevelselect); COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this -} - -// =============== -// STATISTICS MENU -// =============== +}*/ // =============== // STATISTICS MENU @@ -6154,7 +6199,7 @@ static void M_DrawStatsMaps(int location) } mnum = statsMapList[i]; - M_DrawMapEmblems(mnum+1, 292, y); + M_DrawMapEmblems(mnum+1, 295, y); if (mapheaderinfo[mnum]->levelflags & LF_NOZONE) V_DrawString(20, y, 0, va("%s %s", @@ -6203,10 +6248,10 @@ static void M_DrawStatsMaps(int location) exemblem = &extraemblems[i]; if (exemblem->collected) - V_DrawSmallMappedPatch(292, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem), PU_CACHE), + V_DrawSmallMappedPatch(295, y, 0, W_CachePatchName(M_GetExtraEmblemPatch(exemblem), PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, M_GetExtraEmblemColor(exemblem), GTC_CACHE)); else - V_DrawSmallScaledPatch(292, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); + V_DrawSmallScaledPatch(295, y, 0, W_CachePatchName("NEEDIT", PU_CACHE)); V_DrawString(20, y, 0, va("%s", exemblem->description)); } @@ -6219,7 +6264,7 @@ static void M_DrawStatsMaps(int location) bottomarrow: if (dobottomarrow) V_DrawCharacter(10, y-8 + (skullAnimCounter/5), - '\x1B' | highlightflags, false); // up arrow + '\x1B' | highlightflags, false); // down arrow } static void M_DrawLevelStats(void) @@ -6265,8 +6310,8 @@ static void M_DrawLevelStats(void) else V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, recommendedflags, "(complete)"); - V_DrawString(36, 70, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems)); - V_DrawSmallScaledPatch(20, 70, 0, W_CachePatchName("EMBLICON", PU_STATIC)); + V_DrawString(32, 70, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems)); + V_DrawSmallScaledPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_STATIC)); M_DrawStatsMaps(statsLocation); } @@ -6322,7 +6367,6 @@ void M_DrawTimeAttackMenu(void) { INT32 i, x, y, cursory = 0; UINT16 dispstatus; - patch_t *PictureOfUrFace; //S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback @@ -6338,11 +6382,10 @@ void M_DrawTimeAttackMenu(void) y = currentMenu->y; // Character face! - if (W_CheckNumForName(skins[cv_chooseskin.value-1].face) != LUMPERROR) + if (W_CheckNumForName(skins[cv_chooseskin.value-1].facewant) != LUMPERROR) { UINT8 *colormap = R_GetTranslationColormap(cv_chooseskin.value-1, cv_playercolor.value, 0); - PictureOfUrFace = W_CachePatchName(skins[cv_chooseskin.value-1].face, PU_CACHE); - V_DrawMappedPatch(BASEVIDWIDTH-x - SHORT(PictureOfUrFace->width), y, 0, PictureOfUrFace, colormap); + V_DrawMappedPatch(BASEVIDWIDTH-x - SHORT(facewantprefix[cv_chooseskin.value-1]->width), y, 0, facewantprefix[cv_chooseskin.value-1], colormap); } for (i = 0; i < currentMenu->numitems; ++i) @@ -7347,17 +7390,12 @@ static INT32 M_FindFirstMap(INT32 gtype) static void M_StartServer(INT32 choice) { - UINT8 ssplayers = 0; + UINT8 ssplayers = cv_splitplayers.value-1; (void)choice; - if (currentMenu == &MP_SplitServerDef) - ssplayers = -#ifdef NOFOURPLAYER - 1; -#else - cv_dummysplitplayers.value-1; -#endif + if (currentMenu == &MP_OfflineServerDef) + netgame = false; else netgame = true; @@ -7374,24 +7412,27 @@ static void M_StartServer(INT32 choice) if (!cv_nextmap.value) CV_SetValue(&cv_nextmap, G_RandMap(G_TOLFlag(cv_newgametype.value), -1, false, false, 0, false)+1); - if (ssplayers < 1) + if (cv_maxplayers.value < ssplayers+1) + CV_SetValue(&cv_maxplayers, ssplayers+1); + + if (splitscreen != ssplayers) { - D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); - COM_BufAddText("dummyconsvar 1\n"); + splitscreen = ssplayers; + SplitScreen_OnChange(); } - else // split screen + + if (currentMenu == &MP_OfflineServerDef) // offline server { paused = false; SV_StartSinglePlayerServer(); - - if (splitscreen != ssplayers) - { - splitscreen = ssplayers; - SplitScreen_OnChange(); - } - + multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this... D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); } + else + { + D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false); + COM_BufAddText("dummyconsvar 1\n"); + } M_ClearMenus(true); } @@ -7527,7 +7568,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) static void M_DrawServerMenu(void) { - M_DrawLevelSelectOnly((currentMenu == &MP_SplitServerDef), false); + M_DrawLevelSelectOnly(false, false); M_DrawGenericMenu(); #ifndef NONET @@ -7537,15 +7578,92 @@ static void M_DrawServerMenu(void) #define mp_server_room 1 if (ms_RoomId < 0) V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, - highlightflags, (itemOn == mp_server_room) ? "" : ""); else V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, highlightflags, room_list[menuRoomIndex].name); #undef mp_server_room } - else #endif - if (currentMenu == &MP_SplitServerDef) +} + +static void M_MapChange(INT32 choice) +{ + (void)choice; + + levellistmode = LLM_CREATESERVER; + + CV_SetValue(&cv_newgametype, gametype); + CV_SetValue(&cv_nextmap, gamemap); + + M_PrepareLevelSelect(); + M_SetupNextMenu(&MISC_ChangeLevelDef); +} + +static void M_StartOfflineServerMenu(INT32 choice) +{ + (void)choice; + levellistmode = LLM_CREATESERVER; + M_PrepareLevelSelect(); + M_SetupNextMenu(&MP_OfflineServerDef); +} + +#ifndef NONET +static void M_StartServerMenu(INT32 choice) +{ + (void)choice; + levellistmode = LLM_CREATESERVER; + M_PrepareLevelSelect(); + ms_RoomId = -1; + M_SetupNextMenu(&MP_ServerDef); + +} + +// ============== +// CONNECT VIA IP +// ============== + +static char setupm_ip[16]; +#endif +static UINT8 setupm_pselect = 1; + +// Draw the funky Connect IP menu. Tails 11-19-2002 +// So much work for such a little thing! +static void M_DrawMPMainMenu(void) +{ + INT32 x = currentMenu->x; + INT32 y = currentMenu->y; + + // use generic drawer for cursor, items and title + M_DrawGenericMenu(); + +#ifndef NONET +#if MAXPLAYERS != 16 +Update the maxplayers label... +#endif + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[4].alphaKey, + ((itemOn == 4) ? highlightflags : 0), "(2-16 players)"); +#endif + + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[5].alphaKey, + ((itemOn == 5) ? highlightflags : 0), + "(2-4 players)" + ); + +#ifndef NONET + y += MP_MainMenu[8].alphaKey; + + V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 239); + + // draw name string + V_DrawString(x+8,y+12, V_MONOSPACE, setupm_ip); + + // draw text cursor for name + if (itemOn == 8 + && skullAnimCounter < 4) //blink cursor + V_DrawCharacter(x+8+V_StringWidth(setupm_ip, V_MONOSPACE),y+12,'_',false); +#endif + // character bar, ripped off the color bar :V { #define iconwidth 32 @@ -7553,21 +7671,13 @@ static void M_DrawServerMenu(void) #define incrwidth (iconwidth + spacingwidth) UINT8 i = 0, pskin, pcol; // player arrangement width, but there's also a chance i'm a furry, shhhhhh - const INT32 paw = iconwidth + -#ifndef NOFOURPLAYER - 3* -#endif - incrwidth; - INT32 x = BASEVIDWIDTH/2 - paw/2, y = currentMenu->y + 27, trans = 0; - patch_t *face; + const INT32 paw = iconwidth + 3*incrwidth; + INT32 trans = 0; + UINT8 *colmap; + x = BASEVIDWIDTH/2 - paw/2; + y = currentMenu->y + 32; - while (++i <= -#ifdef NOFOURPLAYER - 2 -#else - 4 -#endif - ) + while (++i <= 4) { switch (i) { @@ -7592,13 +7702,20 @@ static void M_DrawServerMenu(void) if (pskin >= MAXSKINS) pskin = 0; -#ifndef NOFOURPLAYER - if (!trans && i > cv_dummysplitplayers.value) + if (!trans && i > cv_splitplayers.value) trans = V_TRANSLUCENT; -#endif - face = W_CachePatchName(skins[pskin].face, PU_CACHE); - V_DrawFixedPatch(x< 1) + { + if (--setupm_pselect < 1) + setupm_pselect = cv_splitplayers.value; + S_StartSound(NULL,sfx_menu1); // Tails + } + break; + + case KEY_RIGHTARROW: + if (cv_splitplayers.value > 1) + { + if (++setupm_pselect > cv_splitplayers.value) + setupm_pselect = 1; + S_StartSound(NULL,sfx_menu1); // Tails + } + break; + + case KEY_DOWNARROW: + M_NextOpt(); + S_StartSound(NULL,sfx_menu1); // Tails + break; + + case KEY_UPARROW: + M_PrevOpt(); + S_StartSound(NULL,sfx_menu1); // Tails + break; + + case KEY_ENTER: + { + S_StartSound(NULL,sfx_menu1); // Tails + currentMenu->lastOn = itemOn; + switch (setupm_pselect) + { + case 2: + M_SetupMultiPlayer2(0); + return; + case 3: + M_SetupMultiPlayer3(0); + return; + case 4: + M_SetupMultiPlayer4(0); + return; + default: + M_SetupMultiPlayer(0); + return; + } + break; + } + + case KEY_ESCAPE: + exitmenu = true; + break; + } + + if (exitmenu) + { + if (currentMenu->prevMenu) + M_SetupNextMenu (currentMenu->prevMenu); + else + M_ClearMenus(true); + } } #ifndef NONET -static void M_StartServerMenu(INT32 choice) -{ - (void)choice; - levellistmode = LLM_CREATESERVER; - M_PrepareLevelSelect(); - ms_RoomId = -1; - M_SetupNextMenu(&MP_ServerDef); - -} - -// ============== -// CONNECT VIA IP -// ============== - -static char setupm_ip[16]; - -// Draw the funky Connect IP menu. Tails 11-19-2002 -// So much work for such a little thing! -static void M_DrawMPMainMenu(void) -{ - INT32 x = currentMenu->x; - INT32 y = currentMenu->y; - - // use generic drawer for cursor, items and title - M_DrawGenericMenu(); - -#if MAXPLAYERS == 16 - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[1].alphaKey, - ((itemOn == 1) ? highlightflags : 0), "(2-16 players)"); -#else -Update the maxplayers label... -#endif - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[2].alphaKey, - ((itemOn == 2) ? highlightflags : 0), -#ifdef NOFOURPLAYER - "(2 players)" -#else - "(2-4 players)" -#endif - ); - - y += MP_MainMenu[5].alphaKey; - - V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 239); - - // draw name string - V_DrawString(x+8,y+12, V_MONOSPACE, setupm_ip); - - // draw text cursor for name - if (itemOn == 5 - && skullAnimCounter < 4) //blink cursor - V_DrawCharacter(x+8+V_StringWidth(setupm_ip, V_MONOSPACE),y+12,'_',false); -} // Tails 11-19-2002 static void M_ConnectIP(INT32 choice) @@ -7695,6 +7813,8 @@ static void M_ConnectIP(INT32 choice) return; } + M_ClearMenus(true); + COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); // A little "please wait" message. @@ -7726,7 +7846,6 @@ static void M_HandleConnectIP(INT32 choice) case KEY_ENTER: S_StartSound(NULL,sfx_menu1); // Tails - M_ClearMenus(true); M_ConnectIP(1); break; @@ -7935,6 +8054,7 @@ static void M_DrawSetupMultiPlayerMenu(void) INT32 offx = 8, offy = 8; patch_t *cursor = W_CachePatchName("K_CHRCUR", PU_CACHE); patch_t *face; + UINT8 *colmap; if (col < 0) col += numskins; @@ -7943,19 +8063,21 @@ static void M_DrawSetupMultiPlayerMenu(void) if (!(k++)) { scale = FRACUNIT; + face = facewantprefix[col]; offx = 12; offy = 0; } else { scale = FRACUNIT/2; + face = facerankprefix[col]; offx = 8; offy = 8; } - face = W_CachePatchName(skins[col].face, PU_CACHE); - V_DrawFixedPatch((x+offx)<= numskins) col -= numskins; x += FixedMul(iconwidth<x - 16, y-(skullAnimCounter/5), highlightflags, "\x1A"); // up arrow + V_DrawCharacter(currentMenu->x - 16, y-(skullAnimCounter/5), + '\x1A' | highlightflags, false); // up arrow if (max != currentMenu->numitems) - V_DrawString(currentMenu->x - 16, y+(SMALLLINEHEIGHT*(controlheight-1))+(skullAnimCounter/5), highlightflags, "\x1B"); // down arrow + V_DrawCharacter(currentMenu->x - 16, y+(SMALLLINEHEIGHT*(controlheight-1))+(skullAnimCounter/5) + (skullAnimCounter/5), + '\x1B' | highlightflags, false); // down arrow for (; i < max; i++) { @@ -8923,25 +9045,10 @@ static void M_ToggleDigital(INT32 choice) } }*/ -static void M_RestartAudio(void) +/*static void M_RestartAudio(void) { - S_StopMusic(); - I_ShutdownMusic(); - I_ShutdownSound(); - I_StartupSound(); - I_InitMusic(); - - I_SetSfxVolume(cv_soundvolume.value); - I_SetDigMusicVolume(cv_digmusicvolume.value); - //I_SetMIDIMusicVolume(cv_midimusicvolume.value); - - S_StartSound(NULL, sfx_strpst); - - if (Playing()) // Gotta make sure the player is in a level - P_RestoreMusic(&players[consoleplayer]); - else - S_ChangeMusicInternal("titles", looptitle); -} + COM_ImmedExecute("restartaudio"); +}*/ // =============== // VIDEO MODE MENU diff --git a/src/m_menu.h b/src/m_menu.h index cb083b0e..c300380b 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -228,6 +228,8 @@ void Screenshot_option_Onchange(void); // Addons menu updating void Addons_option_Onchange(void); +INT32 HU_GetHighlightColor(void); + // These defines make it a little easier to make menus #define DEFAULTMENUSTYLE(header, source, prev, x, y)\ {\ diff --git a/src/p_enemy.c b/src/p_enemy.c index 37dd5899..ea10b62b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -190,9 +190,18 @@ void A_ToggleFlameJet(mobj_t *actor); void A_ItemPop(mobj_t *actor); // SRB2kart void A_JawzChase(mobj_t *actor); // SRB2kart void A_JawzExplode(mobj_t *actor); // SRB2kart +void A_SPBChase(mobj_t *actor); // SRB2kart void A_MineExplode(mobj_t *actor); // SRB2kart void A_BallhogExplode(mobj_t *actor); // SRB2kart -void A_LightningFollowPlayer(mobj_t *actor); // SRB2kart +void A_LightningFollowPlayer(mobj_t *actor); // SRB2kart +void A_FZBoomFlash(mobj_t *actor); // SRB2kart +void A_FZBoomSmoke(mobj_t *actor); // SRB2kart +void A_RandomShadowFrame(mobj_t *actor); // SRB2kart +void A_RoamingShadowThinker(mobj_t *actor); //SRB2kart +void A_MayonakaArrow(mobj_t *actor); //SRB2kart +void A_ReaperThinker(mobj_t *actor); //SRB2kart +void A_MementosTPParticles(mobj_t *actor); //SRB2kart +void A_FlameParticle(mobj_t *actor); // SRB2kart void A_OrbitNights(mobj_t *actor); void A_GhostMe(mobj_t *actor); void A_SetObjectState(mobj_t *actor); @@ -3406,7 +3415,7 @@ void A_ParticleSpawn(mobj_t *actor) P_SetScale(spawn, actor->scale); spawn->momz = speed; spawn->destscale = FixedDiv(spawn->scale<scalespeed = FixedDiv(((actor->spawnpoint->angle >> 8) & 63) << FRACBITS, 100<scalespeed = FixedDiv(((actor->spawnpoint->angle >> 8) & 63) * actor->scale, 100<tics = actor->spawnpoint->extrainfo + 1; } @@ -4014,7 +4023,7 @@ static inline boolean PIT_MineExplode(mobj_t *thing) grenade->flags2 |= MF2_DEBRIS; if (thing->player) // Looks like we're going to have to need a seperate function for this too - K_ExplodePlayer(thing->player, grenade->target); + K_ExplodePlayer(thing->player, grenade->target, grenade); else P_DamageMobj(thing, grenade, grenade->target, 1); @@ -4053,7 +4062,7 @@ void A_MineExplode(mobj_t *actor) if (actor->target && actor->target->player) K_SpawnMineExplosion(actor, actor->target->player->skincolor); else - K_SpawnMineExplosion(actor, SKINCOLOR_RED); + K_SpawnMineExplosion(actor, SKINCOLOR_KETCHUP); P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINEEXPLOSIONSOUND); } @@ -8173,7 +8182,7 @@ void A_ToggleFlameJet(mobj_t* actor) } } -//{ SRB2kart - A_ItemPop, A_JawzChase, A_JawzExplode, A_MineExplode, and A_BallhogExplode +//{ SRB2kart Actions void A_ItemPop(mobj_t *actor) { mobj_t *remains; @@ -8252,6 +8261,9 @@ void A_JawzChase(mobj_t *actor) if (actor->tracer) { + if (G_RaceGametype()) // Stop looking after first target in race + actor->extravalue1 = 1; + if (actor->tracer->health) { mobj_t *ret; @@ -8271,13 +8283,13 @@ void A_JawzChase(mobj_t *actor) if (actor->extravalue1) // Disable looking by setting this return; + if (actor->target && !P_MobjWasRemoved(actor->target)) // No source! + return; + player = K_FindJawzTarget(actor, actor->target->player); if (player) P_SetTarget(&actor->tracer, player->mo); - if (G_RaceGametype()) // Stop looking after first tic in race - actor->extravalue1 = 1; - return; } @@ -8293,7 +8305,7 @@ void A_JawzExplode(mobj_t *actor) truc = P_SpawnMobj(actor->x, actor->y, actor->z, MT_BOOMEXPLODE); truc->scale = actor->scale*2; - truc->color = SKINCOLOR_RED; + truc->color = SKINCOLOR_KETCHUP; while (shrapnel) { @@ -8311,7 +8323,7 @@ void A_JawzExplode(mobj_t *actor) speed2 = FixedMul(15*FRACUNIT, actor->scale)>>FRACBITS; truc->momz = P_RandomRange(speed, speed2)*FRACUNIT; truc->tics = TICRATE*2; - truc->color = SKINCOLOR_RED; + truc->color = SKINCOLOR_KETCHUP; shrapnel--; } @@ -8319,65 +8331,221 @@ void A_JawzExplode(mobj_t *actor) return; } -/* old A_MineExplode - see elsewhere in the file -void A_MineExplode(mobj_t *actor) +void A_SPBChase(mobj_t *actor) { - mobj_t *mo2; - thinker_t *th; - INT32 d; - INT32 locvar1 = var1; - mobjtype_t type; - fixed_t range; + player_t *player = NULL; + UINT8 i; + UINT8 bestrank = UINT8_MAX; + fixed_t dist; + angle_t hang, vang; + fixed_t wspeed, xyspeed, zspeed; #ifdef HAVE_BLUA - if (LUA_CallAction("A_MineExplode", actor)) + if (LUA_CallAction("A_SPBChase", actor)) return; #endif - type = (mobjtype_t)locvar1; - range = FixedMul(actor->info->painchance, mapheaderinfo[gamemap-1]->mobj_scale); + // Default speed + wspeed = FixedMul(actor->info->speed, mapheaderinfo[gamemap-1]->mobj_scale); + if (gamespeed == 0) + wspeed = FixedMul(wspeed, FRACUNIT-FRACUNIT/4); + else if (gamespeed == 2) + wspeed = FixedMul(wspeed, FRACUNIT+FRACUNIT/4); - for (th = thinkercap.next; th != &thinkercap; th = th->next) + if (actor->threshold) // Just fired, go straight. { - if (P_MobjWasRemoved(actor)) - return; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot - - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo2 = (mobj_t *)th; - - if (mo2 == actor || mo2->type == MT_MINEEXPLOSIONSOUND) // Don't explode yourself! Endless loop! - continue; - - if (!(mo2->flags & MF_SHOOTABLE) || (mo2->flags & MF_SCENERY)) - continue; - - if (G_BattleGametype() && actor->target && actor->target->player && actor->target->player->kartstuff[k_bumper] <= 0 && mo2 == actor->target) - continue; - - if (P_AproxDistance(P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y), mo2->z - actor->z) > range) - continue; - - actor->flags2 |= MF2_DEBRIS; - - if (mo2->player) // Looks like we're going to have to need a seperate function for this too - K_ExplodePlayer(mo2->player, actor->target); - else - P_DamageMobj(mo2, actor, actor->target, 1); + P_InstaThrust(actor, actor->angle, wspeed); + return; } - for (d = 0; d < 16; d++) - K_SpawnKartExplosion(actor->x, actor->y, actor->z, range + 32*mapheaderinfo[gamemap-1]->mobj_scale, 32, type, d*(ANGLE_45/4), true, false, actor->target); // 32 <-> 64 + if (actor->extravalue1) // MODE: TARGETING + { + if (actor->tracer && actor->tracer->health) + { + fixed_t defspeed = wspeed; + fixed_t range = (160*actor->tracer->scale); - if (actor->target && actor->target->player) - K_SpawnMineExplosion(actor, actor->target->player->skincolor); - else - K_SpawnMineExplosion(actor, SKINCOLOR_RED); + // Maybe we want SPB to target an object later? IDK lol + if (actor->tracer->player) // 7/8ths max speed for Knuckles, 3/4ths max speed for min accel, exactly max speed for max accel + { + if (!P_IsObjectOnGround(actor->tracer) && !actor->tracer->player->kartstuff[k_pogospring]) + defspeed = 7*actor->tracer->player->speed/8; // In the air you have no control; basically don't hit unless you make a near complete stop + else + defspeed = ((33 - actor->tracer->player->kartspeed) * K_GetKartSpeed(actor->tracer->player, false)) / 32; + } - P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINEEXPLOSIONSOUND); + // Play the intimidating gurgle + if (!S_SoundPlaying(actor, actor->info->activesound)) + S_StartSound(actor, actor->info->activesound); + + dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z); + + wspeed = FixedMul(defspeed, FRACUNIT + FixedDiv(dist-range, range)); + if (wspeed < defspeed) + wspeed = defspeed; + if (wspeed > (3*defspeed)/2) + wspeed = (3*defspeed)/2; + + hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); + vang = R_PointToAngle2(0, actor->z, dist, actor->tracer->z); + + { + // Smoothly rotate horz angle + angle_t input = hang - actor->angle; + boolean invert = (input > ANGLE_180); + if (invert) + input = InvAngle(input); + + // Slow down when turning; it looks better and makes U-turns not unfair + xyspeed = FixedMul(wspeed, max(0, (((180<angle += input; + + // Smoothly rotate vert angle + input = vang - actor->movedir; + invert = (input > ANGLE_180); + if (invert) + input = InvAngle(input); + + // Slow down when turning; might as well do it for momz, since we do it above too + zspeed = FixedMul(wspeed, max(0, (((180<movedir += input; + } + + actor->momx = FixedMul(FixedMul(xyspeed, FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); + actor->momy = FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); + actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT)); + + // Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed! + if (R_PointToDist2(0, 0, actor->momx, actor->momy) > (actor->tracer->player ? (16*actor->tracer->player->speed)/15 + : (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target + && xyspeed > K_GetKartSpeed(actor->tracer->player, false)/4) // Don't display speedup lines at pitifully low speeds + { + mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale), + actor->y + (P_RandomRange(-24,24) * actor->scale), + actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale), + MT_FASTLINE); + fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); + //fast->momx = 3*actor->momx/4; + //fast->momy = 3*actor->momy/4; + //fast->momz = 3*actor->momz/4; + fast->color = SKINCOLOR_RED; + fast->colorized = true; + K_MatchGenericExtraFlags(fast, actor); + } + + return; + } + else // Target's gone, return to SEEKING + { + P_SetTarget(&actor->tracer, NULL); + actor->extravalue1 = 0; // Find someone new next tic + return; + } + } + else // MODE: SEEKING + { + // Find the player with the best rank + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator || players[i].exiting) + continue; // not in-game + + if (!players[i].mo) + continue; // no mobj + + if (players[i].mo->health <= 0) + continue; // dead + + if (players[i].kartstuff[k_respawn]) + continue; // respawning + + if (players[i].kartstuff[k_position] < bestrank) + { + bestrank = players[i].kartstuff[k_position]; + player = &players[i]; + } + } + + // No one there? + if (player == NULL || !player->mo) + { +#if 0 + // SELF-DESTRUCT? + mobj_t *spbexplode; + + S_StopSound(actor); // Don't continue playing the gurgle or the siren + spbexplode = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SPBEXPLOSION); + P_SetTarget(&spbexplode->target, actor->target); + + P_RemoveMobj(actor); +#else + actor->momx = actor->momy = actor->momz = 0; +#endif + return; + } + + // Found someone, now get close enough to initiate the slaughter... + P_SetTarget(&actor->tracer, player->mo); + + dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z); + + hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y); + vang = R_PointToAngle2(0, actor->z, dist, actor->tracer->z); + + { + // Smoothly rotate horz angle + angle_t input = hang - actor->angle; + boolean invert = (input > ANGLE_180); + if (invert) + input = InvAngle(input); + + // Slow down when turning; it looks better and makes U-turns not unfair + xyspeed = FixedMul(wspeed, max(0, (((180<angle += input; + + // Smoothly rotate vert angle + input = vang - actor->movedir; + invert = (input > ANGLE_180); + if (invert) + input = InvAngle(input); + + // Slow down when turning; might as well do it for momz, since we do it above too + zspeed = FixedMul(wspeed, max(0, (((180<movedir += input; + } + + actor->momx = FixedMul(FixedMul(xyspeed, FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); + actor->momy = FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT)); + actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT)); + + if (dist <= (3072*actor->tracer->scale)) // Close enough to target? + { + S_StartSound(actor, actor->info->attacksound); // Siren sound; might not need this anymore, but I'm keeping it for now just for debugging. + actor->extravalue1 = 1; // TARGET ACQUIRED + } + } return; -}*/ +} void A_BallhogExplode(mobj_t *actor) { @@ -8403,7 +8571,9 @@ void A_LightningFollowPlayer(mobj_t *actor) if (LUA_CallAction("A_LightningFollowPlayer", actor)) return; #endif - if (actor->target) + if (!actor->target) + return; + { if (actor->extravalue1) // Make the radius also follow the player somewhat accuratly { @@ -8418,9 +8588,444 @@ void A_LightningFollowPlayer(mobj_t *actor) actor->momy = actor->target->momy; actor->momz = actor->target->momz; // Give momentum since we don't teleport to our player literally every frame. } +} + +// A_FZBoomFlash: +// Flash everyone close enough to the boom +void A_FZBoomFlash(mobj_t *actor) +{ + UINT8 i; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FZBoomFlash", actor)) + return; +#endif + for (i = 0; i < MAXPLAYERS; i++) + { + fixed_t dist; + if (!playeringame[i] || !players[i].mo) + continue; + dist = P_AproxDistance(P_AproxDistance(actor->x-players[i].mo->x, actor->y-players[i].mo->y), actor->z-players[i].mo->z); + if (dist < 1536<x + (P_RandomRange(-rad, rad)*actor->scale), actor->y + (P_RandomRange(-rad, rad)*actor->scale), + actor->z + (P_RandomRange(0, 72)*actor->scale), MT_THOK); + + P_SetMobjState(smoke, S_FZEROSMOKE1); + smoke->tics += P_RandomRange(-3, 4); + smoke->scale = actor->scale*3; + } + return; +} + +// A_RandomShadowFrame +// Gives a random sprite for the Mayonaka static shadows. Dumb and simple. +void A_RandomShadowFrame(mobj_t *actor) +{ + mobj_t *fire; + mobj_t *fake; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RandomShadowFrame", (actor))) + return; +#endif + + if (!actor->extravalue1) // Hack that spawns thoks that look like random shadows. Otherwise the state would overwrite our frame and that's a pain. + { + fake = P_SpawnMobj(actor->x, actor->y, actor->z, MT_THOK); + fake->sprite = SPR_ENM1; + fake->frame = P_RandomRange(0, 6); + P_SetScale(fake, FRACUNIT*3/2); + fake->scale = FRACUNIT*3/2; + fake->destscale = FRACUNIT*3/2; + fake->angle = actor->angle; + fake->tics = -1; + actor->flags2 |= MF2_DONTDRAW; + actor->extravalue1 = 1; + } + + P_SetScale(actor, FRACUNIT*3/2); + + // I have NO CLUE how to hardcode all of that fancy Linedef Executor shit so the fire spinout will be done by these entities directly. + if (P_LookForPlayers(actor, false, false, 380<target && !actor->target->player->powers[pw_flashing] + && !actor->target->player->kartstuff[k_invincibilitytimer] + && !actor->target->player->kartstuff[k_growshrinktimer] + && !actor->target->player->kartstuff[k_spinouttimer] + && P_IsObjectOnGround(actor->target) + && actor->z == actor->target->z) + { + P_DamageMobj(actor->target, actor, actor, 1); + P_InstaThrust(actor->target, actor->angle, 16<target->x, actor->target->y, actor->target->z, MT_THOK); + P_SetMobjStateNF(fire, S_QUICKBOOM1); + P_SetScale(fire, 4<color = SKINCOLOR_RED; + S_StartSound(actor->target, sfx_fire2); + } + } + return; +} + +// A_RoamingShadowThinker +// Thinker for Midnight Channel's Roaming Shadows: +void A_RoamingShadowThinker(mobj_t *actor) +{ + mobj_t *wind; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_RoamingShadowThinker", (actor))) + return; +#endif + // extravalue1 replaces "movetimer" + // extravalue2 replaces "stoptimer" + + P_SetScale(actor, FRACUNIT*3/2); + if (!actor->extravalue2) + { + P_InstaThrust(actor, actor->angle, 8<extravalue1 = ((actor->extravalue1) ? (actor->extravalue1-1) : (TICRATE*5+1)); // deplete timer if set, set to 5 ticrate otherwise. + if (actor->extravalue1 == 1) // if timer reaches 1, do a u-turn. + { + actor->extravalue1 = 0; + actor->extravalue2 = 60; + } + // Search for and attack Players venturing too close in front of us. + + if (P_LookForPlayers(actor, false, false, 256<target && !actor->target->player->powers[pw_flashing] + && !actor->target->player->kartstuff[k_invincibilitytimer] + && !actor->target->player->kartstuff[k_growshrinktimer] + && !actor->target->player->kartstuff[k_spinouttimer]) + { + // send them flying and spawn the WIND! + P_InstaThrust(actor->target, 0, 0); + P_DamageMobj(actor->target, actor, actor, 1); + P_SetObjectMomZ(actor->target, 16<target, sfx_wind1); + + // Spawn the WIND: + wind = P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, MT_THOK); // Opaque layer: + P_SetMobjState(wind, S_GARU1); + P_SetScale(wind, FRACUNIT*3/2); + wind = P_SpawnMobj(actor->target->x, actor->target->y, actor->target->z, MT_THOK); // Translucent layer: + P_SetMobjState(wind, S_TGARU0); + P_SetScale(wind, FRACUNIT*3/2); + wind->destscale = 30<angle += ANG1*3; + actor->extravalue2--; + } + return; +} + +// A_MayonakaArrow +// Used for the arrow sprite animations in Mayonaka. It's only extra visual bullshit to make em more random. + +void A_MayonakaArrow(mobj_t *actor) +{ + INT32 flip = 0; + INT32 iswarning; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MayonakaArrow", (actor))) + return; +#endif + + iswarning = actor->spawnpoint->options & MTF_OBJECTSPECIAL; // is our object a warning sign? + // "animtimer" is replaced by "extravalue1" here. + actor->extravalue1 = ((actor->extravalue1) ? (actor->extravalue1+1) : (P_RandomRange(0, (iswarning) ? (TICRATE/2) : TICRATE*3))); + flip = ((actor->spawnpoint->options & 1) ? (3) : (0)); // flip adds 3 frames, which is the flipped version of the sign. + // special warning behavior: + if (iswarning) + flip = 6; + + actor->frame = flip + actor->extravalue2*3; + + if (actor->extravalue1 >= TICRATE*7/2) + { + actor->extravalue1 = 0; // reset to 0 and start a new cycle. + // special behavior for warning sign; swap from warning to sneaker & reverse + if (iswarning) + actor->extravalue2 = (actor->extravalue2) ? (0) : (1); + } + else if (actor->extravalue1 > TICRATE*7/2 -4) + actor->frame = flip+2; + else if (actor->extravalue1 > TICRATE*3 && leveltime%2 > 0) + actor->frame = flip+1; + + actor->frame |= FF_PAPERSPRITE; + actor->momz = 0; + return; +} + +// A_MementosTPParticles +// Mementos teleporters particles effects. Short and simple. + +void A_MementosTPParticles(mobj_t *actor) +{ + mobj_t *particle; + mobj_t *mo2; + int i = 0; + thinker_t *th; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MementosTPParticles", (actor))) + return; +#endif + + for (; i<4; i++) + { + particle = P_SpawnMobj(actor->x + (P_RandomRange(-256, 256)<y + (P_RandomRange(-256, 256)<z + (P_RandomRange(48, 256)<frame = 0; + particle->color = ((i%2) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK)); + particle->destscale = 1; + P_HomingAttack(particle, actor); + } + + // Although this is mostly used to spawn particles, we will also save the OTHER teleport inside actor->target. That way teleporting doesn't require a thinker iteration. + // Doesn't seem like much given the small amount of mobjs this map has but heh. + if (!actor->target) + { + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + if (mo2->type == MT_MEMENTOSTP && mo2 != actor) + { + P_SetTarget(&actor->target, mo2); // The main target we're pursing. + break; + } + } + } +} + +// A_ReaperThinker +// Mementos's Reaper's thinker. A huge pain in the Derek Bum to translate from Lua to this shite if you ask me. + +void A_ReaperThinker(mobj_t *actor) +{ + mobj_t *particle; // particles to spawn + int i = 0; // for loops + angle_t an = ANGLE_22h; // Reminder that angle constants suck. + + //Waypoint stuff: + mobj_t *mo2; + thinker_t *th; + + //Player targetting stuff: + UINT32 maxscore = 0; // we target the player with the highest score so yeah there you go. + player_t *player; // used as a shortcut in a loop. + mobj_t *targetplayermo = NULL; // the player mo we can eventually target, or whatever. + + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_ReaperThinker", (actor))) + return; +#endif + + // We don't have custom variables or whatever so we'll do with whatever the fuck we have left. + + if (actor->health == 1000) // if health is 1000, set it to a small scale and have it start growing with destscale. Then set the health to uh, not 1000. + { + actor->scale = 1; + actor->destscale = 2<scalespeed = FRACUNIT/24; // Should take a bit less than 2 seconds to fully grow. + S_StartSound(NULL, sfx_chain); + actor->health--; // now we have 999 health, so that above won't happen again. Awesome. + } + + if (actor->scale < 2<x + (P_RandomRange(-60, 60)<y + (P_RandomRange(-60, 60)<z, MT_THOK); + particle->momz = 20<color = ((i%2 !=0) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK)); + particle->frame = 0; + P_SetScale(particle, FRACUNIT/2); + } + + // Spawn particles in some edgy circle or w/e. + + if (leveltime%5 != 0) // spawn the thing under that every tic. + return; + + i=0; + for (; i<15; i++) // spawn in a circle formation or w/e. + { + particle = P_SpawnMobj(actor->x, actor->y, actor->z, MT_THOK); + particle->momz = 20<color = ((i%2 !=0) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK)); + particle->frame = 0; + P_SetScale(particle, FRACUNIT/2); + P_InstaThrust(particle, an*i, 30<flags = MF_NOGRAVITY|MF_PAIN|MF_SPECIAL|MF_NOCLIP|MF_NOCLIPHEIGHT; // set our flags to be a damaging thing. + // Handle animation: + if (!(leveltime%5)) + actor->extravalue2 = (actor->extravalue2 < 9) ? (actor->extravalue2+1) : (0); // Ghetto animation, but hey it works for what it's worth + + // Chain sfx + if (!S_SoundPlaying(actor, sfx_chain)) + S_StartSound(actor, sfx_chain); + + actor->frame = actor->extravalue2; // yes i'm that bad at maths don't @ me. + + if (!actor->target) + { + if (actor->hnext) + { + P_SetTarget(&actor->target, actor->hnext); // Default back to last waypoint. + return; + } + + // We have no target and oughta find one, so let's scan through thinkers for a waypoint of angle 0, or something. + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_REAPERWAYPOINT) + continue; + if (mo2->spawnpoint->angle != 0) + continue; + + P_SetTarget(&actor->target, mo2); // The main target we're pursing. + P_SetTarget(&actor->hnext, mo2); // The last waypoint we hit. We will default back to that if a player goes out of our range! + actor->extravalue1 = 0; // This will store the angle of the last waypoint we touched. This will essentially be useful later on. + if (!actor->tracer) // If we already have a tracer (Waypoint #0), don't do anything. + { + P_SetTarget(&actor->tracer, mo2); // Because our target might be a player OR a waypoint, we need some sort of fallback option. This will always be waypoint 0. + break; + } + } + } + else // Awesome, we now have a target. + { + // Follow target: + P_InstaThrust(actor, R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y), 20<angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + + // The player we should target if it's near us: + for (i=0; imo && player->kartstuff[k_bumper] && player->score >= maxscore) + { + targetplayermo = player->mo; + maxscore = player->score; + } + } + + // Try to target that player: + if (targetplayermo) + { + if (P_LookForPlayers(actor, false, false, 1024<target == targetplayermo && actor->target && !actor->target->player->powers[pw_flashing] + && !actor->target->player->kartstuff[k_invincibilitytimer] + && !actor->target->player->kartstuff[k_growshrinktimer] + && !actor->target->player->kartstuff[k_spinouttimer])) + P_SetTarget(&actor->target, actor->hnext); + // if the above isn't correct, then we should go back to targetting waypoints or something. + } + } + + // Waypoint behavior. + if (actor->target->type == MT_REAPERWAYPOINT) + { + + if (R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) < 22<target, NULL); // remove target so we can default back to first waypoint if things go ham. + + // If we reach close to a waypoint, then we should go to the NEXT one. + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_REAPERWAYPOINT) + continue; + if (mo2->spawnpoint->angle != actor->extravalue1+1) + continue; + + P_SetTarget(&actor->target, mo2); // The main target we're pursing. + P_SetTarget(&actor->hnext, mo2); // The last waypoint we hit. We will default back to that if a player goes out of our range! + actor->extravalue1++; // This will store the angle of the last waypoint we touched. This will essentially be useful later on. + break; + } + } + + + if (!actor->target) // If we have no target, revert back to waypoint 0. + { + actor->extravalue1 = 0; + P_SetTarget(&actor->target, actor->tracer); + } + } + else // if our target ISN'T a waypoint, then it can only be a player. + { + if (!P_CheckSight(actor, actor->target) || R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) > 1024<target, actor->hnext); + } + } +} + +void A_FlameParticle(mobj_t *actor) +{ + fixed_t rad = actor->radius>>FRACBITS, hei = actor->radius>>FRACBITS; + mobj_t *par; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlameParticle", actor)) + return; +#endif + + par = P_SpawnMobj( + actor->x + (P_RandomRange(-rad, rad)<y + (P_RandomRange(-rad, rad)<z + (P_RandomRange(hei/2, hei)<info->painchance); + par->momz = actor->scale<<1; +} + //} // Function: A_OrbitNights @@ -9736,6 +10341,8 @@ void A_SetScale(mobj_t *actor) return; } + locvar1 = FixedMul(locvar1, mapheaderinfo[gamemap-1]->mobj_scale); // SRB2Kart + target->destscale = locvar1; // destination scale if (!(locvar2 & 65535)) P_SetScale(target, locvar1); // this instantly changes current scale to var1 if used, if not destscale will alter scale to var1 anyway @@ -10564,4 +11171,6 @@ void A_SpawnFreshCopy(mobj_t *actor) if (newObject->info->seesound) S_StartSound(newObject, newObject->info->seesound); + + newObject->color = actor->color; // SRB2Kart } diff --git a/src/p_floor.c b/src/p_floor.c index 075ad1da..3365b4b9 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -3003,6 +3003,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) fixed_t topz; fixed_t a, b, c; mobjtype_t type = MT_ROCKCRUMBLE1; + const fixed_t spacing = 48*mapheaderinfo[gamemap-1]->mobj_scale; // If the control sector has a special // of Section3:7-15, use the custom debris. @@ -3034,16 +3035,16 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) rightx = sec->lines[rightmostvertex]->v1->x; topy = sec->lines[topmostvertex]->v1->y-(16<lines[bottommostvertex]->v1->y; - topz = *rover->topheight-(16<topheight-(spacing/2); - for (a = leftx; a < rightx; a += (32< bottomy; b -= (32< bottomy; b -= spacing) { if (R_PointInSubsector(a, b)->sector == sec) { mobj_t *spawned = NULL; - for (c = topz; c > *rover->bottomheight; c -= (32< *rover->bottomheight; c -= spacing) { spawned = P_SpawnMobj(a, b, c, type); spawned->fuse = 3*TICRATE; diff --git a/src/p_inter.c b/src/p_inter.c index cd0ed893..0529c0d5 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -324,48 +324,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; } - else if ((special->flags & MF_ENEMY) && !(special->flags & MF_MISSILE)) + else if ((special->flags & MF_ENEMY) && !(special->flags & MF_MISSILE) + && (special->type != MT_SPRINGSHELL)) // Kart: prevent random hits from these things { - //////////////////////////////////////////////////////// - /////ENEMIES!!////////////////////////////////////////// - //////////////////////////////////////////////////////// - /*if (special->type == MT_GSNAPPER && !(((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) - || player->powers[pw_invulnerability] || player->powers[pw_super]) - && toucher->z < special->z + special->height && toucher->z + toucher->height > special->z) - { - // Can only hit snapper from above - P_DamageMobj(toucher, special, special, 1); - } - else if (special->type == MT_SHARP - && ((special->state == &states[special->info->xdeathstate]) || (toucher->z > special->z + special->height/2))) - { - // Cannot hit sharp from above or when red and angry - P_DamageMobj(toucher, special, special, 1); - } - else if (((player->pflags & PF_NIGHTSMODE) && (player->pflags & PF_DRILLING)) - || (player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)) - || player->powers[pw_invulnerability] || player->powers[pw_super]) // Do you possess the ability to subdue the object? - { - if (P_MobjFlip(toucher)*toucher->momz < 0) - toucher->momz = -toucher->momz; - - P_DamageMobj(special, toucher, toucher, 1); - } - else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP)) - || (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) // Flame is bad at logic - JTE - && player->charability == CA_FLY - && (player->powers[pw_tailsfly] - || (toucher->state >= &states[S_PLAY_SPC1] && toucher->state <= &states[S_PLAY_SPC4]))) // Tails can shred stuff with his propeller. - { - if (P_MobjFlip(toucher)*toucher->momz < 0) - toucher->momz = -toucher->momz/2; - - P_DamageMobj(special, toucher, toucher, 1); - } - // SRB2kart - Removed: No more fly states - else*/ - P_DamageMobj(toucher, special, special, 1); - + P_DamageMobj(toucher, special, special, 1); return; } else if (special->flags & MF_FIRE) @@ -378,6 +340,16 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // We now identify by object type, not sprite! Tails 04-11-2001 switch (special->type) { + case MT_MEMENTOSTP: // Mementos teleport + // Teleport player to the other teleporter (special->target). We'll assume there's always only ever 2. + if (!special->target) + return; // foolproof crash prevention check!!!!! + + P_TeleportMove(player->mo, special->target->x, special->target->y, special->target->z + (48<mo->angle = special->target->angle; + P_SetObjectMomZ(player->mo, 12<mo, player->mo->angle, 20<kartstuff[k_itemamount] && player->kartstuff[k_itemtype] != special->threshold)) return; @@ -414,8 +386,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher); break; - case MT_FAKESHIELD: // SRB2kart - case MT_FAKEITEM: + case MT_EGGMANITEM_SHIELD: // SRB2kart + case MT_EGGMANITEM: if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0)) return; @@ -484,13 +456,15 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) else { mobj_t *boom = P_SpawnMobj(special->target->x, special->target->y, special->target->z, MT_BOOMEXPLODE); + UINT8 ptadd = (K_IsPlayerWanted(player) ? 2 : 1); + 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_RED; + 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 @@ -506,17 +480,20 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } 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 - special->target->player->kartstuff[k_comebackpoints]++; + ptadd++; } - special->target->player->kartstuff[k_comebackpoints] += 2 * (K_IsPlayerWanted(player) ? 2 : 1); - if (netgame && cv_hazardlog.value) - CONS_Printf(M_GetText("%s bombed %s!\n"), player_names[special->target->player-players], player_names[player-players]); - if (special->target->player->kartstuff[k_comebackpoints] >= 3) + special->target->player->kartstuff[k_comebackpoints] += ptadd; + + if (ptadd > 1) + special->target->player->kartstuff[k_yougotem] = 2*TICRATE; + + if (special->target->player->kartstuff[k_comebackpoints] >= 2) K_StealBumper(special->target->player, player, true); + special->target->player->kartstuff[k_comebacktimer] = comebacktime; - K_ExplodePlayer(player, special->target); + K_ExplodePlayer(player, special->target, special); } } else if (special->target->player->kartstuff[k_comebackmode] == 1 && P_CanPickupItem(player, 1)) @@ -527,9 +504,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->kartstuff[k_comebackmode] = 0; special->target->player->kartstuff[k_comebackpoints]++; - if (netgame && cv_hazardlog.value) - CONS_Printf(M_GetText("%s gave an item to %s.\n"), player_names[special->target->player-players], player_names[player-players]); - if (special->target->player->kartstuff[k_comebackpoints] >= 3) + if (special->target->player->kartstuff[k_comebackpoints] >= 2) K_StealBumper(special->target->player, player, true); special->target->player->kartstuff[k_comebacktimer] = comebacktime; @@ -539,6 +514,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) else if (special->target->player->kartstuff[k_comebackmode] == 2 && P_CanPickupItem(player, 2)) { mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); + UINT8 ptadd = 1; // No WANTED bonus for tricking + 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 @@ -553,17 +530,19 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) numingame++; } - if (numingame <= 2) // If so, then an extra two karma points so they are 100% certain to switch places; it's annoying to end matches with a fake kill - special->target->player->kartstuff[k_comebackpoints] += 2; + 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 fake kill + ptadd++; } special->target->player->kartstuff[k_comebackmode] = 0; - special->target->player->kartstuff[k_comebackpoints]++; + special->target->player->kartstuff[k_comebackpoints] += ptadd; - if (netgame && cv_hazardlog.value) - CONS_Printf(M_GetText("%s gave an \"item\" to %s.\n"), player_names[special->target->player-players], player_names[player-players]); - if (special->target->player->kartstuff[k_comebackpoints] >= 3) + if (ptadd > 1) + special->target->player->kartstuff[k_yougotem] = 2*TICRATE; + + if (special->target->player->kartstuff[k_comebackpoints] >= 2) K_StealBumper(special->target->player, player, true); + special->target->player->kartstuff[k_comebacktimer] = comebacktime; K_DropItems(player); //K_StripItems(player); @@ -583,6 +562,85 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->kartstuff[k_eggmanblame] = -1; } return; + case MT_SPB: + if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0)) + return; + + if (special->health <= 0 || toucher->health <= 0) + return; + + if (!player->mo || player->spectator) + return; + + if (special->tracer && toucher == special->tracer) + { + mobj_t *spbexplode; + + S_StopSound(special); // Don't continue playing the gurgle or the siren + + if (!player->kartstuff[k_invincibilitytimer] && !player->kartstuff[k_growshrinktimer]) + { + K_DropHnextList(player); + K_StripItems(player); + //player->powers[pw_flashing] = 0; + } + + spbexplode = P_SpawnMobj(toucher->x, toucher->y, toucher->z, MT_SPBEXPLOSION); + spbexplode->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback + P_SetTarget(&spbexplode->target, special->target); + + P_RemoveMobj(special); + } + else + K_SpinPlayer(player, special, 0, false); + return; + /*case MT_EERIEFOG: + special->frame &= ~FF_TRANS80; + special->frame |= FF_TRANS90; + return;*/ + case MT_SMK_MOLE: + if (special->target && !P_MobjWasRemoved(special->target)) + return; + + if (special->health <= 0 || toucher->health <= 0) + return; + + if (!player->mo || player->spectator) + return; + + // kill + if (player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0) + { + P_KillMobj(special, toucher, toucher); + return; + } + + // no interaction + if (player->powers[pw_flashing] > 0 || player->kartstuff[k_hyudorotimer] > 0 + || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0) + return; + + // attach to player! + P_SetTarget(&special->target, toucher); + S_StartSound(special, sfx_s1a2); + return; + case MT_CDUFO: // SRB2kart + if (special->fuse || !P_CanPickupItem(player, 1) || (G_BattleGametype() && player->kartstuff[k_bumper] <= 0)) + return; + + player->kartstuff[k_itemroulette] = 1; + player->kartstuff[k_roulettetype] = 1; + + S_StartSound(toucher, sfx_cdfm73); // they don't make this sound in the original game but it's nice to have a "reward" for good play + + //special->momx = special->momy = special->momz = 0; + special->momz = -(3*special->scale)/2; + //P_SetTarget(&special->target, toucher); + special->fuse = 2*TICRATE; + break; + case MT_BALLOON: // SRB2kart + P_SetObjectMomZ(toucher, 20<spectator) - return; // No messages for dying (crushed) spectators. - - if (!netgame) - return; // Presumably it's obvious what's happening in splitscreen. - -#ifdef HAVE_BLUA - if (LUAh_HurtMsg(player, inflictor, source)) - return; -#endif - - deadtarget = (player->health <= 0); - - // Target's name - snprintf(targetname, sizeof(targetname), "%s%s%s", - CTFTEAMCODE(player), - player_names[player - players], - CTFTEAMENDCODE(player)); - - if (source) - { - // inflictor shouldn't be NULL if source isn't - I_Assert(inflictor != NULL); - - if (source->player) - { - // Source's name (now that we know there is one) - snprintf(sourcename, sizeof(sourcename), "%s%s%s", - CTFTEAMCODE(source->player), - player_names[source->player - players], - CTFTEAMENDCODE(source->player)); - - // We don't care if it's us. - // "Player 1's [redacted] killed Player 1." - if (source->player->playerstate == PST_DEAD && source->player != player && - (inflictor->flags2 & MF2_BEYONDTHEGRAVE)) - deadsource = true; - - if (inflictor->flags & MF_PUSHABLE) - { - str = M_GetText("%s%s's playtime with heavy objects %s %s.\n"); - } - else switch (inflictor->type) - { - case MT_PLAYER: - if ((inflictor->player->powers[pw_shield] & SH_NOSTACK) == SH_BOMB) - str = M_GetText("%s%s's armageddon blast %s %s.\n"); - else if (inflictor->player->powers[pw_invulnerability]) - str = M_GetText("%s%s's invincibility aura %s %s.\n"); - else if (inflictor->player->powers[pw_super]) - str = M_GetText("%s%s's super aura %s %s.\n"); - else - str = M_GetText("%s%s's tagging hand %s %s.\n"); - break; - case MT_SPINFIRE: - str = M_GetText("%s%s's elemental fire trail %s %s.\n"); - break; - case MT_THROWNBOUNCE: - str = M_GetText("%s%s's bounce ring %s %s.\n"); - break; - case MT_THROWNINFINITY: - str = M_GetText("%s%s's infinity ring %s %s.\n"); - break; - case MT_THROWNAUTOMATIC: - str = M_GetText("%s%s's automatic ring %s %s.\n"); - break; - case MT_THROWNSCATTER: - str = M_GetText("%s%s's scatter ring %s %s.\n"); - break; - // TODO: For next two, figure out how to determine if it was a direct hit or splash damage. -SH - case MT_THROWNEXPLOSION: - str = M_GetText("%s%s's explosion ring %s %s.\n"); - break; - case MT_THROWNGRENADE: - str = M_GetText("%s%s's grenade ring %s %s.\n"); - break; - case MT_REDRING: - if (inflictor->flags2 & MF2_RAILRING) - str = M_GetText("%s%s's rail ring %s %s.\n"); - else - str = M_GetText("%s%s's thrown ring %s %s.\n"); - break; - default: - str = M_GetText("%s%s %s %s.\n"); - break; - } - - CONS_Printf(str, - deadsource ? M_GetText("The late ") : "", - sourcename, - deadtarget ? M_GetText("killed") : M_GetText("hit"), - targetname); - return; - } - else switch (source->type) - { - case MT_NULL: - switch(source->threshold) - { - case 42: - deathonly = true; - str = M_GetText("%s drowned.\n"); - break; - case 43: - str = M_GetText("%s was %s by spikes.\n"); - break; - case 44: - deathonly = true; - str = M_GetText("%s was crushed.\n"); - break; - } - break; - case MT_EGGMANICO: - case MT_EGGMANBOX: - str = M_GetText("%s was %s by Eggman's nefarious TV magic.\n"); - break; - case MT_SPIKE: - str = M_GetText("%s was %s by spikes.\n"); - break; - default: - str = M_GetText("%s was %s by an environmental hazard.\n"); - break; - } - } - else - { - // null source, environment kills - // TERRIBLE HACK for hit damage because P_DoPlayerPain moves the player... - // I'll put it back, I promise! - player->mo->z -= player->mo->momz+1; - if (P_PlayerTouchingSectorSpecial(player, 1, 2)) - str = M_GetText("%s was %s by chemical water.\n"); - else if (P_PlayerTouchingSectorSpecial(player, 1, 3)) - str = M_GetText("%s was %s by molten lava.\n"); - else if (P_PlayerTouchingSectorSpecial(player, 1, 4)) - str = M_GetText("%s was %s by electricity.\n"); - else if (deadtarget) - { - deathonly = true; - if (P_PlayerTouchingSectorSpecial(player, 1, 6) - || P_PlayerTouchingSectorSpecial(player, 1, 7)) - str = M_GetText("%s fell into a bottomless pit.\n"); - else if (P_PlayerTouchingSectorSpecial(player, 1, 12)) - str = M_GetText("%s asphyxiated in space.\n"); - else - str = M_GetText("%s died.\n"); - } - if (!str) - str = M_GetText("%s was %s by an environmental hazard.\n"); - - player->mo->z += player->mo->momz+1; - } - - if (!str) // Should not happen! Unless we missed catching something above. - return; - - // Don't log every hazard hit if they don't want us to. - if (!deadtarget && !cv_hazardlog.value) - return; - - if (deathonly) - { - if (!deadtarget) - return; - CONS_Printf(str, targetname); - } - else - CONS_Printf(str, targetname, deadtarget ? M_GetText("killed") : M_GetText("hit")); -} - /** 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 * timelimitintics and overtime's status will be checked here each tick. @@ -2150,7 +2015,7 @@ boolean P_CheckRacers(void) numplayersingame++; } - if (numplayersingame > 1) // if there's more than one player in-game, this is safe to do + if (numplayersingame > 1 && nospectategrief > 0 && numplayersingame >= nospectategrief) // prevent spectate griefing { // check if we just got unlucky and there was only one guy who was a problem for (j = i+1; j < MAXPLAYERS; j++) @@ -2200,8 +2065,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) && !(target->type == MT_ORBINAUT || target->type == MT_ORBINAUT_SHIELD || target->type == MT_JAWZ || target->type == MT_JAWZ_DUD || target->type == MT_JAWZ_SHIELD || target->type == MT_BANANA || target->type == MT_BANANA_SHIELD - || target->type == MT_FAKEITEM || target->type == MT_FAKESHIELD - || target->type == MT_BALLHOG)) // kart dead items + || target->type == MT_EGGMANITEM || target->type == MT_EGGMANITEM_SHIELD + || target->type == MT_BALLHOG || target->type == MT_SPB)) // kart dead items target->flags |= MF_NOGRAVITY; // Don't drop Tails 03-08-2000 else target->flags &= ~MF_NOGRAVITY; // lose it if you for whatever reason have it, I'm looking at you shields @@ -2224,7 +2089,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) // I wish I knew a better way to do this if (target->target && target->target->player && target->target->player->mo) { - if (target->target->player->kartstuff[k_eggmanheld] && target->type == MT_FAKESHIELD) + if (target->target->player->kartstuff[k_eggmanheld] && target->type == MT_EGGMANITEM_SHIELD) target->target->player->kartstuff[k_eggmanheld] = 0; if (target->target->player->kartstuff[k_itemheld]) @@ -2554,8 +2419,12 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) break; case MT_PLAYER: - target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player) target->momx = target->momy = target->momz = 0; + + if (target->player && target->player->pflags & PF_TIMEOVER) + break; + + target->fuse = TICRATE*3; // timer before mobj disappears from view (even if not an actual player) if (!(source && source->type == MT_NULL && source->threshold == 42)) // Don't jump up when drowning P_SetObjectMomZ(target, 14*FRACUNIT, false); @@ -2566,6 +2435,21 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) else P_PlayDeathSound(target); break; + + // SRB2Kart: + case MT_SMK_ICEBLOCK: + { + mobj_t *cur = target->hnext; + while (cur && !P_MobjWasRemoved(cur)) + { + P_SetMobjState(cur, S_SMK_ICEBLOCK2); + cur = cur->hnext; + } + target->fuse = 10; + S_StartSound(target, sfx_s3k80); + } + break; + default: break; } @@ -2626,6 +2510,40 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) target->z += P_MobjFlip(target)*20*target->scale; } + // kill tracer + if (target->type == MT_FROGGER) + { + if (target->tracer && !P_MobjWasRemoved(target->tracer)) + P_KillMobj(target->tracer, inflictor, source); + } + + if (target->type == MT_FROGGER || target->type == MT_ROBRA_HEAD || target->type == MT_BLUEROBRA_HEAD) // clean hnext list + { + mobj_t *cur = target->hnext; + while (cur && !P_MobjWasRemoved(cur)) + { + P_KillMobj(cur, inflictor, source); + cur = cur->hnext; + } + } + + // Bounce up on death + if (target->type == MT_SMK_PIPE || target->type == MT_SMK_MOLE || target->type == MT_SMK_THWOMP) + { + target->flags &= (~MF_NOGRAVITY); + + if (target->eflags & MFE_VERTICALFLIP) + target->z -= target->height; + else + target->z += target->height; + + S_StartSound(target, target->info->deathsound); + + P_SetObjectMomZ(target, 8<x, inflictor->y, target->x, target->y)+ANGLE_90, 16<type == MT_SPIKE && inflictor && target->info->deathstate != S_NULL) { const fixed_t x=target->x,y=target->y,z=target->z; @@ -2819,7 +2737,6 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou /*if (source->player->pflags & PF_TAGIT && !(player->pflags & PF_TAGIT)) { P_AddPlayerScore(source->player, 1); //award points to tagger. - P_HitDeathMessages(player, inflictor, source); if (gametype == GT_TAG) //survivor { @@ -2923,6 +2840,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) // Get rid of shield player->powers[pw_shield] = SH_NONE; player->mo->color = player->skincolor; + player->mo->colorized = false; // Get rid of emeralds player->powers[pw_emeralds] = 0; @@ -2932,6 +2850,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) P_ResetPlayer(player); P_SetPlayerMobjState(player->mo, player->mo->info->deathstate); + /*if (gametype == GT_CTF && (player->gotflag & (GF_REDFLAG|GF_BLUEFLAG))) { P_PlayerFlagBurst(player, false); @@ -2958,6 +2877,17 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage) HU_DoCEcho(va("%s\\is no longer super.\\\\\\\\", player_names[player-players])); }*/ + if (player->pflags & PF_TIMEOVER) + { + mobj_t *boom; + player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP); + player->mo->flags2 |= MF2_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); + } + if (G_BattleGametype()) { if (player->kartstuff[k_bumper] > 0) @@ -3329,7 +3259,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (!player->kartstuff[k_invincibilitytimer] && player->kartstuff[k_growshrinktimer] <= 0) { // Start shrinking! - player->mo->scalespeed = FRACUNIT/TICRATE; + player->mo->scalespeed = mapheaderinfo[gamemap-1]->mobj_scale/TICRATE; player->mo->destscale = 6*(mapheaderinfo[gamemap-1]->mobj_scale)/8; if (cv_kartdebugshrink.value && !player->bot) player->mo->destscale = 6*player->mo->destscale/8; @@ -3355,8 +3285,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da player->kartstuff[k_growshrinktimer] = 2; } player->kartstuff[k_sneakertimer] = 0; - // Invincible or not, we still need this. - //P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_LIGHTNING); S_StartSound(player->mo, sfx_kc59); return true; } @@ -3392,7 +3320,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { if (inflictor && (inflictor->type == MT_ORBINAUT || inflictor->type == MT_ORBINAUT_SHIELD || inflictor->type == MT_JAWZ || inflictor->type == MT_JAWZ_SHIELD || inflictor->type == MT_JAWZ_DUD - || inflictor->player)) + || inflictor->type == MT_SMK_THWOMP || inflictor->player)) { player->kartstuff[k_sneakertimer] = 0; K_SpinPlayer(player, source, 1, false); @@ -3509,8 +3437,6 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player->health < 0) player->health = 0; - P_HitDeathMessages(player, inflictor, source); - P_ForceFeed(player, 40, 10, TICRATE, 40 + min(damage, 100)*2); } diff --git a/src/p_map.c b/src/p_map.c index 468a5c67..f9eb8bc2 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -663,10 +663,66 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - // SRB2kart 011617 - Colission code for kart items //{ + // SRB2kart 011617 - Colission[sic] code for kart items //{ + + if (thing->type == MT_SMK_ICEBLOCK) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (!(tmthing->flags & MF_SOLID || tmthing->flags & MF_SHOOTABLE || tmthing->flags & MF_BOUNCE)) + return true; + + if (!(tmthing->health)) + return true; + + if (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD + || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_EGGMANITEM_SHIELD + || tmthing->type == MT_SSMINE || tmthing->type == MT_SSMINE_SHIELD + || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) + return false; + + if (thing->health) + P_KillMobj(thing, tmthing, tmthing); + + /*if (tmthing->player && (tmthing->player->kartstuff[k_invincibilitytimer] > 0 + || tmthing->player->kartstuff[k_growshrinktimer] > 0)) + return true;*/ + + K_KartBouncing(tmthing, thing, false, true); + return false; + } + + // Push fakes out of other items + if (tmthing->type == MT_EGGMANITEM && (thing->type == MT_RANDOMITEM || thing->type == MT_EGGMANITEM)) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), thing->radius/4); + return true; + } + else if (thing->type == MT_EGGMANITEM && (tmthing->type == MT_RANDOMITEM || tmthing->type == MT_EGGMANITEM)) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y), tmthing->radius/4); + return true; + } if (tmthing->type == MT_RANDOMITEM) return true; + if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) { @@ -824,7 +880,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_PLAYER && thing->player) { if (tmthing->state == &states[S_MINEEXPLOSION1]) - K_ExplodePlayer(thing->player, tmthing->target); + K_ExplodePlayer(thing->player, tmthing->target, tmthing); else K_SpinPlayer(thing->player, tmthing->target, 0, false); } @@ -1033,7 +1089,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { // Player Damage if (thing->state == &states[S_MINEEXPLOSION1]) - K_ExplodePlayer(tmthing->player, thing->target); + K_ExplodePlayer(tmthing->player, thing->target, thing); else K_SpinPlayer(tmthing->player, thing->target, 0, false); @@ -1077,7 +1133,8 @@ static boolean PIT_CheckThing(mobj_t *thing) //} - if (thing->type == MT_FALLINGROCK || tmthing->type == MT_FALLINGROCK) + if ((thing->type == MT_FALLINGROCK && (tmthing->player || tmthing->type == MT_FALLINGROCK)) + || (tmthing->type == MT_FALLINGROCK && (thing->player || thing->type == MT_FALLINGROCK))) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -1385,19 +1442,17 @@ static boolean PIT_CheckThing(mobj_t *thing) // Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person. && !(thing->z + thing->height < tmthing->z || thing->z > tmthing->z + tmthing->height)) { - // SRB2kart - Squish! - if (tmthing->scale > thing->scale + (FRACUNIT/8)) + + if (tmthing->scale > thing->scale + (FRACUNIT/8)) // SRB2kart - Handle squishes first! K_SquishPlayer(thing->player, tmthing); else if (thing->scale > tmthing->scale + (FRACUNIT/8)) K_SquishPlayer(tmthing->player, thing); - - // SRB2kart - Invincibility! - if (tmthing->player->kartstuff[k_invincibilitytimer] && !thing->player->kartstuff[k_invincibilitytimer]) + else if (tmthing->player->kartstuff[k_invincibilitytimer] && !thing->player->kartstuff[k_invincibilitytimer]) // SRB2kart - Then invincibility! P_DamageMobj(thing, tmthing, tmthing, 1); else if (thing->player->kartstuff[k_invincibilitytimer] && !tmthing->player->kartstuff[k_invincibilitytimer]) P_DamageMobj(tmthing, thing, thing, 1); - if (G_BattleGametype() && (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam)) + /*if (G_BattleGametype() && (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam)) { if ((tmthing->player->powers[pw_invulnerability] || tmthing->player->powers[pw_super]) && !thing->player->powers[pw_super]) @@ -1415,7 +1470,7 @@ static boolean PIT_CheckThing(mobj_t *thing) P_DamageMobj(thing, tmthing, tmthing, 1); else if ((thing->player->pflags & PF_TAGIT) && !(tmthing->player->pflags & PF_TAGIT)) P_DamageMobj(tmthing, thing, tmthing, 1); - } + }*/ } // Force solid players in hide and seek to avoid corner stacking. @@ -1538,6 +1593,106 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; } + else if (thing->type == MT_BLUEROBRA_HEAD || thing->type == MT_BLUEROBRA_JOINT) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (!thing->health) + return true; // dead + + if (tmthing->player->kartstuff[k_invincibilitytimer] > 0 + || tmthing->player->kartstuff[k_growshrinktimer] > 0) + { + if (thing->type == MT_BLUEROBRA_JOINT) + P_KillMobj(thing->target, tmthing, tmthing); + else + P_KillMobj(thing, tmthing, tmthing); + return true; + } + else + { + K_KartBouncing(tmthing, thing, false, true); + return false; + } + } + else if (thing->type == MT_SMK_PIPE) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (!thing->health) + return true; // dead + + if (tmthing->player->kartstuff[k_invincibilitytimer] > 0 + || tmthing->player->kartstuff[k_growshrinktimer] > 0) + { + P_KillMobj(thing, tmthing, tmthing); + return true; // kill + } + + K_KartBouncing(tmthing, thing, false, true); + return false; + } + else if (thing->type == MT_SMK_THWOMP) + { + if (!thing->health) + return true; // dead + + if (!thwompsactive) + return true; // not active yet + + if ((tmthing->z < thing->z) && (thing->z >= thing->movefactor-(256<extravalue1 = 1; // purposely try to stomp on players early + //S_StartSound(thing, sfx_s1bb); + } + + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + // kill + if (tmthing->player->kartstuff[k_invincibilitytimer] > 0 + || tmthing->player->kartstuff[k_growshrinktimer] > 0) + { + P_KillMobj(thing, tmthing, tmthing); + return true; + } + + // continue to squish + if (tmthing->player->kartstuff[k_squishedtimer]) + { + tmthing->player->kartstuff[k_squishedtimer] = 2*TICRATE; + tmthing->player->powers[pw_flashing] = K_GetKartFlashing(tmthing->player); + return true; + } + + // no interaction + if (tmthing->player->powers[pw_flashing] > 0 || tmthing->player->kartstuff[k_hyudorotimer] > 0 + || tmthing->player->kartstuff[k_spinouttimer] > 0) //|| tmthing->player->kartstuff[k_squishedtimer] > 0 + return true; + + // collide + if (tmthing->z < thing->z && thing->momz < 0) + K_SquishPlayer(tmthing->player, thing); + else + { + if (thing->flags2 & MF2_AMBUSH) + P_DamageMobj(tmthing, thing, thing, 1); + K_KartBouncing(tmthing, thing, false, true); + } + + return false; + } else if (thing->flags & MF_SOLID) { // see if it went over / under @@ -1551,7 +1706,7 @@ static boolean PIT_CheckThing(mobj_t *thing) else K_KartBouncing(tmthing, thing, false, true); - return true; + return false; } // Are you touching the side of the object you're interacting with? else if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height @@ -2381,6 +2536,11 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) || (thiscam == &camera3 && (players[thirddisplayplayer].pflags & PF_NOCLIP)) || (thiscam == &camera4 && (players[fourthdisplayplayer].pflags & PF_NOCLIP)) || (leveltime < introtime)) +#else + if ((thiscam == &camera && !(players[displayplayer].pflags & PF_TIMEOVER)) + || (thiscam == &camera2 && !(players[secondarydisplayplayer].pflags & PF_TIMEOVER)) + || (thiscam == &camera3 && !(players[thirddisplayplayer].pflags & PF_TIMEOVER)) + || (thiscam == &camera4 && !(players[fourthdisplayplayer].pflags & PF_TIMEOVER))) #endif { // Noclipping player camera noclips too!! floatok = true; @@ -3778,6 +3938,7 @@ void P_BouncePlayerMove(mobj_t *mo) S_StartSound(mo, sfx_s3k49); } + mo->player->kartstuff[k_pogospring] = 0; // Cancel pogo spring effect so you aren't shoved forward back into the wall you just bounced off P_PlayerHitBounceLine(bestslideline); mo->eflags |= MFE_JUSTBOUNCEDWALL; diff --git a/src/p_mobj.c b/src/p_mobj.c index 32ac6550..5404d27c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1403,7 +1403,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) gravityadd >>= 1; break; case MT_BANANA: - case MT_FAKEITEM: + case MT_EGGMANITEM: case MT_SSMINE: gravityadd = FixedMul(gravityadd, 5*FRACUNIT/2); break; @@ -2345,7 +2345,7 @@ static boolean P_ZMovement(mobj_t *mo) case MT_SHELL: // SRB2kart stuff that should die in pits // Shouldn't stop moving along the Z if there's no speed though! - case MT_FAKEITEM: + case MT_EGGMANITEM: case MT_BANANA: case MT_ORBINAUT: case MT_JAWZ: @@ -2626,12 +2626,14 @@ static boolean P_ZMovement(mobj_t *mo) mom.z /= 2; // Rocks not so bouncy - if (abs(mom.x) < FixedMul(STOPSPEED, mo->scale) - && abs(mom.y) < FixedMul(STOPSPEED, mo->scale) - && abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale)) + if (!mo->fuse + && abs(mom.x) < FixedMul(STOPSPEED*2, mo->scale) + && abs(mom.y) < FixedMul(STOPSPEED*2, mo->scale) + && abs(mom.z) < FixedMul(STOPSPEED*2*3, mo->scale)) { - P_RemoveMobj(mo); - return false; + //P_RemoveMobj(mo); + //return false; + mo->fuse = TICRATE; } } else if (mo->type == MT_CANNONBALLDECOR) @@ -3652,6 +3654,11 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled { boolean itsatwodlevel = false; postimg_t postimg = postimg_none; + + // This can happen when joining + if (thiscam->subsector == NULL || thiscam->subsector->sector == NULL) + return true; + if (twodlevel || (thiscam == &camera && players[displayplayer].mo && (players[displayplayer].mo->flags2 & MF2_TWOD)) || (thiscam == &camera2 && players[secondarydisplayplayer].mo && (players[secondarydisplayplayer].mo->flags2 & MF2_TWOD)) @@ -3709,6 +3716,8 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled dummy.y = thiscam->y; dummy.z = thiscam->z; dummy.height = thiscam->height; + if (player->pflags & PF_TIMEOVER) + player->kartstuff[k_timeovercam] = (2*TICRATE)+1; if (!resetcalled && !(player->pflags & PF_NOCLIP || leveltime < introtime) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. P_ResetCamera(player, thiscam); else @@ -6289,6 +6298,8 @@ void P_RunShadows(void) for (mobj = shadowcap; mobj; mobj = next) { + fixed_t floorz; + next = mobj->hnext; P_SetTarget(&mobj->hnext, NULL); @@ -6298,37 +6309,16 @@ void P_RunShadows(void) continue; // shouldn't you already be dead? } - if ((mobj->target->flags2 & MF2_DONTDRAW) - || (((mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z+mobj->target->height > mobj->target->ceilingz) - || (!(mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z < mobj->target->floorz))) + if (mobj->target->player) + floorz = mobj->target->floorz; + else // FOR SOME REASON, plain floorz is not reliable for normal objects, only players?! + floorz = P_FloorzAtPos(mobj->target->x, mobj->target->y, mobj->target->z, mobj->target->height); + + K_MatchGenericExtraFlags(mobj, mobj->target); + + if (((mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z+mobj->target->height > mobj->target->ceilingz) + || (!(mobj->target->eflags & MFE_VERTICALFLIP) && mobj->target->z < floorz)) mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; - - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->eflags |= MFE_VERTICALFLIP; - else - mobj->eflags &= ~MFE_VERTICALFLIP; - - if (mobj->target->eflags & MFE_DRAWONLYFORP1) // groooooaann... - mobj->eflags |= MFE_DRAWONLYFORP1; - else - mobj->eflags &= ~MFE_DRAWONLYFORP1; - - if (mobj->target->eflags & MFE_DRAWONLYFORP2) - mobj->eflags |= MFE_DRAWONLYFORP2; - else - mobj->eflags &= ~MFE_DRAWONLYFORP2; - - if (mobj->target->eflags & MFE_DRAWONLYFORP3) - mobj->eflags |= MFE_DRAWONLYFORP3; - else - mobj->eflags &= ~MFE_DRAWONLYFORP3; - - if (mobj->target->eflags & MFE_DRAWONLYFORP4) - mobj->eflags |= MFE_DRAWONLYFORP4; - else - mobj->eflags &= ~MFE_DRAWONLYFORP4; // First scale to the same radius P_SetScale(mobj, FixedDiv(mobj->target->radius, mobj->info->radius)); @@ -6341,12 +6331,12 @@ void P_RunShadows(void) P_TeleportMove(mobj, dest->x, dest->y, mobj->target->z); if (((mobj->eflags & MFE_VERTICALFLIP) && (mobj->ceilingz > mobj->z+mobj->height)) - || (!(mobj->eflags & MFE_VERTICALFLIP) && (mobj->floorz < mobj->z))) + || (!(mobj->eflags & MFE_VERTICALFLIP) && (floorz < mobj->z))) { INT32 i; fixed_t prevz; - mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : mobj->floorz); + mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : floorz); for (i = 0; i < MAXFFLOORS; i++) { @@ -6358,7 +6348,7 @@ void P_RunShadows(void) // Check new position to see if you should still be on that ledge P_TeleportMove(mobj, dest->x, dest->y, mobj->z); - mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : mobj->floorz); + mobj->z = (mobj->eflags & MFE_VERTICALFLIP ? mobj->ceilingz : floorz); if (mobj->z == prevz) break; @@ -6637,22 +6627,9 @@ void P_MobjThinker(mobj_t *mobj) case MT_JAWZ_SHIELD: case MT_BANANA_SHIELD: case MT_SSMINE_SHIELD: - case MT_FAKESHIELD: + case MT_EGGMANITEM_SHIELD: case MT_SINK_SHIELD: - /*if (mobj->health > 0 && mobj->target && mobj->target->player - && mobj->target->player->health > 0 && !mobj->target->player->spectator) - { - // Was this so hard? -- Handled this with K_UpdateHnextList instead of thinking it away... - if ((mobj->type == MT_ORBINAUT_SHIELD && mobj->target->player->kartstuff[k_itemtype] != KITEM_ORBINAUT) - || (mobj->type == MT_JAWZ_SHIELD && mobj->target->player->kartstuff[k_itemtype] != KITEM_JAWZ) - || (mobj->movedir > 0 && ((UINT16)mobj->target->player->kartstuff[k_itemamount] < mobj->movedir)) - || (!mobj->target->player->kartstuff[k_itemheld])) - { - P_RemoveMobj(mobj); - return; - } - } - else*/ if ((mobj->health > 0 + if ((mobj->health > 0 && (!mobj->target || !mobj->target->player || mobj->target->player->health <= 0 || mobj->target->player->spectator)) || (mobj->health <= 0 && mobj->z <= mobj->floorz) || P_CheckDeathPitCollide(mobj)) // When in death state @@ -6805,22 +6782,18 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && mobj->target->health && mobj->target->player && !mobj->target->player->spectator && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD - && players[displayplayer].mo && !players[displayplayer].spectator) + /*&& players[displayplayer].mo && !players[displayplayer].spectator*/) { - fixed_t scale = mobj->target->scale; + fixed_t scale = 4*mobj->target->scale; mobj->color = mobj->target->color; + K_MatchGenericExtraFlags(mobj, mobj->target); - if (G_RaceGametype() - || mobj->target->player == &players[displayplayer] - || mobj->target->player->kartstuff[k_bumper] <= 0 - || (mobj->target->player->mo->flags2 & MF2_DONTDRAW) + if ((G_RaceGametype() || mobj->target->player->kartstuff[k_bumper] <= 0) #if 1 // Set to 0 to test without needing to host - || !netgame + || ((mobj->target->player == &players[displayplayer]) || P_IsLocalPlayer(mobj->target->player)) #endif ) mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; P_UnsetThingPosition(mobj); mobj->x = mobj->target->x; @@ -6840,15 +6813,19 @@ void P_MobjThinker(mobj_t *mobj) } P_SetThingPosition(mobj); - scale += FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, - players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); - if (scale > 16*FRACUNIT) - scale = 16*FRACUNIT; + if (!splitscreen) + { + scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, + players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); + if (scale > 16*mobj->target->scale) + scale = 16*mobj->target->scale; + } mobj->destscale = scale; if (!mobj->tracer) { - mobj->tracer = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + mobj_t *overlay = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + P_SetTarget(&mobj->tracer, overlay); P_SetTarget(&mobj->tracer->target, mobj); P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); P_SetMobjState(mobj->tracer, S_ITEMICON); // null sprite and frame to be overwritten later @@ -7003,7 +6980,7 @@ void P_MobjThinker(mobj_t *mobj) && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD && players[displayplayer].mo && !players[displayplayer].spectator) { - fixed_t scale = mobj->target->scale; + fixed_t scale = 4*mobj->target->scale; if (!K_IsPlayerWanted(mobj->target->player)) { @@ -7033,10 +7010,13 @@ void P_MobjThinker(mobj_t *mobj) } P_SetThingPosition(mobj); - scale += FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, - players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); - if (scale > 16*FRACUNIT) - scale = 16*FRACUNIT; + if (!splitscreen) + { + scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayer].mo->x-mobj->target->x, + players[displayplayer].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); + if (scale > 16*mobj->target->scale) + scale = 16*mobj->target->scale; + } mobj->destscale = scale; } else if (mobj->health > 0) @@ -7045,6 +7025,14 @@ void P_MobjThinker(mobj_t *mobj) return; } break; + case MT_PETSMOKER: + if (!(leveltime % 10)) + { + mobj_t *smok = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PETSMOKE); + if (mobj->spawnpoint && mobj->spawnpoint->options & MTF_OBJECTSPECIAL) + P_SetMobjStateNF(smok, smok->info->painstate); // same function, diff sprite + } + break; //} case MT_WATERDROP: P_SceneryCheckWater(mobj); @@ -7412,7 +7400,8 @@ void P_MobjThinker(mobj_t *mobj) //{ SRB2kart Items - Death States case MT_ORBINAUT: case MT_BANANA: - case MT_FAKEITEM: + case MT_EGGMANITEM: + case MT_SPB: if (mobj->z <= mobj->floorz) { P_RemoveMobj(mobj); @@ -7421,7 +7410,7 @@ void P_MobjThinker(mobj_t *mobj) // fallthru case MT_ORBINAUT_SHIELD: case MT_BANANA_SHIELD: - case MT_FAKESHIELD: + case MT_EGGMANITEM_SHIELD: mobj->flags2 ^= MF2_DONTDRAW; break; case MT_JAWZ: @@ -7433,7 +7422,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->flags2 ^= MF2_DONTDRAW; break; case MT_SSMINE: - case MT_BLUEEXPLOSION: + case MT_SPBEXPLOSION: if (mobj->health > -100) { P_SetMobjState(mobj, mobj->info->deathstate); @@ -7448,6 +7437,45 @@ void P_MobjThinker(mobj_t *mobj) case MT_MINEEXPLOSIONSOUND: P_RemoveMobj(mobj); return; + case MT_CDUFO: + if (mobj->fuse > TICRATE) + mobj->flags2 ^= MF2_DONTDRAW; // only by good fortune does this end with it having MF2_DONTDRAW... don't touch! + break; + case MT_SMK_PIPE: + if (mobj->flags2 & MF2_AMBUSH) + P_SetMobjStateNF(mobj, mobj->info->seestate); + else + P_SetMobjStateNF(mobj, mobj->info->spawnstate); + /* FALLTHRU */ + case MT_SMK_MOLE: + mobj->flags2 ^= MF2_DONTDRAW; + if (mobj->z <= mobj->floorz) + { + P_RemoveMobj(mobj); + return; + } + break; + case MT_SMK_THWOMP: + if (mobj->flags2 & MF2_AMBUSH) + { + mobj->colorized = true; + mobj->color = (1 + (leveltime % (MAXSKINCOLORS-1))); + mobj->frame |= FF_FULLBRIGHT; + } + else + { + mobj->colorized = false; + mobj->color = SKINCOLOR_NONE; + mobj->frame &= (~FF_FULLBRIGHT); + } + + mobj->flags2 ^= MF2_DONTDRAW; + if (mobj->z <= mobj->floorz) + { + P_RemoveMobj(mobj); + return; + } + break; //} default: break; @@ -7456,13 +7484,14 @@ void P_MobjThinker(mobj_t *mobj) { case MT_FALLINGROCK: // Despawn rocks here in case zmovement code can't do so (blame slopes) - if (!mobj->momx && !mobj->momy && !mobj->momz + if (!mobj->fuse && !mobj->momx && !mobj->momy && !mobj->momz && ((mobj->eflags & MFE_VERTICALFLIP) ? mobj->z + mobj->height >= mobj->ceilingz : mobj->z <= mobj->floorz)) { - P_RemoveMobj(mobj); - return; + //P_RemoveMobj(mobj); + //return; + mobj->fuse = TICRATE; } P_MobjCheckWater(mobj); break; @@ -7889,50 +7918,6 @@ void P_MobjThinker(mobj_t *mobj) } break; //{ SRB2kart Items - case MT_POKEY: - if (mobj->threshold) - { - if (mobj->state == &states[S_POKEY1]) - mobj->health = 1; - else if (mobj->state == &states[S_POKEY2]) - mobj->health = 2; - else if (mobj->state == &states[S_POKEY3]) - mobj->health = 3; - else if (mobj->state == &states[S_POKEY4]) - mobj->health = 4; - else if (mobj->state == &states[S_POKEY5]) - mobj->health = 5; - else if (mobj->state == &states[S_POKEY6]) - mobj->health = 6; - else if (mobj->state == &states[S_POKEY7]) - mobj->health = 7; - else if (mobj->state == &states[S_POKEY8]) - mobj->health = 8; - - mobj->threshold++; - P_SetMobjState(mobj, S_POKEYIDLE); - } - if (mobj->state == &states[S_POKEYIDLE] && mobj->threshold >= 105) - { - if (mobj->health == 1) - P_SetMobjState(mobj, S_POKEY1); - else if (mobj->health == 2) - P_SetMobjState(mobj, S_POKEY2); - else if (mobj->health == 3) - P_SetMobjState(mobj, S_POKEY3); - else if (mobj->health == 4) - P_SetMobjState(mobj, S_POKEY4); - else if (mobj->health == 5) - P_SetMobjState(mobj, S_POKEY5); - else if (mobj->health == 6) - P_SetMobjState(mobj, S_POKEY6); - else if (mobj->health == 7) - P_SetMobjState(mobj, S_POKEY7); - else if (mobj->health == 8) - P_SetMobjState(mobj, S_POKEY8); - mobj->threshold = 0; - } - break; case MT_FLOATINGITEM: { if (mobj->flags & MF_NOCLIPTHING) @@ -8155,7 +8140,8 @@ void P_MobjThinker(mobj_t *mobj) break; } case MT_BANANA: - case MT_FAKEITEM: + case MT_EGGMANITEM: + mobj->friction = ORIG_FRICTION/4; if (mobj->momx || mobj->momy) P_SpawnGhostMobj(mobj); if (mobj->z <= mobj->floorz && mobj->health > 1) @@ -8167,6 +8153,9 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->threshold > 0) mobj->threshold--; break; + case MT_SPB: + indirectitemcooldown = 20*TICRATE; + /* FALLTHRU */ case MT_BALLHOG: P_SpawnGhostMobj(mobj)->fuse = 3; if (mobj->threshold > 0) @@ -8187,7 +8176,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && mobj->target->player) mobj->color = mobj->target->player->skincolor; else - mobj->color = SKINCOLOR_RED; + mobj->color = SKINCOLOR_KETCHUP; if (mobj->momx || mobj->momy) P_SpawnGhostMobj(mobj); if (P_IsObjectOnGround(mobj)) @@ -8213,7 +8202,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->threshold > 0) mobj->threshold--; break; - case MT_BLUEEXPLOSION: + case MT_SPBEXPLOSION: mobj->health--; break; case MT_MINEEXPLOSION: @@ -8251,16 +8240,24 @@ void P_MobjThinker(mobj_t *mobj) return; } - P_TeleportMove(mobj, mobj->target->x + P_ReturnThrustX(mobj, mobj->target->angle+ANGLE_180, mobj->target->radius), - mobj->target->y + P_ReturnThrustY(mobj, mobj->target->angle+ANGLE_180, mobj->target->radius), mobj->target->z); mobj->angle = mobj->target->angle; + 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); - if (mobj->target->player) { - if (mobj->target->player->kartstuff[k_sneakertimer] > mobj->movecount) - P_SetMobjState(mobj, S_BOOSTFLAME); - mobj->movecount = mobj->target->player->kartstuff[k_sneakertimer]; + player_t *p = NULL; + if (mobj->target->target && mobj->target->target->player) + p = mobj->target->target->player; + else if (mobj->target->player) + p = mobj->target->player; + + if (p) + { + if (p->kartstuff[k_sneakertimer] > mobj->movecount) + P_SetMobjState(mobj, S_BOOSTFLAME); + mobj->movecount = p->kartstuff[k_sneakertimer]; + } } if (mobj->state == &states[S_BOOSTSMOKESPAWNER]) @@ -8269,13 +8266,13 @@ void P_MobjThinker(mobj_t *mobj) P_SetScale(smoke, mobj->target->scale/2); smoke->destscale = 3*mobj->target->scale/2; - smoke->scalespeed = FixedMul(smoke->scalespeed, mobj->target->scale); + smoke->scalespeed = mobj->target->scale/12; smoke->momx = mobj->target->momx/2; smoke->momy = mobj->target->momy/2; smoke->momz = mobj->target->momz/2; - P_Thrust(smoke, mobj->target->angle+FixedAngle(P_RandomRange(135, 225)<target->scale); + P_Thrust(smoke, mobj->angle+FixedAngle(P_RandomRange(135, 225)<target->scale); } break; case MT_SPARKLETRAIL: @@ -8295,6 +8292,43 @@ void P_MobjThinker(mobj_t *mobj) } P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); break; + case MT_BRAKEDRIFT: + if ((!mobj->target || !mobj->target->health || !mobj->target->player || !P_IsObjectOnGround(mobj->target)) + || !mobj->target->player->kartstuff[k_drift] || !mobj->target->player->kartstuff[k_brakedrift] + || !((mobj->target->player->cmd.buttons & BT_BRAKE) + || !(mobj->target->player->cmd.buttons & BT_ACCELERATE))) // Letting go of accel functions about the same as brake-drifting + { + P_RemoveMobj(mobj); + return; + } + else + { + fixed_t newx, newy; + angle_t travelangle; + + travelangle = mobj->target->angle - ((ANGLE_45/5)*mobj->target->player->kartstuff[k_drift]); + + newx = mobj->target->x + P_ReturnThrustX(mobj->target, travelangle+ANGLE_180, 24*mobj->target->scale); + newy = mobj->target->y + P_ReturnThrustY(mobj->target, travelangle+ANGLE_180, 24*mobj->target->scale); + P_TeleportMove(mobj, newx, newy, mobj->target->z); + + mobj->angle = travelangle - ((ANGLE_90/5)*mobj->target->player->kartstuff[k_drift]); + P_SetScale(mobj, (mobj->destscale = mobj->target->scale)); + + if (mobj->target->player->kartstuff[k_driftcharge] >= K_GetKartDriftSparkValue(mobj->target->player)*4) + mobj->color = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))); + else if (mobj->target->player->kartstuff[k_driftcharge] >= K_GetKartDriftSparkValue(mobj->target->player)*2) + mobj->color = SKINCOLOR_KETCHUP; + else if (mobj->target->player->kartstuff[k_driftcharge] >= K_GetKartDriftSparkValue(mobj->target->player)) + mobj->color = SKINCOLOR_SAPPHIRE; + else + mobj->color = SKINCOLOR_WHITE; + + K_MatchGenericExtraFlags(mobj, mobj->target); + if (leveltime & 1) + mobj->flags2 |= MF2_DONTDRAW; + } + break; case MT_PLAYERRETICULE: if (!mobj->target || !mobj->target->health) { @@ -8304,10 +8338,7 @@ void P_MobjThinker(mobj_t *mobj) P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); break; case MT_INSTASHIELDB: - if (leveltime & 1) - mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; + mobj->flags2 ^= MF2_DONTDRAW; /* FALLTHRU */ case MT_INSTASHIELDA: if (!mobj->target || !mobj->target->health || (mobj->target->player && !mobj->target->player->kartstuff[k_instashield])) @@ -8317,6 +8348,28 @@ void P_MobjThinker(mobj_t *mobj) } P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); break; + case MT_BATTLEPOINT: + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + P_RemoveMobj(mobj); + return; + } + + if (mobj->movefactor < 48*mobj->target->scale) + { + mobj->movefactor += (48*mobj->target->scale)/6; + if (mobj->movefactor > mobj->target->height) + mobj->movefactor = mobj->target->height; + } + else if (mobj->movefactor > 48*mobj->target->scale) + { + mobj->movefactor -= (48*mobj->target->scale)/6; + if (mobj->movefactor < mobj->target->height) + mobj->movefactor = mobj->target->height; + } + + P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (mobj->target->height/2) + mobj->movefactor); + break; case MT_THUNDERSHIELD: { fixed_t destx, desty; @@ -8353,75 +8406,121 @@ void P_MobjThinker(mobj_t *mobj) P_TeleportMove(mobj, destx, desty, mobj->target->z); break; } - case MT_KARMAHITBOX: - if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator - || (G_RaceGametype() || mobj->target->player->kartstuff[k_bumper])) + case MT_ROCKETSNEAKER: + if (!mobj->target || !mobj->target->health) { P_RemoveMobj(mobj); return; } - - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); - mobj->scalespeed = mobj->target->scalespeed; - mobj->destscale = mobj->target->destscale; - P_SetScale(mobj, mobj->target->scale); - mobj->color = mobj->target->color; - mobj->colorized = (mobj->target->player->kartstuff[k_comebackmode]); - - if (mobj->target->player->kartstuff[k_comebacktimer] > 0) + if (mobj->target->player && !mobj->target->player->kartstuff[k_rocketsneakertimer]) { - if (mobj->state != &states[mobj->info->spawnstate]) - P_SetMobjState(mobj, mobj->info->spawnstate); + mobj->flags &= ~MF_NOGRAVITY; + mobj->angle += ANGLE_45; - if (mobj->target->player->kartstuff[k_comebacktimer] < TICRATE && (leveltime & 1)) - mobj->flags2 &= ~MF2_DONTDRAW; - else - mobj->flags2 |= MF2_DONTDRAW; - } - else - { - if (!mobj->target->player->kartstuff[k_comebackmode] - && mobj->state != &states[mobj->info->spawnstate]) - P_SetMobjState(mobj, mobj->info->spawnstate); - else if (mobj->target->player->kartstuff[k_comebackmode] == 1 - && mobj->state != &states[mobj->info->seestate]) - P_SetMobjState(mobj, mobj->info->seestate); - else if (mobj->target->player->kartstuff[k_comebackmode] == 2 - && mobj->state != &states[mobj->info->painstate]) - P_SetMobjState(mobj, mobj->info->painstate); - - if (mobj->target->player->powers[pw_flashing] && (leveltime & 1)) - mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; - } - - // Now for the wheels - { - const fixed_t rad = FixedMul(mobjinfo[MT_PLAYER].radius, mobj->target->scale); - mobj_t *cur = mobj->hnext; - - while (cur && !P_MobjWasRemoved(cur)) + if (!mobj->extravalue2) { - fixed_t offx = rad; - fixed_t offy = rad; - - if (cur->lastlook == 1 || cur->lastlook == 3) - offx *= -1; - if (cur->lastlook == 2 || cur->lastlook == 3) - offy *= -1; - - P_TeleportMove(cur, mobj->x + offx, mobj->y + offy, mobj->z); - cur->scalespeed = mobj->target->scalespeed; - cur->destscale = mobj->target->destscale; - P_SetScale(cur, mobj->target->scale); - - if (mobj->flags2 & MF2_DONTDRAW) - cur->flags2 |= MF2_DONTDRAW; + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->z -= mobj->height; else - cur->flags2 &= ~MF2_DONTDRAW; + mobj->z += mobj->height; - cur = cur->hnext; + S_StartSound(mobj, mobj->info->deathsound); + P_SetObjectMomZ(mobj, 8*FRACUNIT, false); + P_InstaThrust(mobj, R_PointToAngle2(mobj->target->x, mobj->target->y, mobj->x, mobj->y)+ANGLE_90, 16*FRACUNIT); + mobj->momx += mobj->target->momx; + mobj->momy += mobj->target->momy; + mobj->momz += mobj->target->momz; + mobj->extravalue2 = 1; + } + else if (P_IsObjectOnGround(mobj)) + { + P_RemoveMobj(mobj); + return; + } + } + break; + case MT_KARMAHITBOX: + { + statenum_t state = (mobj->state-states); + + if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator + || (G_RaceGametype() || mobj->target->player->kartstuff[k_bumper])) + { + P_RemoveMobj(mobj); + return; + } + + P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z); + mobj->angle = mobj->target->angle; + mobj->scalespeed = mobj->target->scalespeed; + mobj->destscale = mobj->target->destscale; + P_SetScale(mobj, mobj->target->scale); + mobj->color = mobj->target->color; + mobj->colorized = true; + + // Give items an item-sized hitbox + if (mobj->target->player->kartstuff[k_comebackmode] == 1) + mobj->radius = 36*mobj->target->scale; + else + mobj->radius = 24*mobj->target->scale; + mobj->height = 2*mobj->radius; + + if (mobj->target->player->kartstuff[k_comebacktimer] > 0) + { + if (state < mobj->info->spawnstate || state > mobj->info->spawnstate+19) + P_SetMobjState(mobj, mobj->info->spawnstate); + if (mobj->target->player->kartstuff[k_comebacktimer] < TICRATE && (leveltime & 1)) + mobj->flags2 &= ~MF2_DONTDRAW; + else + mobj->flags2 |= MF2_DONTDRAW; + } + else + { + if (!mobj->target->player->kartstuff[k_comebackmode] + && (state < mobj->info->spawnstate || state > mobj->info->spawnstate+19)) + P_SetMobjState(mobj, mobj->info->spawnstate); + else if (mobj->target->player->kartstuff[k_comebackmode] == 1 + && state != mobj->info->seestate) + P_SetMobjState(mobj, mobj->info->seestate); + else if (mobj->target->player->kartstuff[k_comebackmode] == 2 + && state != mobj->info->painstate) + P_SetMobjState(mobj, mobj->info->painstate); + + if (mobj->target->player->powers[pw_flashing] && (leveltime & 1)) + mobj->flags2 |= MF2_DONTDRAW; + else + mobj->flags2 &= ~MF2_DONTDRAW; + } + + // Now for the wheels + { + const fixed_t rad = FixedMul(mobjinfo[MT_PLAYER].radius, mobj->target->scale); + mobj_t *cur = mobj->hnext; + + while (cur && !P_MobjWasRemoved(cur)) + { + fixed_t offx = rad; + fixed_t offy = rad; + + if (cur->lastlook == 1 || cur->lastlook == 3) + offx *= -1; + if (cur->lastlook == 2 || cur->lastlook == 3) + offy *= -1; + + P_TeleportMove(cur, mobj->x + offx, mobj->y + offy, mobj->z); + cur->scalespeed = mobj->target->scalespeed; + cur->destscale = mobj->target->destscale; + P_SetScale(cur, mobj->target->scale); + cur->color = mobj->target->color; + cur->colorized = true; + + if (mobj->flags2 & MF2_DONTDRAW) + cur->flags2 |= MF2_DONTDRAW; + else + cur->flags2 &= ~MF2_DONTDRAW; + + cur = cur->hnext; + } } } break; @@ -8454,6 +8553,531 @@ void P_MobjThinker(mobj_t *mobj) } } break; + case MT_CDUFO: + if (!mobj->spawnpoint || mobj->fuse) + break; + + if (mobj->movecount) + { + mobj->movecount--; + break; + } + else if (P_AproxDistance(mobj->x - (mobj->spawnpoint->x<y - (mobj->spawnpoint->y<movecount = 3; + + { + angle_t facing = P_RandomRange(0, 90); + if (facing >= 45) + facing = InvAngle((facing - 45)*ANG1); + else + facing *= ANG1; + + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->spawnpoint->x<spawnpoint->y<extravalue1) + { + fixed_t mx = P_ReturnThrustX(NULL, mobj->angle, 32*mobj->scale); + fixed_t my = P_ReturnThrustY(NULL, mobj->angle, 32*mobj->scale); + mobj_t *explosion = P_SpawnMobj(mobj->x + (2*mx), mobj->y + (2*my), mobj->z+(mobj->height/2), MT_THOK); + + P_SetMobjState(explosion, S_FZEROBOOM1); + explosion->scale = mobj->scale*2; + explosion->momx = mx; + explosion->momy = my; + + S_StartSound(mobj, mobj->info->seesound); + mobj->extravalue1 = 1; + } + + if (!S_SoundPlaying(mobj, mobj->info->attacksound)) + S_StartSound(mobj, mobj->info->attacksound); + + if (mobj->extravalue2 > 70) // fire + smoke pillar + { + UINT8 i; + mobj_t *fire = P_SpawnMobj(mobj->x + (P_RandomRange(-32, 32)*mobj->scale), mobj->y + (P_RandomRange(-32, 32)*mobj->scale), mobj->z, MT_THOK); + + fire->sprite = SPR_FPRT; + fire->frame = FF_FULLBRIGHT|FF_TRANS30; + fire->scale = mobj->scale*4; + fire->momz = P_RandomRange(2, 3)*mobj->scale; + fire->scalespeed = mobj->scale/12; + fire->destscale = 1; + fire->tics = TICRATE; + + for (i = 0; i < 2; i++) + { + mobj_t *smoke = P_SpawnMobj(mobj->x + (P_RandomRange(-16, 16)*mobj->scale), mobj->y + (P_RandomRange(-16, 16)*mobj->scale), mobj->z, MT_SMOKE); + + P_SetMobjState(smoke, S_FZSLOWSMOKE1); + smoke->scale = mobj->scale; + smoke->momz = P_RandomRange(3, 10)*mobj->scale; + smoke->destscale = mobj->scale*4; + smoke->scalespeed = mobj->scale/24; + } + } + else + { + mobj->extravalue2++; // flametimer + + if (mobj->extravalue2 > 8) + { + mobj_t *smoke = P_SpawnMobj(mobj->x + (P_RandomRange(-31, 31)*mobj->scale), mobj->y + (P_RandomRange(-31, 31)*mobj->scale), + mobj->z + (P_RandomRange(0, 48)*mobj->scale), MT_THOK); + + P_SetMobjState(smoke, S_FZEROSMOKE1); + smoke->tics += P_RandomRange(-3, 4); + smoke->scale = mobj->scale*2; + } + } + break; + case MT_EZZPROPELLER: + if (mobj->hnext) + { + mobj_t *cur = mobj->hnext; + + while (cur && !P_MobjWasRemoved(cur)) + { + cur->angle += FixedAngle(mobj->info->speed); + P_TeleportMove(cur, mobj->x + FINECOSINE((cur->angle*8)>>ANGLETOFINESHIFT), + mobj->y + FINESINE((cur->angle*8)>>ANGLETOFINESHIFT), mobj->z); + //P_SpawnGhostMobj(cur)->tics = 2; + + cur = cur->hnext; + } + } + if (!S_SoundPlaying(mobj, mobj->info->seesound)) + S_StartSound(mobj, mobj->info->seesound); + break; + case MT_FROGGER: + { + statenum_t frogstate = (mobj->state-states); + + // FROG ATTACK VALUES: + // threshold: distance + // movecount: time + // lastlook: direction + // extravalue1: x step + // extravalue2: y step + // cusval: z step + + if (frogstate == S_FROGGER) + { + mobj->threshold = mobj->movecount = mobj->lastlook = 0; // clear tongue attack + mobj->extravalue1 = mobj->extravalue2 = mobj->cusval = 0; + if (mobj->hnext) // Clean hnext list + { + mobj_t *cur = mobj->hnext; + while (cur && !P_MobjWasRemoved(cur)) + { + mobj_t *next = cur->hnext; + P_RemoveMobj(cur); + cur = next; + } + } + + if (mobj->reactiontime) + mobj->reactiontime--; + else + { + if (mobj->flags2 & MF2_AMBUSH) + { + mobj->momz = P_RandomRange(12, 16)<x, mobj->y, mobj->z + (mobj->height/2), MT_FROGTONGUE); + P_SetTarget(&mobj->tracer, tongue); + P_SetMobjState(mobj, S_FROGGER_ATTACK); + } + } + } + else if (frogstate == S_FROGGER_ATTACK) + { + if (!mobj->tracer || P_MobjWasRemoved(mobj->tracer)) + { + mobj->reactiontime = mobj->info->reactiontime; + P_SetMobjState(mobj, S_FROGGER); + break; + } + + if (mobj->threshold == 0) + { + fixed_t targetz = mobj->tracer->z; //mobj->z + (mobj->height/2) + + mobj->threshold = 256; + mobj->movecount = 1; + mobj->lastlook = 1; + + mobj->tracer->angle = mobj->angle; + + mobj->extravalue1 = FixedMul(FixedMul((mobj->threshold/16)<>ANGLETOFINESHIFT)), + FINECOSINE(mobj->angle>>ANGLETOFINESHIFT)) >> FRACBITS; + + mobj->extravalue2 = FixedMul(FixedMul((mobj->threshold/16)<>ANGLETOFINESHIFT)), + FINESINE(mobj->angle>>ANGLETOFINESHIFT)) >> FRACBITS; + + mobj->cusval = FixedMul((mobj->threshold/16)<>ANGLETOFINESHIFT)) >> FRACBITS; + + S_StartSound(mobj, sfx_s3k8c); // Play that tongue-y sound. + } + + mobj->movecount += mobj->lastlook; + + if (!(P_TryMove(mobj->tracer, mobj->x + ((mobj->extravalue1<movecount), mobj->y + ((mobj->extravalue2<movecount), true)) + || (mobj->movecount >= 16) // maximum travel time + || (mobj->tracer->z <= mobj->tracer->floorz) // Through the floor + || ((mobj->tracer->z + mobj->tracer->height) >= mobj->tracer->ceilingz)) // Through the ceiling + { + mobj->lastlook = -1; // Reverse direction. + } + + if (mobj->movecount == 0) // It's back to its source, time to reset. + { + mobj->threshold = mobj->lastlook = 0; + + P_RemoveMobj(mobj->tracer); + + if (mobj->hnext) // Clean hnext list + { + mobj_t *cur = mobj->hnext; + while (cur && !P_MobjWasRemoved(cur)) + { + mobj_t *next = cur->hnext; + P_RemoveMobj(cur); + cur = next; + } + } + + mobj->reactiontime = mobj->info->reactiontime; + P_SetMobjState(mobj, S_FROGGER); + } + else + { + const UINT8 numjoints = 11; + UINT8 joint = numjoints; + mobj_t *cur = mobj->hnext, *prev = mobj; + + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->tracer->x, mobj->tracer->y); + + for (; joint > 0; joint--) + { + fixed_t wx = mobj->tracer->x + (joint * (mobj->x - mobj->tracer->x) / (numjoints+1)); + fixed_t wy = mobj->tracer->y + (joint * (mobj->y - mobj->tracer->y) / (numjoints+1)); + fixed_t wz = mobj->tracer->z + (joint * ((mobj->z + (mobj->height/2)) - mobj->tracer->z) / (numjoints+1)); + + if (cur && !P_MobjWasRemoved(cur)) + P_TeleportMove(cur, wx, wy, wz); + else + cur = P_SpawnMobj(wx, wy, wz, MT_FROGTONGUE_JOINT); + + P_SetTarget(&cur->target, mobj); + + P_SetTarget(&prev->hnext, cur); + P_SetTarget(&cur->hprev, prev); + + prev = cur; + cur = cur->hnext; + } + } + } + else if (frogstate == S_FROGGER_JUMP) + { + if (P_IsObjectOnGround(mobj)) + { + mobj->reactiontime = mobj->info->reactiontime; + P_SetMobjState(mobj, S_FROGGER); + } + } + } + break; + case MT_ROBRA: + case MT_BLUEROBRA: + if (mobj->health) + { + boolean blue = (mobj->type == MT_BLUEROBRA); + + if (blue) + { + if (mobj->spawnpoint) + mobj->extravalue2 = mobj->spawnpoint->angle; + else + mobj->extravalue2 = 128; + } + else + { + if (!mobj->extravalue2) + mobj->extravalue2 = P_RandomRange(64, 192); + } + + if (mobj->reactiontime) + mobj->reactiontime--; + else + { + if (!mobj->extravalue1) + { + mobj_t *head = P_SpawnMobj(mobj->x, mobj->y, mobj->z, (blue ? MT_BLUEROBRA_HEAD : MT_ROBRA_HEAD)); + P_SetTarget(&mobj->tracer, head); + + mobj->destscale = mapheaderinfo[gamemap-1]->mobj_scale; + P_SetTarget(&mobj->tracer->target, mobj->target); + P_SetTarget(&mobj->tracer->tracer, mobj); + mobj->tracer->extravalue2 = mobj->extravalue2; + + if (!blue) + mobj->tracer->angle = mobj->angle; + + mobj->extravalue1 = 1; + } + } + + if ((mobj->extravalue1) && !(mobj->tracer && !P_MobjWasRemoved(mobj->tracer))) + { + mobj->reactiontime = 20*mobj->info->reactiontime; + P_SetTarget(&mobj->target, NULL); + mobj->extravalue1 = 0; + } + + if ((mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) && !(leveltime % 10)) + { + mobj_t *dust = P_SpawnMobj(mobj->x + (P_RandomRange(-4, 4)<y + (P_RandomRange(-4, 4)<z + (P_RandomRange(0, 2)<scale/2); + P_InstaThrust(dust, FixedAngle(P_RandomRange(0,359)<tracer->momz)/2); + + if (abs(mobj->tracer->momz) >= 2<health) + { + boolean blue = (mobj->type == MT_BLUEROBRA_HEAD); + UINT8 numsegs = abs(mobj->z - mobj->floorz) / (32 * mobj->scale); + UINT8 i; + mobj_t *cur = mobj->hnext, *prev = mobj; + + if (blue) + mobj->angle = (angle_t)mobj->extravalue1; + mobj->extravalue1 += (FixedAngle(2*mobj->momz) * (blue ? -1 : 1)); + + for (i = 0; i < numsegs*2; i++) // *2 to check for any extra segs still present + { + fixed_t segz = mobj->z - ((i+1) * (32 * mobj->scale)); + + if (cur && !P_MobjWasRemoved(cur)) + { + if (i >= numsegs) // Remove extras + { + mobj_t *next = cur->hnext; + P_RemoveMobj(cur); + cur = next; + continue; + } + else // Move into place + P_TeleportMove(cur, mobj->x, mobj->y, segz); + } + else + { + if (i >= numsegs) // We're done with this list + continue; //break; + else // Need another here! + cur = P_SpawnMobj(mobj->x, mobj->y, segz, (blue ? MT_BLUEROBRA_JOINT : MT_ROBRA_JOINT)); + } + + P_SetTarget(&cur->target, mobj); + P_SetScale(cur, (7*mobj->scale)/8); + + cur->angle = mobj->extravalue1; + mobj->extravalue1 += (FixedAngle(2*mobj->momz) * (blue ? -1 : 1)); + + P_SetTarget(&prev->hnext, cur); + P_SetTarget(&cur->hprev, prev); + + prev = cur; + cur = cur->hnext; + } + + { + //fixed_t ceilingheight = mobj->ceilingz - (72<floorz + (72<floorz + (mobj->extravalue2<z < targetheight) + { + mobj->momz += mobj->info->speed; + if ((mobj->z < floorheight) && (mobj->momz < 0)) + mobj->momz /= 2; + } + else + { + mobj->momz -= mobj->info->speed; + if ((mobj->z > (targetheight + (64<momz > 0)) + mobj->momz /= 2; + } + } + } + break; + case MT_ROBRA_JOINT: + case MT_BLUEROBRA_JOINT: + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + P_RemoveMobj(mobj); + return; + } + break; + case MT_SMK_PIPE: + if (mobj->flags2 & MF2_AMBUSH) + P_SetMobjStateNF(mobj, mobj->info->seestate); + else + P_SetMobjStateNF(mobj, mobj->info->spawnstate); + break; + case MT_SMK_MOLESPAWNER: + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + mobj_t *newmole = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_MOLE); + P_SetTarget(&mobj->target, newmole); + return; + } + break; + case MT_SMK_MOLE: + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + player_t *player = mobj->target->player; + + mobj->extravalue1 = 1; + player->kartstuff[k_offroad] += 2<mo->x + P_ReturnThrustX(NULL, player->mo->angle, player->mo->radius) + + P_ReturnThrustX(NULL, player->mo->angle+ANGLE_90, (mobj->threshold)<mo->y + P_ReturnThrustY(NULL, player->mo->angle, player->mo->radius) + + P_ReturnThrustY(NULL, player->mo->angle+ANGLE_90, (mobj->threshold)<mo->z + (player->mo->height/2 * P_MobjFlip(player->mo)) + + (P_RandomRange(-abs(mobj->threshold), abs(mobj->threshold))<threshold /= 2; + mobj->momz = 0; + + if (mobj->movecount > 8*TICRATE) + { + P_KillMobj(mobj, mobj->target, mobj->target); + break; + } + + if (abs(player->cmd.driftturn) > 100) + { + INT32 lastsign = 0; + if (mobj->lastlook > 0) + lastsign = 1; + else if (mobj->lastlook < 0) + lastsign = -1; + + if ((player->cmd.driftturn > 0 && lastsign < 0) + || (player->cmd.driftturn < 0 && lastsign > 0)) + { + mobj->movecount += (TICRATE/2); + mobj->threshold = 16*lastsign; + S_StartSound(mobj, sfx_s1ab); + } + + mobj->lastlook = player->cmd.driftturn; + } + + mobj->movecount++; + } + else if (mobj->extravalue1) // lost your player somehow, DIE + { + P_KillMobj(mobj, NULL, NULL); + break; + } + else + { + if (P_IsObjectOnGround(mobj)) + { + if (mobj->reactiontime) + mobj->reactiontime--; + else + { + mobj->momz = (mobj->info->speed * P_MobjFlip(mobj)); + mobj->reactiontime = mobj->info->reactiontime; + } + } + } + break; + case MT_SMK_THWOMP: + if (mobj->flags2 & MF2_AMBUSH) + { + mobj->colorized = true; + mobj->color = (1 + (leveltime % (MAXSKINCOLORS-1))); + mobj->frame |= FF_FULLBRIGHT; + } + else + { + mobj->colorized = false; + mobj->color = SKINCOLOR_NONE; + mobj->frame &= (~FF_FULLBRIGHT); + } + + if (!thwompsactive) + break; + + if (mobj->reactiontime) + mobj->reactiontime--; + else + { + if (mobj->extravalue1) + { + P_SpawnGhostMobj(mobj)->tics = 3; + + if (mobj->z == mobj->floorz) + { + UINT8 i; + + mobj->extravalue1 = 0; + mobj->reactiontime = mobj->info->reactiontime; + S_StartSound(mobj, sfx_s1bd); + + for (i = 0; i < 8; i++) + { + mobj_t *dust = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_DRIFTDUST); + P_InstaThrust(dust, FixedAngle(((360*FRACUNIT)/8) * i), mobj->info->speed/8); + dust->momz = P_MobjFlip(mobj) * (P_RandomRange(1,4)<scale = mobj->scale/2; + dust->destscale = mobj->scale*3; + } + } + else + mobj->momz = (-mobj->info->speed) * P_MobjFlip(mobj); + } + else + { + if (mobj->z > mobj->movefactor) + mobj->z = mobj->movefactor; + + if (mobj->z == mobj->movefactor) + { + mobj->extravalue1 = 1; + //S_StartSound(mobj, sfx_s1bb); + } + else + mobj->momz = (mobj->info->speed/16) * P_MobjFlip(mobj); + } + } + break; //} case MT_TURRET: P_MobjCheckWater(mobj); @@ -8748,6 +9372,31 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s return; case MT_PLAYER: break; // don't remove + case MT_SMK_ICEBLOCK: + { + mobj_t *cur = mobj->hnext, *next; + UINT8 i; + + for (i = 0; i < 5; i++) + { + mobj_t *debris = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_ICEBLOCK_DEBRIS); + debris->angle = FixedAngle(P_RandomRange(0,360)<angle, P_RandomRange(3,18)*(FRACUNIT/4)); + debris->momz = P_RandomRange(4,8)<hnext; + P_RemoveMobj(cur); + cur = next; + } + + P_RemoveMobj(mobj); + return; + } default: P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. break; @@ -8755,7 +9404,7 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s if (P_MobjWasRemoved(mobj)) return; } - else if (((mobj->type == MT_RANDOMITEM && mobj->threshold == 69) || mobj->type == MT_FAKEITEM) && mobj->fuse <= TICRATE) + else if (((mobj->type == MT_RANDOMITEM && mobj->threshold == 69) || mobj->type == MT_EGGMANITEM || mobj->type == MT_FALLINGROCK) && mobj->fuse <= TICRATE) mobj->flags2 ^= MF2_DONTDRAW; } @@ -9089,7 +9738,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // All mobjs are created at 100% scale. mobj->scale = FRACUNIT; mobj->destscale = mobj->scale; - mobj->scalespeed = FRACUNIT/12; + mobj->scalespeed = mapheaderinfo[gamemap-1]->mobj_scale/12; if (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->mobj_scale != FRACUNIT) //&& !(mobj->type == MT_BLACKEGGMAN) mobj->destscale = mapheaderinfo[gamemap-1]->mobj_scale; @@ -9256,7 +9905,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BLUEBALL: nummaprings++; break; - case MT_KARMAHITBOX: // SRB2Kart + // SRB2Kart + case MT_KARMAHITBOX: { const fixed_t rad = FixedMul(mobjinfo[MT_PLAYER].radius, mobj->scale); mobj_t *cur, *prev = mobj; @@ -9323,6 +9973,109 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->color = SKINCOLOR_AQUA; break; } + case MT_MARBLETORCH: + P_SpawnMobj(mobj->x, mobj->y, mobj->z + (29*mobj->scale), MT_MARBLELIGHT); + break; + case MT_RUSTYLAMP_ORANGE: + P_SpawnMobj(mobj->x, mobj->y, mobj->z + (69*mobj->scale), MT_MARBLELIGHT); + break; + case MT_PINETREE: + { + angle_t diff = FixedAngle((360/mobj->info->mass)*FRACUNIT); + UINT8 i; + + for (i = 0; i < mobj->info->mass; i++) + { + angle_t ang = i * diff; + mobj_t *side = P_SpawnMobj(mobj->x + FINECOSINE((ang>>ANGLETOFINESHIFT) & FINEMASK), + mobj->y + FINESINE((ang>>ANGLETOFINESHIFT) & FINEMASK), mobj->z, MT_PINETREE_SIDE); + side->angle = ang; + side->target = mobj; + side->threshold = i; + } + break; + } + case MT_EZZPROPELLER: + { + mobj_t *cur, *prev = mobj; + UINT8 i; + + for (i = 0; i < mobj->info->mass; i++) + { + mobj->angle = FixedAngle((i * (360/mobj->info->mass))<x + FINECOSINE(((mobj->angle*8)>>ANGLETOFINESHIFT) & FINEMASK), + mobj->y + FINESINE(((mobj->angle*8)>>ANGLETOFINESHIFT) & FINEMASK), mobj->z, MT_EZZPROPELLER_BLADE); + cur->angle = mobj->angle; + + P_SetTarget(&cur->hprev, prev); + P_SetTarget(&prev->hnext, cur); + + prev = cur; + } + break; + } + case MT_ROBRA: + case MT_BLUEROBRA: + P_SetScale(mobj, (mobj->destscale = 1)); + break; + case MT_ROBRA_HEAD: + { + mobj_t *shell; + + shell = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + P_SetTarget(&shell->target, mobj); + P_SetMobjState(shell, S_ROBRASHELL_INSIDE); + + shell = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + P_SetTarget(&shell->target, mobj); + P_SetMobjState(shell, S_ROBRASHELL_OUTSIDE); + } + break; + case MT_EERIEFOGGEN: + { + UINT16 i; + for (i = 0; i < mobj->info->mass; i++) + { + fixed_t newx = mobj->x + (P_RandomRange(-mobj->info->mass, mobj->info->mass)<y + (P_RandomRange(-mobj->info->mass, mobj->info->mass)<z, 8<z) + P_SpawnMobj(newx, newy, mobj->z, MT_EERIEFOG); + } + } + break; + case MT_SMK_MOLE: + mobj->reactiontime = P_RandomRange(0, 3*mobj->info->reactiontime/2); // Random delay on start of level + break; + case MT_SMK_THWOMP: + mobj->reactiontime = P_RandomRange(0, 3*mobj->info->reactiontime); // Random delay on start of level + if (mobj->z == mobj->floorz) + mobj->z += (256<movefactor = mobj->z + (256<flags2 |= MF2_STANDONME; + { + mobj_t *cur, *prev = mobj; + UINT8 i; + + for (i = 0; i < 4; i++) + { + cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_ICEBLOCK_SIDE); + P_SetTarget(&cur->target, mobj); + cur->threshold = i; + P_TeleportMove(cur, cur->x + ((cur->radius>>FRACBITS) * FINECOSINE((FixedAngle((90*cur->threshold)<>ANGLETOFINESHIFT) & FINEMASK)), + cur->y + ((cur->radius>>FRACBITS) * FINESINE((FixedAngle((90*cur->threshold)<>ANGLETOFINESHIFT) & FINEMASK)), cur->z); + cur->angle = ANGLE_90*(cur->threshold+1); + + P_SetTarget(&cur->hprev, prev); + P_SetTarget(&prev->hnext, cur); + + prev = cur; + } + } + break; default: break; } @@ -9330,18 +10083,21 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) switch (mobj->type) { case MT_PLAYER: - case MT_BIGMACE: case MT_SMALLMACE: + case MT_SMALLMACE: case MT_BIGMACE: + case MT_PUMA: case MT_BIGPUMA: case MT_FALLINGROCK: + case MT_SMK_MOLE: case MT_SMK_THWOMP: //case MT_RANDOMITEM: case MT_FLOATINGITEM: case MT_BATTLEBUMPER: case MT_BANANA: case MT_BANANA_SHIELD: - //case MT_FAKEITEM: case MT_FAKESHIELD: + //case MT_EGGMANITEM: case MT_EGGMANSHIELD: case MT_ORBINAUT: case MT_ORBINAUT_SHIELD: - case MT_JAWZ: case MT_JAWZ_DUD: case MT_JAWZ_SHIELD: - case MT_SSMINE: case MT_SSMINE_SHIELD: - case MT_BALLHOG: case MT_SINK: - case MT_THUNDERSHIELD: + case MT_JAWZ: case MT_JAWZ_DUD: case MT_JAWZ_SHIELD: + case MT_SSMINE: case MT_SSMINE_SHIELD: + case MT_BALLHOG: case MT_SINK: + case MT_THUNDERSHIELD: case MT_ROCKETSNEAKER: + case MT_SPB: P_SpawnShadowMobj(mobj); default: break; @@ -9429,7 +10185,7 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster) // All mobjs are created at 100% scale. mobj->scale = FRACUNIT; mobj->destscale = mobj->scale; - mobj->scalespeed = FRACUNIT/12; + mobj->scalespeed = mapheaderinfo[gamemap-1]->mobj_scale/12; if (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->mobj_scale != FRACUNIT) //&& !(mobj->type == MT_BLACKEGGMAN) mobj->destscale = mapheaderinfo[gamemap-1]->mobj_scale; @@ -10094,6 +10850,8 @@ void P_SpawnPlayer(INT32 playernum) continue; if (!playeringame[i] || players[i].spectator) continue; + if (players[i].jointime <= 1) // Prevent splitscreen hosters/joiners from only adding 1 player at a time in empty servers + continue; pcount++; } @@ -10980,6 +11738,50 @@ ML_NOCLIMB : Direction not controllable case MT_TRAPGOYLELONG: if (mthing->angle >= 360) mobj->tics += 7*(mthing->angle / 360) + 1; // starting delay + break; + // SRB2Kart + case MT_BALLOON: + if (mthing->angle < MAXSKINCOLORS && mthing->angle > 0) + mobj->color = mthing->angle; + break; + case MT_AAZTREE_HELPER: + { + fixed_t top = mobj->z; + UINT8 numsegs = (mthing->extrainfo)+2; + UINT8 numleaves = max(3, (abs(mthing->angle+1) % 6) + 3); + UINT8 i; + mobj_t *coconut; + + // Spawn tree segments + for (i = 0; i < numsegs; i++) + { + P_SpawnMobj(mobj->x, mobj->y, top, MT_AAZTREE_SEG); + top += FixedMul(mobjinfo[MT_AAZTREE_SEG].height, mobj->scale); + } + + // Big coconut topper + coconut = P_SpawnMobj(mobj->x, mobj->y, top - (8<destscale = (2*mobj->scale))); + + // Spawn all of the papersprite leaves + for (i = 0; i < numleaves; i++) + { + mobj_t *leaf; + + mobj->angle = FixedAngle((i * (360/numleaves))<x + FINECOSINE((mobj->angle>>ANGLETOFINESHIFT) & FINEMASK), + mobj->y + FINESINE((mobj->angle>>ANGLETOFINESHIFT) & FINEMASK), top, MT_AAZTREE_LEAF); + leaf->angle = mobj->angle; + + // Small coconut for each leaf + P_SpawnMobj(mobj->x + (32 * FINECOSINE((mobj->angle>>ANGLETOFINESHIFT) & FINEMASK)), + mobj->y + (32 * FINESINE((mobj->angle>>ANGLETOFINESHIFT) & FINEMASK)), top - (24<info->seestate + (i & 1)); + //if (maptol & TOL_XMAS) + //P_SetMobjState(mobj, mobj->info->seestate + (i & 1)); mobj->z -= mobj->height/2; P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center. @@ -11319,8 +12121,10 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Link all the sprites in the hoop together if (nextmobj) { - mobj->hprev = nextmobj; - mobj->hprev->hnext = mobj; + P_SetTarget(&mobj->hprev, nextmobj); + P_SetTarget(&mobj->hprev->hnext, mobj); + //mobj->hprev = nextmobj; + //mobj->hprev->hnext = mobj; } else mobj->hprev = mobj->hnext = NULL; @@ -11350,8 +12154,10 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Link all the collision sprites together. mobj->hnext = NULL; - mobj->hprev = nextmobj; - mobj->hprev->hnext = mobj; + P_SetTarget(&mobj->hprev, nextmobj); + P_SetTarget(&mobj->hprev->hnext, mobj); + //mobj->hprev = nextmobj; + //mobj->hprev->hnext = mobj; nextmobj = mobj; } @@ -11377,8 +12183,10 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Link all the collision sprites together. mobj->hnext = NULL; - mobj->hprev = nextmobj; - mobj->hprev->hnext = mobj; + P_SetTarget(&mobj->hprev, nextmobj); + P_SetTarget(&mobj->hprev->hnext, mobj); + //mobj->hprev = nextmobj; + //mobj->hprev->hnext = mobj; nextmobj = mobj; } @@ -11451,8 +12259,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP); - if (maptol & TOL_XMAS) - P_SetMobjState(mobj, mobj->info->seestate + (i & 1)); + //if (maptol & TOL_XMAS) + //P_SetMobjState(mobj, mobj->info->seestate + (i & 1)); mobj->z -= mobj->height/2; P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center. @@ -11461,8 +12269,10 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Link all the sprites in the hoop together if (nextmobj) { - mobj->hprev = nextmobj; - mobj->hprev->hnext = mobj; + P_SetTarget(&mobj->hprev, nextmobj); + P_SetTarget(&mobj->hprev->hnext, mobj); + //mobj->hprev = nextmobj; + //mobj->hprev->hnext = mobj; } else mobj->hprev = mobj->hnext = NULL; @@ -11503,8 +12313,10 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) // Link all the collision sprites together. mobj->hnext = NULL; - mobj->hprev = nextmobj; - mobj->hprev->hnext = mobj; + P_SetTarget(&mobj->hprev, nextmobj); + P_SetTarget(&mobj->hprev->hnext, mobj); + //mobj->hprev = nextmobj; + //mobj->hprev->hnext = mobj; nextmobj = mobj; } @@ -11512,6 +12324,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) return; } + else return; // srb2kart - no rings or ring-like objects in R1 + /* // Wing logo item. else if (mthing->type == mobjinfo[MT_NIGHTSWING].doomednum) { @@ -11805,7 +12619,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing) } } return; - } + }*/ } // diff --git a/src/p_saveg.c b/src/p_saveg.c index df76497d..1b4314b8 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1116,7 +1116,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff |= MD_SCALE; if (mobj->destscale != mobj->scale) diff |= MD_DSCALE; - if (mobj->scalespeed != FRACUNIT/12) + if (mobj->scalespeed != mapheaderinfo[gamemap-1]->mobj_scale/12) diff2 |= MD2_SCALESPEED; if (mobj == redflag) @@ -2123,7 +2123,7 @@ static void LoadMobjThinker(actionf_p1 thinker) if (diff2 & MD2_SCALESPEED) mobj->scalespeed = READFIXED(save_p); else - mobj->scalespeed = FRACUNIT/12; + mobj->scalespeed = mapheaderinfo[gamemap-1]->mobj_scale/12; if (diff2 & MD2_CUSVAL) mobj->cusval = READINT32(save_p); if (diff2 & MD2_CVMEM) @@ -3284,9 +3284,9 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, wantedcalcdelay); WRITEUINT32(save_p, indirectitemcooldown); - WRITEUINT32(save_p, spbincoming); - WRITEUINT8(save_p, spbplayer); WRITEUINT32(save_p, mapreset); + WRITEUINT8(save_p, nospectategrief); + WRITEUINT8(save_p, thwompsactive); // Is it paused? if (paused) @@ -3390,9 +3390,9 @@ static inline boolean P_NetUnArchiveMisc(void) wantedcalcdelay = READUINT32(save_p); indirectitemcooldown = READUINT32(save_p); - spbincoming = READUINT32(save_p); - spbplayer = READUINT8(save_p); mapreset = READUINT32(save_p); + nospectategrief = READUINT8(save_p); + thwompsactive = (boolean)READUINT8(save_p); // Is it paused? if (READUINT8(save_p) == 0x2f) diff --git a/src/p_setup.c b/src/p_setup.c index a606dca0..a40bdbe0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2209,7 +2209,7 @@ static void P_LevelInitStuff(void) players[i].lives = cv_startinglives.value; } #else - players[i].lives = 1; + players[i].lives = 1; // SRB2Kart #endif players[i].realtime = countdown = countdown2 = 0; @@ -3023,9 +3023,9 @@ boolean P_SetupLevel(boolean skipprecip) wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0; - spbincoming = 0; - spbplayer = 0; mapreset = 0; + nospectategrief = 0; + thwompsactive = false; // clear special respawning que iquehead = iquetail = 0; @@ -3210,7 +3210,6 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname) HU_LoadGraphics(); ST_LoadGraphics(); ST_ReloadSkinFaceGraphics(); - K_ReloadSkinIconGraphics(); // // look for skins diff --git a/src/p_spec.c b/src/p_spec.c index 50aa9188..651f3b20 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -36,6 +36,7 @@ #include "lua_hook.h" // LUAh_LinedefExecute #include "k_kart.h" // SRB2kart +#include "console.h" // CON_LogMessage #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -3218,7 +3219,7 @@ void P_SetupSignExit(player_t *player) // SRB2Kart: Set sign spinning variables thing->movefactor = thing->z; - thing->z += (768<z += (768*thing->scale) * P_MobjFlip(thing); thing->movecount = 1; ++numfound; @@ -3246,7 +3247,7 @@ void P_SetupSignExit(player_t *player) // SRB2Kart: Set sign spinning variables thing->movefactor = thing->z; - thing->z += (768<z += (768*thing->scale) * P_MobjFlip(thing); thing->movecount = 1; ++numfound; @@ -3258,7 +3259,7 @@ void P_SetupSignExit(player_t *player) // SRB2Kart: FINALLY, add in an alternative if no place is found if (player->mo) { - mobj_t *sign = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + (768<mo->x, player->mo->y, player->mo->z + (768*mapheaderinfo[gamemap-1]->mobj_scale), MT_SIGN); P_SetTarget(&sign->target, player->mo); P_SetMobjState(sign, S_SIGN1); @@ -4022,7 +4023,7 @@ DoneSection2: player->kartstuff[k_floorboost] = 3; else player->kartstuff[k_floorboost] = 2; - K_DoSneaker(player, false); + K_DoSneaker(player, 0); } break; @@ -4195,21 +4196,41 @@ DoneSection2: { if (player->starpostcount >= numstarposts/2) // srb2kart: must have touched *enough* starposts (was originally "(player->starpostnum == numstarposts)") { + UINT8 i; + UINT8 nump = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + nump++; + } + player->laps++; + + // Set up lap animation vars + if (nump > 1) + { + if (K_IsPlayerLosing(player)) + player->kartstuff[k_laphand] = 3; + else + { + if (nump > 2 && player->kartstuff[k_position] == 1) // 1st place in 1v1 uses thumbs up + player->kartstuff[k_laphand] = 1; + else + player->kartstuff[k_laphand] = 2; + } + } + else + player->kartstuff[k_laphand] = 0; // No hands in FREE PLAY + player->kartstuff[k_lapanimation] = 80; if (player->pflags & PF_NIGHTSMODE) player->drillmeter += 48*20; - if (netgame) - { - if (player->laps >= (UINT8)cv_numlaps.value) - CONS_Printf(M_GetText("%s has finished the race.\n"), player_names[player-players]); - else if (player->laps == (UINT8)(cv_numlaps.value - 1)) - CONS_Printf("%s started the final lap\n", player_names[player-players]); - else - CONS_Printf(M_GetText("%s started lap %u\n"), player_names[player-players], (UINT32)player->laps+1); - } + 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]) @@ -4235,12 +4256,17 @@ DoneSection2: S_StartSound(NULL, sfx_s221); } - // //player->starpostangle = player->starposttime = player->starpostnum = 0; //player->starpostx = player->starposty = player->starpostz = 0; // Play the starpost sound for 'consistency' // S_StartSound(player->mo, sfx_strpst); + + // Figure out how many are playing on the last lap, to prevent spectate griefing + if (!nospectategrief && player->laps >= (UINT8)(cv_numlaps.value - 1)) + nospectategrief = nump; + + thwompsactive = true; // Lap 2 effects } else if (player->starpostnum) { diff --git a/src/p_tick.c b/src/p_tick.c index 9b59e70d..e2a1bb4b 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -678,38 +678,6 @@ void P_Ticker(boolean run) if (countdown2) countdown2--; - if (spbincoming && --spbincoming <= 0) - { - UINT8 best = 0; - SINT8 hurtthisguy = -1; - - spbincoming = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo) - continue; - - if (players[i].exiting) - continue; - - if (best <= 0 || players[i].kartstuff[k_position] < best) - { - best = players[i].kartstuff[k_position]; - hurtthisguy = i; - } - } - - if (hurtthisguy != -1) - { - players[hurtthisguy].kartstuff[k_deathsentence] = (2*TICRATE)+1; - S_StartSound(players[hurtthisguy].mo, sfx_kc57); - } - } - if (indirectitemcooldown) indirectitemcooldown--; diff --git a/src/p_user.c b/src/p_user.c index 472d7c27..a2d07843 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -45,6 +45,7 @@ // SRB2kart #include "m_cond.h" // M_UpdateUnlockablesAndExtraEmblems #include "k_kart.h" +#include "console.h" // CON_LogMessage #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -845,7 +846,8 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) fixed_t fallbackspeed; if (inflictor && (inflictor->type != MT_PLAYER && inflictor->type != MT_ORBINAUT && inflictor->type != MT_ORBINAUT_SHIELD - && inflictor->type != MT_JAWZ && inflictor->type != MT_JAWZ_DUD && inflictor->type != MT_JAWZ_SHIELD)) + && inflictor->type != MT_JAWZ && inflictor->type != MT_JAWZ_DUD && inflictor->type != MT_JAWZ_SHIELD + && inflictor->type != MT_SMK_THWOMP)) { if (player->mo->eflags & MFE_VERTICALFLIP) player->mo->z--; @@ -1139,34 +1141,57 @@ boolean P_EndingMusic(player_t *player) { char buffer[9]; boolean looping = true; + INT32 bestlocalpos; + player_t *bestlocalplayer; if (!P_IsLocalPlayer(player)) // Only applies to a local player return false; // Event - Level Finish - if (splitscreen - && (players[displayplayer].exiting - || players[secondarydisplayplayer].exiting - || ((splitscreen < 2) && players[thirddisplayplayer].exiting) - || ((splitscreen < 3) && players[fourthdisplayplayer].exiting))) + // Check for if this is valid or not + if (splitscreen) { - sprintf(buffer, "k*ok"); + if (!((players[displayplayer].exiting || (players[displayplayer].pflags & PF_TIMEOVER)) + || (players[secondarydisplayplayer].exiting || (players[secondarydisplayplayer].pflags & PF_TIMEOVER)) + || ((splitscreen < 2) && (players[thirddisplayplayer].exiting || (players[thirddisplayplayer].pflags & PF_TIMEOVER))) + || ((splitscreen < 3) && (players[fourthdisplayplayer].exiting || (players[fourthdisplayplayer].pflags & PF_TIMEOVER))))) + return false; + + bestlocalplayer = &players[displayplayer]; + bestlocalpos = ((players[displayplayer].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[displayplayer].kartstuff[k_position]); +#define setbests(p) \ + if (((players[p].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[p].kartstuff[k_position]) < bestlocalpos) \ + { \ + bestlocalplayer = &players[p]; \ + bestlocalpos = ((players[p].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[p].kartstuff[k_position]); \ } - else if (player->pflags & PF_TIMEOVER) // || !player->lives) -- outta lives, outta time - { - sprintf(buffer, "k*lose"); + setbests(secondarydisplayplayer); + if (splitscreen > 1) + setbests(thirddisplayplayer); + if (splitscreen > 2) + setbests(fourthdisplayplayer); +#undef setbests } - else if (player->exiting) + else { - if (player->kartstuff[k_position] == 1) + if (!(player->exiting || (player->pflags & PF_TIMEOVER))) + return false; + + bestlocalplayer = player; + bestlocalpos = ((player->pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : player->kartstuff[k_position]); + } + + if (G_RaceGametype() && bestlocalpos == MAXPLAYERS+1) + sprintf(buffer, "k*fail"); // F-Zero death results theme + else + { + if (bestlocalpos == 1) sprintf(buffer, "k*win"); - else if (K_IsPlayerLosing(player)) + else if (K_IsPlayerLosing(bestlocalplayer)) sprintf(buffer, "k*lose"); else sprintf(buffer, "k*ok"); } - else - return false; S_SpeedMusic(1.0f); @@ -1193,6 +1218,8 @@ void P_RestoreMusic(player_t *player) if (!P_IsLocalPlayer(player)) // Only applies to a local player return; + S_SpeedMusic(1.0f); + // Event - HERE COMES A NEW CHALLENGER if (mapreset) { @@ -1204,24 +1231,58 @@ void P_RestoreMusic(player_t *player) if (P_EndingMusic(player)) return; - S_SpeedMusic(1.0f); - // Event - Level Start if (leveltime < (starttime + (TICRATE/2))) S_ChangeMusicInternal((encoremode ? "estart" : "kstart"), false); //S_StopMusic(); else // see also where time overs are handled - search for "lives = 2" in this file { + INT32 wantedmus = 0; // 0 is level music, 1 is invincibility, 2 is grow + + if (splitscreen) + { + INT32 bestlocaltimer = 1; + +#define setbests(p) \ + if (players[p].playerstate == PST_LIVE) \ + { \ + if (players[p].kartstuff[k_growshrinktimer] > bestlocaltimer) \ + { wantedmus = 2; bestlocaltimer = players[p].kartstuff[k_growshrinktimer]; } \ + else if (players[p].kartstuff[k_invincibilitytimer] > bestlocaltimer) \ + { wantedmus = 1; bestlocaltimer = players[p].kartstuff[k_invincibilitytimer]; } \ + } + setbests(displayplayer); + setbests(secondarydisplayplayer); + if (splitscreen > 1) + setbests(thirddisplayplayer); + if (splitscreen > 2) + setbests(fourthdisplayplayer); +#undef setbests + } + else + { + if (player->playerstate == PST_LIVE) + { + if (player->kartstuff[k_growshrinktimer] > 1) + wantedmus = 2; + else if (player->kartstuff[k_invincibilitytimer] > 1) + wantedmus = 1; + } + } + // Item - Grow - if (player->kartstuff[k_growshrinktimer] > 1 && player->playerstate == PST_LIVE) + if (wantedmus == 2) S_ChangeMusicInternal("kgrow", true); // Item - Invincibility - else if (player->kartstuff[k_invincibilitytimer] > 1 && player->playerstate == PST_LIVE) + else if (wantedmus == 1) S_ChangeMusicInternal("kinvnc", true); else { +#if 0 // Event - Final Lap + // Still works for GME, but disabled for consistency if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value - 1)) S_SpeedMusic(1.2f); +#endif S_ChangeMusic(mapmusname, mapmusflags, true); } } @@ -6628,13 +6689,24 @@ static void P_MovePlayer(player_t *player) if (player->mo->state != &states[S_KART_SQUISH]) P_SetPlayerMobjState(player->mo, S_KART_SQUISH); } - else if (player->kartstuff[k_spinouttimer] > 0 || player->pflags & PF_SLIDING) + else if (player->pflags & PF_SLIDING) { if (player->mo->state != &states[S_KART_SPIN]) P_SetPlayerMobjState(player->mo, S_KART_SPIN); - player->frameangle -= ANGLE_22h; } + else if (player->kartstuff[k_spinouttimer] > 0) + { + INT32 speed = max(1, min(8, player->kartstuff[k_spinouttimer]/8)); + + if (player->mo->state != &states[S_KART_SPIN]) + P_SetPlayerMobjState(player->mo, S_KART_SPIN); + + if (speed == 1 && abs(player->mo->angle - player->frameangle) < ANGLE_22h) + player->frameangle = player->mo->angle; // Face forward at the end of the animation + else + player->frameangle -= (ANGLE_11hh * speed); + } else if (player->powers[pw_nocontrol] && player->pflags & PF_SKIDDOWN) { if (player->mo->state != &states[S_KART_SPIN]) @@ -7311,7 +7383,7 @@ static void P_DoZoomTube(player_t *player) fixed_t dist; boolean reverse; - player->mo->height = P_GetPlayerSpinHeight(player); + //player->mo->height = P_GetPlayerSpinHeight(player); if (player->speed > 0) reverse = false; @@ -7416,6 +7488,11 @@ static void P_DoZoomTube(player_t *player) else if (player == &players[fourthdisplayplayer]) localangle4 = player->mo->angle; } +#if 0 + if (player->mo->state != &states[S_KART_SPIN]) + P_SetPlayerMobjState(player->mo, S_KART_SPIN); + player->frameangle -= ANGLE_22h; +#endif } // @@ -7642,7 +7719,8 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) mo = (mobj_t *)think; - if (!(mo->flags & MF_SHOOTABLE) && !(mo->type == MT_EGGGUARD || mo->type == MT_MINUS)) + if (!(mo->flags & MF_SHOOTABLE) && !(mo->type == MT_EGGGUARD || mo->type == MT_MINUS + || mo->type == MT_SPB)) // Don't want to give SPB MF_SHOOTABLE, to ensure it's undamagable through other means continue; if (mo->flags & MF_MONITOR) @@ -7670,8 +7748,8 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) if (mo->type == MT_ORBINAUT || mo->type == MT_JAWZ || mo->type == MT_JAWZ_DUD || mo->type == MT_ORBINAUT_SHIELD || mo->type == MT_JAWZ_SHIELD || mo->type == MT_BANANA || mo->type == MT_BANANA_SHIELD - || mo->type == MT_FAKEITEM || mo->type == MT_FAKESHIELD - || mo->type == MT_BALLHOG) + || mo->type == MT_EGGMANITEM || mo->type == MT_EGGMANITEM_SHIELD + || mo->type == MT_BALLHOG || mo->type == MT_SPB) { if (mo->eflags & MFE_VERTICALFLIP) mo->z -= mo->height; @@ -7685,6 +7763,9 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) P_InstaThrust(mo, R_PointToAngle2(inflictor->x, inflictor->y, mo->x, mo->y)+ANGLE_90, 16*FRACUNIT); } + if (mo->type == MT_SPB) // If you destroy a SPB, you don't get the luxury of a cooldown. + indirectitemcooldown = 0; + if (mo == inflictor) // Don't nuke yourself, dummy! continue; @@ -7859,25 +7940,22 @@ void P_FindEmerald(void) // static void P_DeathThink(player_t *player) { - //ticcmd_t *cmd = &player->cmd; - //player->deltaviewheight = 0; + if (player->pflags & PF_TIMEOVER) + { + player->kartstuff[k_timeovercam]++; + if (player->mo) + { + player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP); + player->mo->flags2 |= MF2_DONTDRAW; + } + } + else + player->kartstuff[k_timeovercam] = 0; if (player->deadtimer < INT32_MAX) player->deadtimer++; - // continue logic - /*if (!(netgame || multiplayer) && player->lives <= 0) - { - if (player->deadtimer > TICRATE && (cmd->buttons & BT_BRAKE || cmd->buttons & BT_ACCELERATE || cmd->buttons & BT_DRIFT) && player->continues > 0) - G_UseContinue(); - else if (player->deadtimer >= gameovertics) - G_UseContinue(); // Even if we don't have one this handles ending the game - }*/ - // Force respawn if idle for more than 30 seconds in shooter modes. - /*if (player->deadtimer > 30*TICRATE && !G_RaceGametype()) - player->playerstate = PST_REBORN; - else if (player->lives > 0 && !G_IsSpecialStage(gamemap)*/ if (player->lives > 0 /*&& leveltime >= starttime*/) // *could* you respawn? { // SRB2kart - spawn automatically after 1 second @@ -7886,55 +7964,6 @@ static void P_DeathThink(player_t *player) : TICRATE)) // don't let them change it in record attack player->playerstate = PST_REBORN; } - /*else if ((netgame || multiplayer) && player->deadtimer == 8*TICRATE) - { - // In a net/multiplayer game, and out of lives - if (gametype == GT_COMPETITION) - { - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && !players[i].exiting && players[i].lives > 0) - break; - - if (i == MAXPLAYERS) - { - // Everyone's either done with the race, or dead. - if (!countdown2 || countdown2 > 1*TICRATE) - countdown2 = 1*TICRATE; - } - } - - // In a coop game, and out of lives - if (gametype == GT_COOP) - { - INT32 i; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && (players[i].exiting || players[i].lives > 0)) - break; - - if (i == MAXPLAYERS) - { - // They're dead, Jim. - //nextmapoverride = spstage_start; - nextmapoverride = gamemap; - countdown2 = 1*TICRATE; - skipstats = true; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i]) - players[i].score = 0; - } - - //emeralds = 0; - tokenbits = 0; - tokenlist = 0; - token = 0; - } - } - }*/ // Keep time rolling if (!(countdown2 && !countdown) && !(player->exiting || mapreset) && !(player->pflags & PF_TIMEOVER)) @@ -7958,50 +7987,6 @@ static void P_DeathThink(player_t *player) } } - /*if (G_RaceGametype() && (player->lives <= 0)) - { - // to the lose music! - if (player->deadtimer == 4*TICRATE) - P_EndingMusic(player); - // stuff below isn't for kart - // Return to level music - if (netgame) - { - if (player->deadtimer == gameovertics && P_IsLocalPlayer(player)) - S_ChangeMusic(mapmusname, mapmusflags, true); - } - else if (multiplayer) // local multiplayer only - { - if (player->deadtimer != gameovertics) - ; - // Restore the first available player's music once we're dead for long enough - // -- that is, as long as they aren't dead too - else - { - INT32 i; - - for (i = 0; i < 4; i++) - { - if (i > splitscreen) - break; - - if (i == 0 && player != &players[displayplayer] && players[displayplayer].lives > 0) - P_RestoreMusic(&players[displayplayer]); - else if (i == 1 && player != &players[secondarydisplayplayer] && players[secondarydisplayplayer].lives > 0) - P_RestoreMusic(&players[secondarydisplayplayer]); - else if (i == 2 && player != &players[thirddisplayplayer] && players[thirddisplayplayer].lives > 0) - P_RestoreMusic(&players[thirddisplayplayer]); - else if (i == 3 && player != &players[fourthdisplayplayer] && players[fourthdisplayplayer].lives > 0) - P_RestoreMusic(&players[fourthdisplayplayer]); - else - continue; - - break; - } - } - } - }*/ - if (!player->mo) return; @@ -8138,25 +8123,36 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall fixed_t x, y, z, dist, height, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight; fixed_t pan, xpan, ypan; INT32 camrotate; - boolean camstill, cameranoclip, lookback; + boolean camstill, lookback; + UINT8 timeover; mobj_t *mo; - subsector_t *newsubsec; fixed_t f1, f2; +#ifndef NOCLIPCAM + boolean cameranoclip; + subsector_t *newsubsec; +#endif // We probably shouldn't move the camera if there is no player or player mobj somehow if (!player || !player->mo) return true; + // This can happen when joining + if (thiscam->subsector == NULL || thiscam->subsector->sector == NULL) + return true; + mo = player->mo; -#ifdef NOCLIPCAM - cameranoclip = true; // We like camera noclip! -#else +#ifndef NOCLIPCAM cameranoclip = ((player->pflags & (PF_NOCLIP|PF_NIGHTSMODE)) || (mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)) // Noclipping player camera noclips too!! || (leveltime < introtime)); // Kart intro cam #endif + if (player->pflags & PF_TIMEOVER) // 1 for momentum keep, 2 for turnaround + timeover = (player->kartstuff[k_timeovercam] > 2*TICRATE ? 2 : 1); + else + timeover = 0; + if (!(player->playerstate == PST_DEAD || player->exiting)) { if (player->spectator) // force cam off for spectators @@ -8215,7 +8211,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // if (leveltime > 0 && timeinmap <= 0) // return true; - if (player->pflags & PF_NIGHTSMODE) + if (demoplayback) { focusangle = mo->angle; focusaiming = 0; @@ -8286,7 +8282,12 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall lookback = camspin4; } - if (leveltime < introtime) // Whoooshy camera! + if (timeover) + { + const INT32 timeovercam = max(0, min(180, (player->kartstuff[k_timeovercam] - 2*TICRATE)*15)); + camrotate += timeovercam; + } + else if (leveltime < introtime) // Whoooshy camera! { const INT32 introcam = (introtime - leveltime); camrotate += introcam*5; @@ -8306,10 +8307,15 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (mo->eflags & MFE_VERTICALFLIP) camheight += thiscam->height; - if (camstill || resetcalled || player->playerstate == PST_DEAD) - angle = thiscam->angle; + if (splitscreen == 1) + camspeed = (3*camspeed)/4; + + if (timeover) + angle = mo->angle + FixedAngle(camrotate*FRACUNIT); else if (leveltime < starttime) angle = focusangle + FixedAngle(camrotate*FRACUNIT); + else if (camstill || resetcalled || player->playerstate == PST_DEAD) + angle = thiscam->angle; else { angle_t input = focusangle + FixedAngle(camrotate<angle; @@ -8322,12 +8328,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall input = InvAngle(input); angle = thiscam->angle + input; - - if (demoplayback && player == &players[consoleplayer]) - localangle = angle; } - if (!resetcalled && (leveltime > starttime) + if (!resetcalled && (leveltime > starttime && timeover != 2) && ((thiscam == &camera && t_cam_rotate != -42) || (thiscam == &camera2 && t_cam2_rotate != -42) || (thiscam == &camera3 && t_cam3_rotate != -42) @@ -8363,25 +8366,30 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist); // SRB2Kart: set camera panning - if (player->kartstuff[k_drift] != 0) - { - fixed_t panmax = (dist/5); - pan = FixedDiv(FixedMul(min((fixed_t)player->kartstuff[k_driftcharge], K_GetKartDriftSparkValue(player)), panmax), K_GetKartDriftSparkValue(player)); - if (pan > panmax) - pan = panmax; - if (player->kartstuff[k_drift] < 0) - pan *= -1; - } + if (camstill || resetcalled || player->playerstate == PST_DEAD) + pan = xpan = ypan = 0; else - pan = 0; + { + if (player->kartstuff[k_drift] != 0) + { + fixed_t panmax = (dist/5); + pan = FixedDiv(FixedMul(min((fixed_t)player->kartstuff[k_driftcharge], K_GetKartDriftSparkValue(player)), panmax), K_GetKartDriftSparkValue(player)); + if (pan > panmax) + pan = panmax; + if (player->kartstuff[k_drift] < 0) + pan *= -1; + } + else + pan = 0; - pan = thiscam->pan + FixedMul(pan - thiscam->pan, camspeed/4); + pan = thiscam->pan + FixedMul(pan - thiscam->pan, camspeed/4); - xpan = FixedMul(FINECOSINE(((angle+ANGLE_90)>>ANGLETOFINESHIFT) & FINEMASK), pan); - ypan = FixedMul(FINESINE(((angle+ANGLE_90)>>ANGLETOFINESHIFT) & FINEMASK), pan); + xpan = FixedMul(FINECOSINE(((angle+ANGLE_90)>>ANGLETOFINESHIFT) & FINEMASK), pan); + ypan = FixedMul(FINESINE(((angle+ANGLE_90)>>ANGLETOFINESHIFT) & FINEMASK), pan); - x += xpan; - y += ypan; + x += xpan; + y += ypan; + } pviewheight = FixedMul(32<scale); @@ -8390,6 +8398,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall else z = mo->z + pviewheight + camheight; +#ifndef NOCLIPCAM // Disable all z-clipping for noclip cam // move camera down to move under lower ceilings newsubsec = R_IsPointInSubsector(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1)); @@ -8587,6 +8596,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (thiscam->z < thiscam->floorz && !cameranoclip) thiscam->z = thiscam->floorz; +#endif // NOCLIPCAM // point viewed by the camera // this point is just 64 unit forward the player @@ -8594,15 +8604,19 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall viewpointx = mo->x + FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist) + xpan; viewpointy = mo->y + FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist) + ypan; - if (!camstill && !resetcalled && !paused) + if (timeover) + thiscam->angle = angle; + else if (!camstill && !resetcalled && !paused && timeover != 1) thiscam->angle = R_PointToAngle2(thiscam->x, thiscam->y, viewpointx, viewpointy); - if (player->exiting) + if (timeover == 1) { - thiscam->momx = 0; - thiscam->momy = 0; + thiscam->momx = P_ReturnThrustX(NULL, mo->angle, 32*mo->scale); // Push forward + thiscam->momy = P_ReturnThrustY(NULL, mo->angle, 32*mo->scale); thiscam->momz = 0; } + else if (player->exiting || timeover == 2) + thiscam->momx = thiscam->momy = thiscam->momz = 0; else if (leveltime < starttime) { thiscam->momx = FixedMul(x - thiscam->x, camspeed); @@ -8613,7 +8627,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { thiscam->momx = x - thiscam->x; thiscam->momy = y - thiscam->y; - thiscam->momz = FixedMul(z - thiscam->z, camspeed/2); + if (splitscreen == 1) // Wide-screen needs to follow faster, due to a smaller vertical:horizontal ratio of screen space + thiscam->momz = FixedMul(z - thiscam->z, (3*camspeed)/4); + else + thiscam->momz = FixedMul(z - thiscam->z, camspeed/2); } thiscam->pan = pan; @@ -8628,10 +8645,10 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall else angle = R_PointToAngle2(0, thiscam->z, dist, mo->z + P_GetPlayerHeight(player)); - if (player->playerstate != PST_DEAD && !(player->pflags & PF_NIGHTSMODE && player->exiting)) + if (player->playerstate != PST_DEAD && !((player->pflags & PF_NIGHTSMODE) && player->exiting)) angle += (focusaiming < ANGLE_180 ? focusaiming/2 : InvAngle(InvAngle(focusaiming)/2)); // overcomplicated version of '((signed)focusaiming)/2;' - if (twodlevel || (mo->flags2 & MF2_TWOD) || !camstill) // Keep the view still... + if (twodlevel || (mo->flags2 & MF2_TWOD) || (!camstill && !timeover)) // Keep the view still... { G_ClipAimingPitch((INT32 *)&angle); dist = thiscam->aiming - angle; @@ -8730,7 +8747,7 @@ boolean P_SpectatorJoinGame(player_t *player) if (P_IsLocalPlayer(player) && displayplayer != consoleplayer) displayplayer = consoleplayer; - CONS_Printf(M_GetText("%s entered the game.\n"), player_names[player-players]); + HU_AddChatText(va(M_GetText("\x82*%s entered the game."), player_names[player-players]), false); return true; // no more player->mo, cannot continue. } return false; @@ -8892,15 +8909,13 @@ void P_DoTimeOver(player_t *player) S_StopSound(player->mo); P_DamageMobj(player->mo, NULL, NULL, 10000); } + player->lives = 0; P_EndingMusic(player); -#if 0 - // sal, when you do the f-zero explosion, this is how you make sure the map doesn't end before it's done ^u^ ~toast if (!countdown2) countdown2 = 5*TICRATE; -#endif } // @@ -8933,7 +8948,7 @@ void P_PlayerThink(player_t *player) } #ifdef SEENAMES - if (netgame && player == &players[displayplayer] && !(leveltime % (TICRATE/5))) + if (netgame && player == &players[displayplayer] && !(leveltime % (TICRATE/5)) && !splitscreen) { seenplayer = NULL; @@ -9147,10 +9162,10 @@ void P_PlayerThink(player_t *player) } } - if ((netgame || splitscreen) && player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing]) + if ((netgame || multiplayer) && player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing]) { player->pflags ^= PF_WANTSTOJOIN; - //player->powers[pw_flashing] = TICRATE + 1; + player->powers[pw_flashing] = TICRATE/2 + 1; /*if (P_SpectatorJoinGame(player)) return; // player->mo was removed.*/ } @@ -9398,6 +9413,7 @@ void P_PlayerThink(player_t *player) player->kartstuff[k_hyudorotimer] // SRB2kart - fixes Hyudoro not flashing when it should. || player->kartstuff[k_growshrinktimer] > 0 // Grow doesn't flash either. || player->kartstuff[k_respawn] // Respawn timer (for drop dash effect) + || (player->pflags & PF_TIMEOVER) // NO CONTEST explosion || (G_BattleGametype() && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || leveltime < starttime)) // Level intro { diff --git a/src/r_main.c b/src/r_main.c index bd1cd477..1db5989f 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -185,16 +185,6 @@ void SplitScreen_OnChange(void) { UINT8 i; - if (!cv_debug && netgame) - { - if (splitscreen) - { - CONS_Alert(CONS_NOTICE, M_GetText("Splitscreen not supported in netplay, sorry!\n")); - splitscreen = 0; - } - return; - } - // recompute screen size R_ExecuteSetViewSize(); @@ -861,7 +851,7 @@ void R_SkyboxFrame(player_t *player) { aimingangle = player->aiming; viewangle = player->mo->angle; - if (!demoplayback && player->playerstate != PST_DEAD) + if (/*!demoplayback && */player->playerstate != PST_DEAD) { if (player == &players[consoleplayer]) { @@ -1138,7 +1128,7 @@ void R_SetupFrame(player_t *player, boolean skybox) aimingangle = player->aiming; viewangle = viewmobj->angle; - if (!demoplayback && player->playerstate != PST_DEAD) + if (/*!demoplayback && */player->playerstate != PST_DEAD) { if (player == &players[consoleplayer]) { diff --git a/src/r_things.c b/src/r_things.c index 802b3235..54b20e17 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2517,9 +2517,9 @@ static void Sk_SetDefaultValue(skin_t *skin) strcpy(skin->realname, "Someone"); strcpy(skin->hudname, "???"); - strncpy(skin->charsel, "CHRSONIC", 9); - strncpy(skin->face, "MISSING", 9); - strncpy(skin->superface, "MISSING", 9); + strncpy(skin->facerank, "PLAYRANK", 9); + strncpy(skin->facewant, "PLAYWANT", 9); + strncpy(skin->facemmap, "PLAYMMAP", 9); skin->starttranscolor = 160; skin->prefcolor = SKINCOLOR_GREEN; @@ -2551,7 +2551,6 @@ static void Sk_SetDefaultValue(skin_t *skin) for (i = 0; i < sfx_skinsoundslot0; i++) if (S_sfx[i].skinsound != -1) skin->soundsid[S_sfx[i].skinsound] = i; - strncpy(skin->iconprefix, "SONICICN", 9); } // @@ -2584,17 +2583,17 @@ void R_InitSkins(void) strcpy(skin->realname, "Sonic"); strcpy(skin->hudname, "SONIC"); - strncpy(skin->charsel, "CHRSONIC", 9); - strncpy(skin->face, "LIVSONIC", 9); - strncpy(skin->superface, "LIVSUPER", 9); + strncpy(skin->facerank, "PLAYRANK", 9); + strncpy(skin->facewant, "PLAYWANT", 9); + strncpy(skin->facemmap, "PLAYMMAP", 9); skin->prefcolor = SKINCOLOR_BLUE; skin->ability = CA_THOK; skin->actionspd = 60<kartspeed = 7; - skin->kartweight = 3; + skin->kartspeed = 8; + skin->kartweight = 2; // skin->normalspeed = 36<spritedef.numframes = sprites[SPR_PLAY].numframes; skin->spritedef.spriteframes = sprites[SPR_PLAY].spriteframes; - ST_LoadFaceGraphics(skin->face, skin->superface, 0); - strncpy(skin->iconprefix, "SONICICN", 9); - K_LoadIconGraphics(skin->iconprefix, 0); + ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, 0); //MD2 for sonic doesn't want to load in Linux. #ifdef HWRENDER @@ -2699,7 +2696,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->jumpfactor = skin->jumpfactor; - if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback || modeattacking)) + /*if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback || modeattacking)) { if (playernum == consoleplayer) CV_StealthSetValue(&cv_playercolor, skin->prefcolor); @@ -2712,7 +2709,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) player->skincolor = skin->prefcolor; if (player->mo) player->mo->color = player->skincolor; - } + }*/ if (player->mo) P_SetScale(player->mo, player->mo->scale); @@ -2763,7 +2760,7 @@ void R_AddSkins(UINT16 wadnum) char *value; size_t size; skin_t *skin; - boolean hudname, realname, superface; + boolean hudname, realname; // // search for all skin markers in pwad @@ -2793,7 +2790,7 @@ void R_AddSkins(UINT16 wadnum) skin = &skins[numskins]; Sk_SetDefaultValue(skin); skin->wadnum = wadnum; - hudname = realname = superface = false; + hudname = realname = false; // parse stoken = strtok (buf2, "\r\n= "); while (stoken) @@ -2878,23 +2875,20 @@ void R_AddSkins(UINT16 wadnum) strupr(value); strncpy(skin->sprite, value, sizeof skin->sprite); } - else if (!stricmp(stoken, "charsel")) + else if (!stricmp(stoken, "facerank")) { strupr(value); - strncpy(skin->charsel, value, sizeof skin->charsel); + strncpy(skin->facerank, value, sizeof skin->facerank); } - else if (!stricmp(stoken, "face")) + else if (!stricmp(stoken, "facewant")) { strupr(value); - strncpy(skin->face, value, sizeof skin->face); - if (!superface) - strncpy(skin->superface, value, sizeof skin->superface); + strncpy(skin->facewant, value, sizeof skin->facewant); } - else if (!stricmp(stoken, "superface")) + else if (!stricmp(stoken, "facemmap")) { - superface = true; strupr(value); - strncpy(skin->superface, value, sizeof skin->superface); + strncpy(skin->facemmap, value, sizeof skin->facemmap); } #define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value); @@ -2936,11 +2930,6 @@ void R_AddSkins(UINT16 wadnum) skin->jumpfactor = FLOAT_TO_FIXED(atof(value)); else if (!stricmp(stoken, "highresscale")) skin->highresscale = FLOAT_TO_FIXED(atof(value)); - else if (!stricmp(stoken, "faceicon")) - { - strupr(value); - strncpy(skin->iconprefix, value, sizeof skin->iconprefix); - } else { INT32 found = false; @@ -3041,10 +3030,7 @@ next_token: #endif // add face graphics - ST_LoadFaceGraphics(skin->face, skin->superface, numskins); - - // load minimap icons - K_LoadIconGraphics(skin->iconprefix, numskins); + ST_LoadFaceGraphics(skin->facerank, skin->facewant, skin->facemmap, numskins); #ifdef HWRENDER if (rendermode == render_opengl) diff --git a/src/r_things.h b/src/r_things.h index a037b873..a7542e2f 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -81,7 +81,7 @@ typedef struct char realname[SKINNAMESIZE+1]; // Display name for level completion. char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long) - char charsel[9], face[9], superface[9]; // Arbitrarily named patch lumps + char facerank[9], facewant[9], facemmap[9]; // Arbitrarily named patch lumps UINT8 ability; // ability definition UINT8 ability2; // secondary ability definition @@ -113,9 +113,6 @@ typedef struct // specific sounds per skin sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table - - // minimap icons - char iconprefix[9]; } skin_t; // ----------- diff --git a/src/s_sound.c b/src/s_sound.c index d87b6106..6dae619a 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -531,6 +531,9 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) pitch = NORM_PITCH; priority = NORM_PRIORITY; + if (splitscreen && origin) + volume = FixedDiv(volume<>FRACBITS; + if (splitscreen && listenmobj2) // Copy the sound for the split player { // Check to see if it is audible, and if not, modify the params @@ -1011,6 +1014,9 @@ void S_UpdateSounds(void) pitch = NORM_PITCH; sep = NORM_SEP; + if (splitscreen && c->origin) + volume = FixedDiv(volume<>FRACBITS; + // check non-local sounds for distance clipping // or modify their params if (c->origin && ((c->origin != players[consoleplayer].mo) @@ -1325,6 +1331,9 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v *vol = (15 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; } + if (splitscreen) + *vol = FixedDiv((*vol)<>FRACBITS; + return (*vol > 0); } diff --git a/src/sounds.c b/src/sounds.c index 02ad0853..e8f247e4 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -705,7 +705,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"kc2e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"kc2f", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Pogo Spring use {"kc30", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"kc31", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"kc31", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR}, // NO CONTEST explosion {"kc32", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"kc33", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"kc34", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, @@ -737,7 +737,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"kc4e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"kc50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"kc51", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"kc51", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR}, // NO CONTEST debris ambience {"kc52", false, 64, 0, -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}, @@ -813,6 +813,9 @@ sfxinfo_t S_sfx[NUMSFX] = {"kpogos", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"ddash", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"zio3", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, + {"wind1", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, + {"fire2", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, + {"chain", false, 128, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"mcitm1", false, 110, 8, -1, NULL, 0, -1, -1, LUMPERROR}, {"chaooo", false, 110, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, @@ -946,6 +949,21 @@ sfxinfo_t S_sfx[NUMSFX] = {"krti11", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR}, {"krti12", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR}, + // SOC_CHAO SFX + {"mkuma", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"mkpop", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"bfare", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"merry", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"bowlh", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"tcart", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"tppop", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"toada", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"hsdoor",false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"hstrn", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"aspkb", false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"msmnj1",false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"msmnj2",false, 60, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + // SRB2kart - Skin sounds {"kwin", false, 64, 96, -1, NULL, 0, SKSKWIN, -1, LUMPERROR}, {"klose", false, 64, 96, -1, NULL, 0, SKSKLOSE, -1, LUMPERROR}, diff --git a/src/sounds.h b/src/sounds.h index 2516b646..69755e47 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -888,6 +888,9 @@ typedef enum sfx_kpogos, sfx_ddash, sfx_zio3, + sfx_wind1, + sfx_fire2, + sfx_chain, sfx_mcitm1, sfx_chaooo, sfx_itfree, @@ -1021,6 +1024,21 @@ typedef enum sfx_krti11, sfx_krti12, + // SOC_CHAO hardcode + sfx_mkuma, + sfx_mkpop, + sfx_bfare, + sfx_merry, + sfx_bowlh, + sfx_tcart, + sfx_tppop, + sfx_toada, + sfx_hsdoor, + sfx_hstrn, + sfx_aspkb, + sfx_msmnj1, + sfx_msmnj2, + // And LASTLY, Kart's skin sounds. sfx_kwin, sfx_klose, diff --git a/src/st_stuff.c b/src/st_stuff.c index 45e0deb5..06890368 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -50,8 +50,9 @@ UINT16 objectsdrawn = 0; // STATUS BAR DATA // -patch_t *faceprefix[MAXSKINS]; // face status patches -patch_t *superprefix[MAXSKINS]; // super face status patches +patch_t *facerankprefix[MAXSKINS]; // ranking +patch_t *facewantprefix[MAXSKINS]; // wanted +patch_t *facemmapprefix[MAXSKINS]; // minimap // ------------------------------------------ // status bar overlay @@ -124,6 +125,10 @@ static patch_t *minicaps; static patch_t *gotrflag; static patch_t *gotbflag; +// Midnight Channel: +static patch_t *hud_tv1; +static patch_t *hud_tv2; + // SRB2kart // @@ -345,31 +350,27 @@ void ST_LoadGraphics(void) ngradeletters[i] = W_CachePatchName(va("GRADE%d", i), PU_HUDGFX); K_LoadKartHUDGraphics(); + + // Midnight Channel: + hud_tv1 = W_CachePatchName("HUD_TV1", PU_HUDGFX); + hud_tv2 = W_CachePatchName("HUD_TV2", PU_HUDGFX); } // made separate so that skins code can reload custom face graphics -void ST_LoadFaceGraphics(char *facestr, char *superstr, INT32 skinnum) +void ST_LoadFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 skinnum) { - faceprefix[skinnum] = W_CachePatchName(facestr, PU_HUDGFX); - superprefix[skinnum] = W_CachePatchName(superstr, PU_HUDGFX); + facerankprefix[skinnum] = W_CachePatchName(rankstr, PU_HUDGFX); + facewantprefix[skinnum] = W_CachePatchName(wantstr, PU_HUDGFX); + facemmapprefix[skinnum] = W_CachePatchName(mmapstr, PU_HUDGFX); facefreed[skinnum] = false; } -#ifdef DELFILE -void ST_UnLoadFaceGraphics(INT32 skinnum) -{ - Z_Free(faceprefix[skinnum]); - Z_Free(superprefix[skinnum]); - facefreed[skinnum] = true; -} -#endif - void ST_ReloadSkinFaceGraphics(void) { INT32 i; for (i = 0; i < numskins; i++) - ST_LoadFaceGraphics(skins[i].face, skins[i].superface, i); + ST_LoadFaceGraphics(skins[i].facerank, skins[i].facewant, skins[i].facemmap, i); } static inline void ST_InitData(void) @@ -718,9 +719,9 @@ static void ST_drawLives(void) // SRB2kart - unused. { // skincolor face/super UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE); - patch_t *face = faceprefix[stplyr->skin]; + patch_t *face = facerankprefix[stplyr->skin]; if (stplyr->powers[pw_super] || stplyr->pflags & PF_NIGHTSMODE) - face = superprefix[stplyr->skin]; + face = facewantprefix[stplyr->skin]; V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,face, colormap); } @@ -729,7 +730,7 @@ static void ST_drawLives(void) // SRB2kart - unused. // skincolor face UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE); V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0), - V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,faceprefix[stplyr->skin], colormap); + V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,facerankprefix[stplyr->skin], colormap); } // name @@ -1895,13 +1896,13 @@ static void ST_overlayDrawer(void) if(!P_IsLocalPlayer(stplyr)) { - char name[MAXPLAYERNAME+1]; + /*char name[MAXPLAYERNAME+1]; // shorten the name if its more than twelve characters. - strlcpy(name, player_names[stplyr-players], 13); + strlcpy(name, player_names[stplyr-players], 13);*/ // Show name of player being displayed V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Viewpoint:")); - V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, name); + V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]); } // This is where we draw all the fun cheese if you have the chasecam off! @@ -1927,7 +1928,7 @@ static void ST_overlayDrawer(void) ) ST_drawLevelTitle(); - if (!hu_showscores && !splitscreen && netgame && displayplayer == consoleplayer && !mapreset) + if (!hu_showscores && netgame && !mapreset) { /*if (G_GametypeUsesLives() && stplyr->lives <= 0 && countdown != 1) V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), 0, M_GetText("Press F12 to watch another player.")); @@ -1952,21 +1953,50 @@ static void ST_overlayDrawer(void) ) { // SRB2kart: changed positions & text - V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -")); - if (stplyr->pflags & PF_WANTSTOJOIN) - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Cancel Join")); - /*else if (G_GametypeHasTeams()) - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Join Team"));*/ + if (splitscreen) + { + INT32 splitflags = K_calcSplitFlags(0); + V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|splitflags, M_GetText("- SPECTATING -")); + if (stplyr->powers[pw_flashing]) + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - . . .")); + else if (stplyr->pflags & PF_WANTSTOJOIN) + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - Cancel Join")); + /*else if (G_GametypeHasTeams()) + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - Join Team"));*/ + else + V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, M_GetText("Item - Join Game")); + } else - V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Join Game")); - V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF, M_GetText("Accelerate - Float")); - V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF, M_GetText("Brake - Sink")); + { + V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -")); + if (stplyr->powers[pw_flashing]) + V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - . . .")); + else if (stplyr->pflags & PF_WANTSTOJOIN) + V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Cancel Join")); + /*else if (G_GametypeHasTeams()) + V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Join Team"));*/ + else + V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, M_GetText("Item - Join Game")); + V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF, M_GetText("Accelerate - Float")); + V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF, M_GetText("Brake - Sink")); + } } } ST_drawDebugInfo(); } +// MayonakaStatic: draw Midnight Channel's TV-like borders +static void ST_MayonakaStatic(void) +{ + INT32 flag = (leveltime%2) ? V_90TRANS : V_70TRANS; + + V_DrawFixedPatch(0, 0, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT|flag, hud_tv1, NULL); + V_DrawFixedPatch(320<typeoflevel & TOL_TV) // Very specific Midnight Channel stuff. + ST_MayonakaStatic(); + } + + // Draw a white fade on level opening + if (leveltime < 15) + { + if (leveltime <= 5) + V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,120); // Pure white on first few frames, to hide SRB2's awful level load artifacts + else + V_DrawFadeScreen(120, 15-leveltime); // Then gradually fade out from there } } diff --git a/src/st_stuff.h b/src/st_stuff.h index d0528e0a..b054460b 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -42,7 +42,7 @@ void ST_UnloadGraphics(void); void ST_LoadGraphics(void); // face load graphics, called when skin changes -void ST_LoadFaceGraphics(char *facestr, char *superstr, INT32 playernum); +void ST_LoadFaceGraphics(char *rankstr, char *wantstr, char *mmapstr, INT32 playernum); void ST_ReloadSkinFaceGraphics(void); #ifdef DELFILE void ST_UnLoadFaceGraphics(INT32 skinnum); @@ -66,8 +66,9 @@ extern patch_t *sboscore; extern patch_t *sbotime; extern patch_t *sbocolon; extern patch_t *sboperiod; -extern patch_t *faceprefix[MAXSKINS]; // face status patches -extern patch_t *superprefix[MAXSKINS]; // super face status patches +extern patch_t *facerankprefix[MAXSKINS]; // ranking +extern patch_t *facewantprefix[MAXSKINS]; // wanted +extern patch_t *facemmapprefix[MAXSKINS]; // minimap extern patch_t *livesback; extern patch_t *ngradeletters[7]; extern boolean iconfreed[MAXPLAYERS]; diff --git a/src/v_video.c b/src/v_video.c index 0a8fd561..fc76bf31 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -78,9 +78,9 @@ consvar_t cv_grcoronas = {"gr_coronas", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, consvar_t cv_grcoronasize = {"gr_coronasize", "1", CV_SAVE| CV_FLOAT, 0, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif -static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}}; +//static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NULL}}; // console variables in development -consvar_t cv_grmd2 = {"gr_md2", "Off", CV_SAVE, CV_MD2, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_grmd2 = {"gr_md2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif const UINT8 gammatable[5][256] = @@ -952,6 +952,39 @@ void V_DrawDiag(INT32 x, INT32 y, INT32 wh, INT32 c) } } +#ifdef HWRENDER +// This is now a function since it's otherwise repeated 2 times and honestly looks retarded: +static UINT32 V_GetHWConsBackColor(void) +{ + UINT32 hwcolor; + switch (cons_backcolor.value) + { + case 0: hwcolor = 0xffffff00; break; // White + case 1: hwcolor = 0x80808000; break; // Gray + case 2: hwcolor = 0xdeb88700; break; // Sepia + case 3: hwcolor = 0x40201000; break; // Brown + case 4: hwcolor = 0xfa807200; break; // Pink + case 5: hwcolor = 0xff69b400; break; // Raspberry + case 6: hwcolor = 0xff000000; break; // Red + case 7: hwcolor = 0xffd68300; break; // Creamsicle + case 8: hwcolor = 0xff800000; break; // Orange + case 9: hwcolor = 0xdaa52000; break; // Gold + case 10: hwcolor = 0x80800000; break; // Yellow + case 11: hwcolor = 0x00ff0000; break; // Emerald + case 12: hwcolor = 0x00800000; break; // Green + case 13: hwcolor = 0x4080ff00; break; // Cyan + case 14: hwcolor = 0x4682b400; break; // Steel + case 15: hwcolor = 0x1e90ff00; break; // Periwinkle + case 16: hwcolor = 0x0000ff00; break; // Blue + case 17: hwcolor = 0xff00ff00; break; // Purple + case 18: hwcolor = 0xee82ee00; break; // Lavender + // Default green + default: hwcolor = 0x00800000; break; + } + return hwcolor; +} +#endif + // THANK YOU MPC!!! void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) @@ -966,21 +999,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) #ifdef HWRENDER if (rendermode != render_soft && rendermode != render_none) { - UINT32 hwcolor; - switch (cons_backcolor.value) - { - case 0: hwcolor = 0xffffff00; break; // White - case 1: hwcolor = 0x80808000; break; // Gray - case 2: hwcolor = 0x40201000; break; // Brown - case 3: hwcolor = 0xff000000; break; // Red - case 4: hwcolor = 0xff800000; break; // Orange - case 5: hwcolor = 0x80800000; break; // Yellow - case 6: hwcolor = 0x00800000; break; // Green - case 7: hwcolor = 0x0000ff00; break; // Blue - case 8: hwcolor = 0x4080ff00; break; // Cyan - // Default green - default: hwcolor = 0x00800000; break; - } + UINT32 hwcolor = V_GetHWConsBackColor(); HWR_DrawConsoleFill(x, y, w, h, hwcolor, c); // we still use the regular color stuff but only for flags. actual draw color is "hwcolor" for this. return; } @@ -1226,21 +1245,7 @@ void V_DrawFadeConsBack(INT32 plines) #ifdef HWRENDER // not win32 only 19990829 by Kin if (rendermode != render_soft && rendermode != render_none) { - UINT32 hwcolor; - switch (cons_backcolor.value) - { - case 0: hwcolor = 0xffffff00; break; // White - case 1: hwcolor = 0x80808000; break; // Gray - case 2: hwcolor = 0x40201000; break; // Brown - case 3: hwcolor = 0xff000000; break; // Red - case 4: hwcolor = 0xff800000; break; // Orange - case 5: hwcolor = 0x80800000; break; // Yellow - case 6: hwcolor = 0x00800000; break; // Green - case 7: hwcolor = 0x0000ff00; break; // Blue - case 8: hwcolor = 0x4080ff00; break; // Cyan - // Default green - default: hwcolor = 0x00800000; break; - } + UINT32 hwcolor = V_GetHWConsBackColor(); HWR_DrawConsoleBack(hwcolor, plines); return; } @@ -1347,10 +1352,10 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UI w = (vid.width < 640 ) ? (SHORT(hu_font[c]->width)/2) : (SHORT(hu_font[c]->width)); // use normal sized characters if we're using a terribly low resolution. if (x + w > vid.width) return; - + V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, (vid.width < 640) ? (FRACUNIT) : (FRACUNIT/2), flags, hu_font[c], colormap); - + } // Precompile a wordwrapped string to any given width. diff --git a/src/y_inter.c b/src/y_inter.c index 5d7456dd..3ed06352 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -275,6 +275,8 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) for (j = 0; j < numplayersingame; j++) { + INT32 nump = ((G_RaceGametype() && nospectategrief > 0) ? nospectategrief : numplayersingame); + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator || completed[i]) @@ -296,9 +298,9 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) else data.match.pos[data.match.numplayers] = data.match.numplayers+1; - if (!rankingsmode && !(players[i].pflags & PF_TIMEOVER) && (data.match.pos[data.match.numplayers] != numplayersingame)) + if (!rankingsmode && !(players[i].pflags & PF_TIMEOVER) && (data.match.pos[data.match.numplayers] < nump)) { - data.match.increase[i] = numplayersingame - data.match.pos[data.match.numplayers]; + data.match.increase[i] = nump - data.match.pos[data.match.numplayers]; players[i].score += data.match.increase[i]; } @@ -346,7 +348,7 @@ void Y_IntermissionDrawer(void) V_DrawPatchFill(bgtile); if (usebuffer) // Fade everything out - V_DrawFadeScreen(0xFF00, 20); + V_DrawFadeScreen(0xFF00, 22); if (!splitscreen) whiteplayer = demoplayback ? displayplayer : consoleplayer; @@ -414,7 +416,7 @@ void Y_IntermissionDrawer(void) else*/ if (intertype == int_race || intertype == int_match) { #define NUMFORNEWCOLUMN 8 - INT32 y = 48, gutter = ((data.match.numplayers > NUMFORNEWCOLUMN) ? 0 : (BASEVIDWIDTH/2)); + INT32 y = 41, gutter = ((data.match.numplayers > NUMFORNEWCOLUMN) ? 0 : (BASEVIDWIDTH/2)); const char *timeheader; if (data.match.rankingsmode) @@ -423,26 +425,27 @@ void Y_IntermissionDrawer(void) timeheader = (intertype == int_race ? "TIME" : "SCORE"); // draw the level name - V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 20, 0, data.match.levelstring); - V_DrawFill(x, 42, 312, 1, 0); + V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12, 0, data.match.levelstring); + V_DrawFill(x, 34, 312, 1, 0); if (data.match.encore) - V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 20-8, hilicol, "ENCORE MODE"); + V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12-8, hilicol, "ENCORE MODE"); if (!gutter) { - V_DrawFill(x+156, 32, 1, 152, 0); + V_DrawFill(x+156, 24, 1, 158, 0); + V_DrawFill(x, 182, 312, 1, 0); - V_DrawCenteredString(x+6+(BASEVIDWIDTH/2), 32, hilicol, "#"); - V_DrawString(x+36+(BASEVIDWIDTH/2), 32, hilicol, "NAME"); + V_DrawCenteredString(x+6+(BASEVIDWIDTH/2), 24, hilicol, "#"); + V_DrawString(x+36+(BASEVIDWIDTH/2), 24, hilicol, "NAME"); - V_DrawRightAlignedString(x+152, 32, hilicol, timeheader); + V_DrawRightAlignedString(x+152, 24, hilicol, timeheader); } - V_DrawCenteredString(x+6, 32, hilicol, "#"); - V_DrawString(x+36, 32, hilicol, "NAME"); + V_DrawCenteredString(x+6, 24, hilicol, "#"); + V_DrawString(x+36, 24, hilicol, "NAME"); - V_DrawRightAlignedString(x+(BASEVIDWIDTH/2)+152, 32, hilicol, timeheader); + V_DrawRightAlignedString(x+(BASEVIDWIDTH/2)+152, 24, hilicol, timeheader); for (i = 0; i < data.match.numplayers; i++) { @@ -458,12 +461,10 @@ void Y_IntermissionDrawer(void) V_DrawCenteredString(x+6, y, 0, va("%d", data.match.pos[i])); - if (data.match.color[i] == 0) - V_DrawSmallScaledPatch(x+16, y-4, 0,faceprefix[*data.match.character[i]]); - else + if (data.match.color[i]) { UINT8 *colormap = R_GetTranslationColormap(*data.match.character[i], *data.match.color[i], GTC_CACHE); - V_DrawSmallMappedPatch(x+16, y-4, 0,faceprefix[*data.match.character[i]], colormap); + V_DrawMappedPatch(x+16, y-4, 0,facerankprefix[*data.match.character[i]], colormap); } if (!gutter) @@ -518,11 +519,11 @@ void Y_IntermissionDrawer(void) else data.match.num[i] = MAXPLAYERS; // this should be the only field setting in this function - y += 16; + y += 18; if (i == NUMFORNEWCOLUMN-1) { - y = 48; + y = 41; x += BASEVIDWIDTH/2; } #undef NUMFORNEWCOLUMN @@ -1146,12 +1147,10 @@ void Y_VoteDrawer(void) V_DrawDiag(x, y, 6, V_SNAPTOLEFT|levelinfo[votes[i]].gtc); } - if (players[i].skincolor == 0) - V_DrawSmallScaledPatch(x+24, y+9, V_SNAPTOLEFT, faceprefix[players[i].skin]); - else + if (players[i].skincolor) { UINT8 *colormap = R_GetTranslationColormap(players[i].skin, players[i].skincolor, GTC_CACHE); - V_DrawSmallMappedPatch(x+24, y+9, V_SNAPTOLEFT, faceprefix[players[i].skin], colormap); + V_DrawMappedPatch(x+24, y+9, V_SNAPTOLEFT, facerankprefix[players[i].skin], colormap); } }