diff --git a/src/command.c b/src/command.c index 7184ace42..d9e0e83d6 100644 --- a/src/command.c +++ b/src/command.c @@ -78,6 +78,7 @@ CV_PossibleValue_t CV_OnOff[] = {{0, "Off"}, {1, "On"}, {0, NULL}}; CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}}; CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}}; CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; +CV_PossibleValue_t CV_TrueFalse[] = {{0, "False"}, {1, "True"}, {0, NULL}}; // Cheats #ifdef DEVELOP @@ -909,15 +910,17 @@ static void COM_Help_f(void) { CONS_Printf(" Possible values:\n"); if (cvar->PossibleValue == CV_YesNo) - CONS_Printf(" Yes or No (On or Off, 1 or 0)\n"); + CONS_Printf(" Yes or No (On or Off, True or False, 1 or 0)\n"); else if (cvar->PossibleValue == CV_OnOff) - CONS_Printf(" On or Off (Yes or No, 1 or 0)\n"); + CONS_Printf(" On or Off (Yes or No, True or False, 1 or 0)\n"); + else if (cvar->PossibleValue == CV_TrueFalse) + CONS_Printf(" True or False (On or Off, Yes or No, 1 or 0)\n"); else if (cvar->PossibleValue == Color_cons_t || cvar->PossibleValue == Followercolor_cons_t) { boolean follower = (cvar->PossibleValue == Followercolor_cons_t); for (i = SKINCOLOR_NONE; i < numskincolors; ++i) { - if (K_ColorUsable(i, follower) == true) + if (K_ColorUsable(i, follower, true) == true) { CONS_Printf(" %-3d : %s\n", i, skincolors[i].name); if (i == cvar->value) @@ -1565,12 +1568,12 @@ boolean CV_CompleteValue(consvar_t *var, const char **valstrp, INT32 *intval) goto found; } // Not found ... but wait, there's hope! - if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo) + if (var->PossibleValue == CV_OnOff || var->PossibleValue == CV_YesNo || var->PossibleValue == CV_TrueFalse) { overrideval = -1; - if (!stricmp(valstr, "on") || !stricmp(valstr, "yes")) + if (!stricmp(valstr, "on") || !stricmp(valstr, "yes") || !stricmp(valstr, "true")) overrideval = 1; - else if (!stricmp(valstr, "off") || !stricmp(valstr, "no")) + else if (!stricmp(valstr, "off") || !stricmp(valstr, "no") || !stricmp(valstr, "false")) overrideval = 0; if (overrideval != -1) diff --git a/src/command.h b/src/command.h index b3bae86a7..52e18f0fd 100644 --- a/src/command.h +++ b/src/command.h @@ -172,6 +172,7 @@ extern CV_PossibleValue_t CV_OnOff[]; extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_Unsigned[]; extern CV_PossibleValue_t CV_Natural[]; +extern CV_PossibleValue_t CV_TrueFalse[]; // SRB2kart // the KARTSPEED and KARTGP were previously defined here, but moved to doomstat to avoid circular dependencies diff --git a/src/console.c b/src/console.c index 3c5e0f9f2..16fc3b8f9 100644 --- a/src/console.c +++ b/src/console.c @@ -59,7 +59,7 @@ static boolean con_started = false; // console has been initialised static boolean con_forcepic = true; // at startup toggle console translucency when first off boolean con_recalc; // set true when screen size has changed -static tic_t con_tick; // console ticker for anim or blinking prompt cursor +static tic_t con_tick; // console ticker for blinking prompt cursor // con_scrollup should use time (currenttime - lasttime).. static boolean consoletoggle; // true when console key pushed, ticker will handle @@ -70,8 +70,8 @@ static INT32 con_curlines; // vid lines currently used by console INT32 con_clipviewtop; // (useless) -static INT32 con_hudlines; // number of console heads up message lines -static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines +static UINT8 con_hudlines; // number of console heads up message lines +static UINT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines INT32 con_clearlines; // top screen lines to refresh when view reduced boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh @@ -108,6 +108,7 @@ static void CON_RecalcSize(void); static void CON_ChangeHeight(void); static void CON_DrawBackpic(void); +static void CONS_height_Change(void); static void CONS_hudlines_Change(void); static void CONS_backcolor_Change(void); @@ -123,10 +124,13 @@ static void CONS_backcolor_Change(void); static char con_buffer[CON_BUFFERSIZE]; // how many seconds the hud messages lasts on the screen -static consvar_t cons_msgtimeout = CVAR_INIT ("con_hudtime", "5", CV_SAVE, CV_Unsigned, NULL); +// CV_Unsigned can overflow when multiplied by TICRATE later, so let's use a 3-year limit instead +static CV_PossibleValue_t hudtime_cons_t[] = {{0, "MIN"}, {99999999, "MAX"}, {0, NULL}}; +static consvar_t cons_hudtime = CVAR_INIT ("con_hudtime", "5", CV_SAVE, hudtime_cons_t, NULL); // number of lines displayed on the HUD -static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, CV_Unsigned, CONS_hudlines_Change); +static CV_PossibleValue_t hudlines_cons_t[] = {{0, "MIN"}, {MAXHUDLINES, "MAX"}, {0, NULL}}; +static consvar_t cons_hudlines = CVAR_INIT ("con_hudlines", "5", CV_CALL|CV_SAVE, hudlines_cons_t, CONS_hudlines_Change); // number of lines console move per frame // (con_speed needs a limit, apparently) @@ -134,7 +138,7 @@ static CV_PossibleValue_t speed_cons_t[] = {{0, "MIN"}, {64, "MAX"}, {0, NULL}}; static consvar_t cons_speed = CVAR_INIT ("con_speed", "8", CV_SAVE, speed_cons_t, NULL); // percentage of screen height to use for console -static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_SAVE, CV_Unsigned, NULL); +static consvar_t cons_height = CVAR_INIT ("con_height", "50", CV_CALL|CV_SAVE, CV_Unsigned, CONS_height_Change); static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}, {0, NULL}}; // whether to use console background picture, or translucent mode @@ -152,6 +156,18 @@ consvar_t cons_backcolor = CVAR_INIT ("con_backcolor", "Black", CV_CALL|CV_SAVE, static void CON_Print(char *msg); +// Change the console height on demand +// +static void CONS_height_Change(void) +{ + Lock_state(); + + if (con_destlines > 0 && !con_startup) // If the console is open (as in, not using "bind")... + CON_ChangeHeight(); // ...update its height now, not only when it's closed and re-opened + + Unlock_state(); +} + // // static void CONS_hudlines_Change(void) @@ -164,11 +180,6 @@ static void CONS_hudlines_Change(void) for (i = 0; i < con_hudlines; i++) con_hudtime[i] = 0; - if (cons_hudlines.value < 1) - cons_hudlines.value = 1; - else if (cons_hudlines.value > MAXHUDLINES) - cons_hudlines.value = MAXHUDLINES; - con_hudlines = cons_hudlines.value; Unlock_state(); @@ -449,7 +460,7 @@ void CON_Init(void) Unlock_state(); - CV_RegisterVar(&cons_msgtimeout); + CV_RegisterVar(&cons_hudtime); CV_RegisterVar(&cons_hudlines); CV_RegisterVar(&cons_speed); CV_RegisterVar(&cons_height); @@ -614,33 +625,39 @@ static void CON_ChangeHeight(void) // static void CON_MoveConsole(void) { - fixed_t conspeed; + static fixed_t fracmovement = 0; Lock_state(); - conspeed = FixedDiv(cons_speed.value*vid.fdupy, FRACUNIT); - // instant if (!cons_speed.value) { con_curlines = con_destlines; + Unlock_state(); return; } - // up/down move to dest - if (con_curlines < con_destlines) + // Not instant - Increment fracmovement fractionally + fracmovement += FixedMul(cons_speed.value*vid.fdupy, renderdeltatics); + + if (con_curlines < con_destlines) // Move the console downwards { - con_curlines += FixedInt(conspeed); - if (con_curlines > con_destlines) - con_curlines = con_destlines; + con_curlines += FixedInt(fracmovement); // Move by fracmovement's integer value + if (con_curlines > con_destlines) // If we surpassed the destination... + con_curlines = con_destlines; // ...clamp to it! } - else if (con_curlines > con_destlines) + else // Move the console upwards { - con_curlines -= FixedInt(conspeed); + con_curlines -= FixedInt(fracmovement); if (con_curlines < con_destlines) con_curlines = con_destlines; + + if (con_destlines == 0) // If the console is being closed, not just moved up... + con_tick = 0; // ...don't show the blinking cursor } + fracmovement %= FRACUNIT; // Reset fracmovement's integer value, but keep the fraction + Unlock_state(); } @@ -759,10 +776,6 @@ void CON_Ticker(void) CON_ChangeHeight(); } - // console movement - if (con_destlines != con_curlines) - CON_MoveConsole(); - // clip the view, so that the part under the console is not drawn con_clipviewtop = -1; if (cons_backpic.value) // clip only when using an opaque background @@ -784,9 +797,8 @@ void CON_Ticker(void) // make overlay messages disappear after a while for (i = 0; i < con_hudlines; i++) { - con_hudtime[i]--; - if (con_hudtime[i] < 0) - con_hudtime[i] = 0; + if (con_hudtime[i]) + con_hudtime[i]--; } Unlock_state(); @@ -1334,7 +1346,8 @@ boolean CON_Responder(event_t *ev) static void CON_Linefeed(void) { // set time for heads up messages - con_hudtime[con_cy%con_hudlines] = cons_msgtimeout.value*TICRATE; + if (con_hudlines) + con_hudtime[con_cy%con_hudlines] = cons_hudtime.value*TICRATE; con_cy++; con_cx = 0; @@ -1674,7 +1687,7 @@ static void CON_DrawHudlines(void) INT32 charwidth = 8 * con_scalefactor; INT32 charheight = 8 * con_scalefactor; - if (con_hudlines <= 0) + if (!con_hudlines) return; if (chat_on && OLDCHAT) @@ -1682,7 +1695,7 @@ static void CON_DrawHudlines(void) else y = 0; - for (i = con_cy - con_hudlines+1; i <= con_cy; i++) + for (i = con_cy - con_hudlines; i <= con_cy; i++) { size_t c; INT32 x; @@ -1799,41 +1812,41 @@ static void CON_DrawConsole(void) } // draw console text lines from top to bottom - if (con_curlines < minheight) - return; - - i = con_cy - con_scrollup; - - // skip the last empty line due to the cursor being at the start of a new line - i--; - - i -= (con_curlines - minheight) / charheight; - - if (rendermode == render_none) return; - - for (y = (con_curlines-minheight) % charheight; y <= con_curlines-minheight; y += charheight, i++) + if (con_curlines >= minheight) { - INT32 x; - size_t c; + i = con_cy - con_scrollup; - p = (UINT8 *)&con_buffer[((i > 0 ? i : 0)%con_totallines)*con_width]; + // skip the last empty line due to the cursor being at the start of a new line + i--; - for (c = 0, x = charwidth; c < con_width; c++, x += charwidth, p++) + i -= (con_curlines - minheight) / charheight; + + if (rendermode == render_none) return; + + for (y = (con_curlines-minheight) % charheight; y <= con_curlines-minheight; y += charheight, i++) { - while (*p & 0x80) + INT32 x; + size_t c; + + p = (UINT8 *)&con_buffer[((i > 0 ? i : 0)%con_totallines)*con_width]; + + for (c = 0, x = charwidth; c < con_width; c++, x += charwidth, p++) { - charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; - p++; - c++; + while (*p & 0x80) + { + charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; + p++; + c++; + } + if (c >= con_width) + break; + V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true); } - if (c >= con_width) - break; - V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true); } } // draw prompt if enough place (not while game startup) - if ((con_curlines == con_destlines) && (con_curlines >= minheight) && !con_startup) + if ((con_curlines >= (minheight-charheight)) && !con_startup) CON_DrawInput(); } @@ -1875,6 +1888,10 @@ void CON_Drawer(void) CON_ClearHUD(); } + // console movement + if (con_curlines != con_destlines) + CON_MoveConsole(); + if (con_curlines > 0) CON_DrawConsole(); else if (CON_GamestateDrawHudLines() == true) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d5023265f..65cb6d067 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -118,7 +118,7 @@ UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values. #define GENTLEMANSMOOTHING (TICRATE) static tic_t reference_lag; -static UINT8 spike_time; +static UINT8 spike_time; static tic_t lowest_lag; boolean server_lagless; static CV_PossibleValue_t mindelay_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}}; @@ -266,7 +266,7 @@ shouldsign_t ShouldSignChallenge(uint8_t *message) #ifndef SRB2_LITTLE_ENDIAN #error "FIXME: 64-bit timestamp field is not supported on Big Endian" #endif - + UINT64 then, now; UINT32 claimedIP, realIP; @@ -2280,7 +2280,7 @@ static void CL_ConnectToServer(void) { PR_ApplyProfile(cv_lastprofile[i].value, i); } - + // Slightly sucks that we have to duplicate these from d_main.c, but // the change to cv_lastprofile doesn't take in time for this codepath. if (M_CheckParm("-profile")) @@ -2775,20 +2775,36 @@ void CL_ClearPlayer(INT32 playernum) K_RemoveFollower(&players[playernum]); } - if (players[playernum].mo) - { - P_RemoveMobj(players[playernum].mo); - P_SetTarget(&players[playernum].mo, NULL); +#define PlayerPointerRemove(field) \ + if (field) \ + { \ + P_RemoveMobj(field); \ + P_SetTarget(&field, NULL); \ } + // These are mostly subservient to the player, and may not clean themselves up. + PlayerPointerRemove(players[playernum].mo); + PlayerPointerRemove(players[playernum].followmobj); + PlayerPointerRemove(players[playernum].stumbleIndicator); + PlayerPointerRemove(players[playernum].sliptideZipIndicator); + +#undef PlayerPointerRemove + + // These have thinkers of their own. + P_SetTarget(&players[playernum].whip, NULL); + P_SetTarget(&players[playernum].hand, NULL); + P_SetTarget(&players[playernum].hoverhyudoro, NULL); + P_SetTarget(&players[playernum].ringShooter, NULL); + + // TODO: Any better handling in store? + P_SetTarget(&players[playernum].flickyAttacker, NULL); + P_SetTarget(&players[playernum].powerup.flickyController, NULL); + + // These are camera items and possibly belong to multiple players. P_SetTarget(&players[playernum].skybox.viewpoint, NULL); P_SetTarget(&players[playernum].skybox.centerpoint, NULL); P_SetTarget(&players[playernum].awayview.mobj, NULL); - P_SetTarget(&players[playernum].followmobj, NULL); - P_SetTarget(&players[playernum].hoverhyudoro, NULL); - P_SetTarget(&players[playernum].stumbleIndicator, NULL); - P_SetTarget(&players[playernum].sliptideZipIndicator, NULL); - P_SetTarget(&players[playernum].ringShooter, NULL); + } // Handle parties. @@ -4029,7 +4045,7 @@ static void Got_AddBot(UINT8 **p, INT32 playernum) K_SetBot(newplayernum, skinnum, difficulty, style); } -static boolean SV_AddWaitingPlayers(SINT8 node, UINT8 *availabilities, +static boolean SV_AddWaitingPlayers(SINT8 node, UINT8 *availabilities, const char *name, uint8_t *key, UINT16 *pwr, const char *name2, uint8_t *key2, UINT16 *pwr2, const char *name3, uint8_t *key3, UINT16 *pwr3, @@ -4192,9 +4208,15 @@ boolean SV_SpawnServer(void) serverrunning = true; SV_ResetServer(); SV_GenContext(); - if (netgame && I_NetOpenSocket) + if (netgame) { - I_NetOpenSocket(); + if (I_NetOpenSocket) + { + I_NetOpenSocket(); + } + + ourIP = 0; + STUN_bind(GotOurIP); } // non dedicated server just connect to itself @@ -4203,9 +4225,7 @@ boolean SV_SpawnServer(void) else doomcom->numslots = 1; } - ourIP = 0; - if (netgame && server) - STUN_bind(GotOurIP); + // strictly speaking, i'm not convinced the following is necessary // but I'm not confident enough to remove it entirely in case it breaks something @@ -4438,19 +4458,19 @@ static void HandleConnect(SINT8 node) memcpy(lastReceivedKey[node][i], PR_GetLocalPlayerProfile(i)->public_key, sizeof(lastReceivedKey[node][i])); } else // Remote player, gotta check their signature. - { + { if (PR_IsKeyGuest(lastReceivedKey[node][i])) // IsSplitPlayerOnNodeGuest isn't appropriate here, they're not in-game yet! { if (!cv_allowguests.value) { SV_SendRefuse(node, M_GetText("The server doesn't allow GUESTs.\nCreate a profile to join!")); - return; + return; } sigcheck = 0; // Always succeeds. Yes, this is a success response. C R Y P T O } else - { + { sigcheck = crypto_eddsa_check(netbuffer->u.clientcfg.challengeResponse[i], lastReceivedKey[node][i], lastSentChallenge[node], CHALLENGELENGTH); } @@ -4473,7 +4493,7 @@ static void HandleConnect(SINT8 node) CONS_Alert(CONS_WARNING, "Joining player's pubkey matches existing player, stat updates will be nonsense!\n"); #else SV_SendRefuse(node, M_GetText("Duplicate pubkey already on server.\n(Did you share your profile?)")); - return; + return; #endif } } @@ -4491,7 +4511,7 @@ static void HandleConnect(SINT8 node) CONS_Alert(CONS_WARNING, "Players with same pubkey in the joning party, stat updates will be nonsense!\n"); #else SV_SendRefuse(node, M_GetText("Duplicate pubkey in local party.\n(How did you even do this?)")); - return; + return; #endif } } @@ -5013,7 +5033,7 @@ static void PT_Say(int node) return; } - stop_spamming[say.source] = 4; + stop_spamming[say.source] = 4; serverplayer_t *stats = SV_GetStatsByPlayerIndex(say.source); @@ -5044,7 +5064,7 @@ static char NodeToSplitPlayer(int node, int split) else if (split == 3) return nodetoplayer4[node]; return -1; -} +} /** Handles a packet received from a node that is in game * @@ -5073,7 +5093,7 @@ static void HandlePacketFromPlayer(SINT8 node) if (netconsole >= MAXPLAYERS) I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole); #endif - + #ifdef SIGNGAMETRAFFIC if (server) @@ -5097,10 +5117,10 @@ static void HandlePacketFromPlayer(SINT8 node) { if (crypto_eddsa_check(netbuffer->signature[splitnodes], players[targetplayer].public_key, message, doomcom->datalength - BASEPACKETSIZE)) { - CONS_Alert(CONS_ERROR, "SIGFAIL! Packet type %d from node %d player %d\nkey %s size %d netconsole %d\n", + CONS_Alert(CONS_ERROR, "SIGFAIL! Packet type %d from node %d player %d\nkey %s size %d netconsole %d\n", netbuffer->packettype, node, splitnodes, GetPrettyRRID(players[targetplayer].public_key, true), doomcom->datalength - BASEPACKETSIZE, netconsole); - + // Something scary can happen when multiple kicks that resolve to the same node are processed in quick succession. // Sometimes, a kick will still be left to process after the player's been disposed, and that causes the kick to resolve on the server instead! // This sucks, so we check for a stale/misfiring kick beforehand. @@ -5111,7 +5131,7 @@ static void HandlePacketFromPlayer(SINT8 node) return; } } - + } } } @@ -5635,7 +5655,7 @@ static void HandlePacketFromPlayer(SINT8 node) SendKick(targetplayer, KICK_MSG_SIGFAIL); break; } - else + else { memcpy(lastReceivedSignature[targetplayer], netbuffer->u.responseall.signature[responseplayer], sizeof(lastReceivedSignature[targetplayer])); } @@ -5987,7 +6007,7 @@ static void CL_SendClientCmd(void) lagDelay = reference_lag; } } - else + else { reference_lag = lagDelay; // Adjust quickly if the connection improves. spike_time = 0; @@ -6601,10 +6621,10 @@ static void KickUnverifiedPlayers(void) SendKick(i, KICK_MSG_SIGFAIL); } } - } + } } -// +// static void SendChallengeResults(void) { int i; @@ -7130,5 +7150,5 @@ void SendServerNotice(SINT8 target, char *message) { if (client) return; - DoSayCommand(message, target + 1, HU_PRIVNOTICE, servernode); + DoSayCommand(message, target + 1, HU_PRIVNOTICE, servernode); } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 823099cf6..35c3fed88 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -430,7 +430,7 @@ static CV_PossibleValue_t kartbot_cons_t[] = { {13,"Lv.MAX"}, {0, NULL} }; -consvar_t cv_kartbot = CVAR_INIT ("bots", "0", CV_NETVAR, kartbot_cons_t, NULL); +consvar_t cv_kartbot = CVAR_INIT ("bots", "Off", CV_NETVAR, kartbot_cons_t, NULL); consvar_t cv_karteliminatelast = CVAR_INIT ("eliminatelast", "Yes", CV_NETVAR|CV_CALL, CV_YesNo, KartEliminateLast_OnChange); @@ -1497,9 +1497,9 @@ static void SendNameAndColor(const UINT8 n) UINT16 sendFollowerColor = cv_followercolor[n].value; // don't allow inaccessible colors - if (sendColor != SKINCOLOR_NONE && K_ColorUsable(sendColor, false) == false) + if (sendColor != SKINCOLOR_NONE && K_ColorUsable(sendColor, false, true) == false) { - if (player->skincolor && K_ColorUsable(player->skincolor, false) == true) + if (player->skincolor && K_ColorUsable(player->skincolor, false, true) == true) { // Use our previous color CV_StealthSetValue(&cv_playercolor[n], player->skincolor); @@ -1514,7 +1514,7 @@ static void SendNameAndColor(const UINT8 n) } // ditto for follower colour: - if (sendFollowerColor != SKINCOLOR_NONE && K_ColorUsable(sendFollowerColor, true) == false) + if (sendFollowerColor != SKINCOLOR_NONE && K_ColorUsable(sendFollowerColor, true, true) == false) { CV_StealthSet(&cv_followercolor[n], "Default"); // set it to "Default". I don't care about your stupidity! sendFollowerColor = cv_followercolor[n].value; @@ -1724,7 +1724,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) boolean kick = false; // don't allow inaccessible colors - if (K_ColorUsable(p->skincolor, false) == false) + if (K_ColorUsable(p->skincolor, false, false) == false) { kick = true; } @@ -6829,7 +6829,7 @@ static void Color_OnChange(const UINT8 p) I_Assert(p < MAXSPLITSCREENPLAYERS); UINT16 color = cv_playercolor[p].value; - boolean colorisgood = (color == SKINCOLOR_NONE || K_ColorUsable(color, false) == true); + boolean colorisgood = (color == SKINCOLOR_NONE || K_ColorUsable(color, false, true) == true); if (Playing() && splitscreen < p) { diff --git a/src/deh_tables.c b/src/deh_tables.c index d43c6457e..da72e26ec 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -6577,6 +6577,7 @@ struct int_const_s const INT_CONST[] = { {"DMG_KARMA",DMG_KARMA}, {"DMG_VOLTAGE",DMG_VOLTAGE}, {"DMG_STUMBLE",DMG_STUMBLE}, + {"DMG_WHUMBLE",DMG_WHUMBLE}, //// Death types {"DMG_INSTAKILL",DMG_INSTAKILL}, {"DMG_DEATHPIT",DMG_DEATHPIT}, diff --git a/src/g_game.c b/src/g_game.c index 1280a8319..708479fbc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2455,10 +2455,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT32 followerskin; UINT16 followercolor; - mobj_t *follower; // old follower, will probably be removed by the time we're dead but you never know. - mobj_t *hoverhyudoro; - mobj_t *skyboxviewpoint; - mobj_t *skyboxcenterpoint; + mobj_t *ringShooter, *hoverhyudoro; + mobj_t *skyboxviewpoint, *skyboxcenterpoint; INT32 charflags; UINT32 followitem; @@ -2677,22 +2675,40 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) if (!betweenmaps) { - follower = players[player].follower; - P_SetTarget(&players[player].follower, NULL); - P_SetTarget(&players[player].awayview.mobj, NULL); - P_SetTarget(&players[player].stumbleIndicator, NULL); + K_RemoveFollower(&players[player]); + +#define PlayerPointerRemove(field) \ + if (field) \ + { \ + P_RemoveMobj(field); \ + P_SetTarget(&field, NULL); \ + } + + // These are mostly subservient to the player, and may not clean themselves up. + PlayerPointerRemove(players[player].followmobj); + PlayerPointerRemove(players[player].stumbleIndicator); + PlayerPointerRemove(players[player].sliptideZipIndicator); + +#undef PlayerPointerRemove + + // These will erase themselves. P_SetTarget(&players[player].whip, NULL); P_SetTarget(&players[player].hand, NULL); - P_SetTarget(&players[player].ringShooter, NULL); - P_SetTarget(&players[player].followmobj, NULL); + // TODO: Any better handling in store? + P_SetTarget(&players[player].awayview.mobj, NULL); + P_SetTarget(&players[player].flickyAttacker, NULL); + P_SetTarget(&players[player].powerup.flickyController, NULL); + + // The following pointers are safe to set directly, because the end goal should be refcount consistency before and after remanifestation. + ringShooter = players[player].ringShooter; hoverhyudoro = players[player].hoverhyudoro; skyboxviewpoint = players[player].skybox.viewpoint; skyboxcenterpoint = players[player].skybox.centerpoint; } else { - follower = hoverhyudoro = NULL; + ringShooter = hoverhyudoro = NULL; skyboxviewpoint = skyboxcenterpoint = NULL; } @@ -2769,9 +2785,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) if (saveroundconditions) memcpy(&p->roundconditions, &roundconditions, sizeof (p->roundconditions)); - if (follower) - P_RemoveMobj(follower); - + // See above comment about refcount consistency. + p->ringShooter = ringShooter; p->hoverhyudoro = hoverhyudoro; p->skybox.viewpoint = skyboxviewpoint; p->skybox.centerpoint = skyboxcenterpoint; diff --git a/src/k_collide.cpp b/src/k_collide.cpp index 2f65d1536..4f920ea1e 100644 --- a/src/k_collide.cpp +++ b/src/k_collide.cpp @@ -888,7 +888,7 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim) // while still behaving as if it's a "real" hit. P_PlayRinglossSound(victim); P_PlayerRingBurst(victimPlayer, 5); - P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a special exception in P_DamageMobj for type==MT_INSTAWHIP + P_DamageMobj(victim, shield, attacker, 1, DMG_WHUMBLE); K_DropPowerUps(victimPlayer); diff --git a/src/k_color.c b/src/k_color.c index 9078fc6bc..27d597f87 100644 --- a/src/k_color.c +++ b/src/k_color.c @@ -217,11 +217,11 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) } /*-------------------------------------------------- - boolean K_ColorUsable(skincolornum_t color, boolean follower) + boolean K_ColorUsable(skincolornum_t color, boolean follower, boolean locked) See header file for description. --------------------------------------------------*/ -boolean K_ColorUsable(skincolornum_t color, boolean follower) +boolean K_ColorUsable(skincolornum_t color, boolean follower, boolean locked) { INT32 i = MAXUNLOCKABLES; @@ -237,7 +237,7 @@ boolean K_ColorUsable(skincolornum_t color, boolean follower) return false; } - if (demo.playback) + if (demo.playback || !locked) { // Simplifies things elsewhere... return true; diff --git a/src/k_color.h b/src/k_color.h index b835f9194..a66626f62 100644 --- a/src/k_color.h +++ b/src/k_color.h @@ -117,7 +117,7 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); /*-------------------------------------------------- - boolean K_ColorUsable(skincolornum_t color, skin_t *skin, follower_t *follower); + boolean K_ColorUsable(skincolornum_t color, skin_t *skin, follower_t *follower, boolean locked); Determines whenever or not we meet the unlockable conditions to use a certain color. @@ -125,12 +125,13 @@ void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); Input Arguments:- color - Color we want to use. follower - Set to include the special follower-only color options. + locked - use local player's unlocks. Return:- true if we can use it, otherwise false. --------------------------------------------------*/ -boolean K_ColorUsable(skincolornum_t color, boolean follower); +boolean K_ColorUsable(skincolornum_t color, boolean follower, boolean locked); #ifdef __cplusplus diff --git a/src/k_follower.c b/src/k_follower.c index 511e81932..b1e4261b0 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -722,7 +722,7 @@ void K_FollowerHornTaunt(player_t *taunter, player_t *victim) || victim == NULL || taunter->followerskin < 0 || taunter->followerskin >= numfollowers - || (P_IsLocalPlayer(victim) == false && cv_karthorns.value != 2) + || (P_IsDisplayPlayer(victim) == false && cv_karthorns.value != 2) || P_MobjWasRemoved(taunter->mo) == true || P_MobjWasRemoved(taunter->follower) == true ) diff --git a/src/k_hud.c b/src/k_hud.c index f60aff730..6c3a1d283 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3994,8 +3994,6 @@ static void K_drawKartMinimap(void) if (doprogressionbar == false) { - angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); - interpx = R_InterpolateFixed(mobj->old_x, mobj->x); interpy = R_InterpolateFixed(mobj->old_y, mobj->y); @@ -4010,6 +4008,10 @@ static void K_drawKartMinimap(void) if (!nocontest) { + angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); + if (encoremode) + ang = ANGLE_180 - ang; + K_drawKartMinimapIcon( interpx, interpy, @@ -4198,8 +4200,6 @@ static void K_drawKartMinimap(void) if (doprogressionbar == false) { - angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); - interpx = R_InterpolateFixed(mobj->old_x, mobj->x); interpy = R_InterpolateFixed(mobj->old_y, mobj->y); @@ -4214,6 +4214,10 @@ static void K_drawKartMinimap(void) if (!nocontest) { + angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle); + if (encoremode) + ang = ANGLE_180 - ang; + K_drawKartMinimapIcon( interpx, interpy, diff --git a/src/k_kart.c b/src/k_kart.c index cd33715ac..83a6039b2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -8068,9 +8068,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->guardCooldown) player->guardCooldown--; - if (player->whip && P_MobjWasRemoved(player->whip)) - P_SetTarget(&player->whip, NULL); - if (player->startboost > 0 && onground == true) { player->startboost--; @@ -8328,20 +8325,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->tripwireState = TRIPSTATE_NONE; } - if (player->hand && P_MobjWasRemoved(player->hand)) - P_SetTarget(&player->hand, NULL); - - if (player->flickyAttacker && P_MobjWasRemoved(player->flickyAttacker)) - P_SetTarget(&player->flickyAttacker, NULL); - - if (player->powerup.flickyController && P_MobjWasRemoved(player->powerup.flickyController)) - P_SetTarget(&player->powerup.flickyController, NULL); - if (player->spectator == false) { K_KartEbrakeVisuals(player); - Obj_ServantHandHandling(player); + Obj_ServantHandSpawning(player); } if (K_GetKartButtons(player) & BT_BRAKE && diff --git a/src/k_objects.h b/src/k_objects.h index ca2bec744..ab4d259e6 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -144,7 +144,8 @@ void Obj_GachaBomReboundThink(mobj_t *mobj); void Obj_SpawnGachaBomRebound(mobj_t *source, mobj_t *target); /* Servant Hand */ -void Obj_ServantHandHandling(player_t *player); +void Obj_ServantHandSpawning(player_t *player); +void Obj_ServantHandThink(mobj_t *hand); void Obj_PointPlayersToXY(fixed_t x, fixed_t y); /* Super Flicky Controller */ diff --git a/src/k_profiles.c b/src/k_profiles.c index 63dccc8b7..f0a0a8e89 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -373,7 +373,7 @@ void PR_LoadProfiles(void) ; // Valid, even outside the bounds } else if (profilesList[i]->color >= numskincolors - || K_ColorUsable(profilesList[i]->color, false) == false) + || K_ColorUsable(profilesList[i]->color, false, false) == false) { profilesList[i]->color = PROFILEDEFAULTCOLOR; } @@ -383,13 +383,13 @@ void PR_LoadProfiles(void) profilesList[i]->followercolor = READUINT16(save.p); if (profilesList[i]->followercolor == FOLLOWERCOLOR_MATCH - || profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE) + || profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE + || profilesList[i]->followercolor == SKINCOLOR_NONE) { ; // Valid, even outside the bounds } else if (profilesList[i]->followercolor >= numskincolors - || profilesList[i]->followercolor == SKINCOLOR_NONE - || K_ColorUsable(profilesList[i]->followercolor, true) == false) + || K_ColorUsable(profilesList[i]->followercolor, true, false) == false) { profilesList[i]->followercolor = PROFILEDEFAULTFOLLOWERCOLOR; } diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 12a5f2ff3..965e9dd42 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -341,7 +341,7 @@ static int lib_cvRegisterVar(lua_State *L) } else if (i == 4 || (k && fasticmp(k, "PossibleValue"))) { if (lua_islightuserdata(L, 4)) { CV_PossibleValue_t *pv = lua_touserdata(L, 4); - if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural) + if (pv == CV_OnOff || pv == CV_YesNo || pv == CV_Unsigned || pv == CV_Natural || pv == CV_TrueFalse) cvar->PossibleValue = pv; else FIELDERROR("PossibleValue", "CV_PossibleValue_t expected, got unrecognised pointer") @@ -577,6 +577,8 @@ int LUA_ConsoleLib(lua_State *L) lua_setglobal(L, "CV_Unsigned"); lua_pushlightuserdata(L, CV_Natural); lua_setglobal(L, "CV_Natural"); + lua_pushlightuserdata(L, CV_TrueFalse); + lua_setglobal(L, "CV_TrueFalse"); // Set global functions lua_pushvalue(L, LUA_GLOBALSINDEX); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 282279a71..9e7253e97 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -409,8 +409,12 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->trickboostdecay); else if (fastcmp(field,"trickboost")) lua_pushinteger(L, plr->trickboost); + else if (fastcmp(field,"dashRingPullTics")) + lua_pushinteger(L, plr->dashRingPullTics); + else if (fastcmp(field,"dashRingPushTics")) + lua_pushinteger(L, plr->dashRingPushTics); else if (fastcmp(field,"roundscore")) - plr->roundscore = luaL_checkinteger(L, 3); + lua_pushinteger(L, plr->roundscore); else if (fastcmp(field,"emeralds")) lua_pushinteger(L, plr->emeralds); else if (fastcmp(field,"karmadelay")) @@ -730,7 +734,7 @@ static int player_set(lua_State *L) else if (fastcmp(field,"sliptideZipBoost")) plr->sliptideZipBoost = luaL_checkinteger(L, 3); else if (fastcmp(field,"instaShieldCooldown")) - plr->instaShieldCooldown = luaL_checkinteger(L, 3); + plr->instaShieldCooldown = luaL_checkinteger(L, 3); else if (fastcmp(field,"guardCooldown")) plr->guardCooldown = luaL_checkinteger(L, 3); /* @@ -813,8 +817,12 @@ static int player_set(lua_State *L) plr->trickboostdecay = luaL_checkinteger(L, 3); else if (fastcmp(field,"trickboost")) plr->trickboost = luaL_checkinteger(L, 3); + else if (fastcmp(field,"dashRingPullTics")) + plr->dashRingPullTics = luaL_checkinteger(L, 3); + else if (fastcmp(field,"dashRingPushTics")) + plr->dashRingPushTics = luaL_checkinteger(L, 3); else if (fastcmp(field,"roundscore")) - lua_pushinteger(L, plr->roundscore); + plr->roundscore = luaL_checkinteger(L, 3); else if (fastcmp(field,"emeralds")) plr->emeralds = luaL_checkinteger(L, 3); else if (fastcmp(field,"karmadelay")) diff --git a/src/menus/play-char-select.c b/src/menus/play-char-select.c index 111c24ed8..257f0ad06 100644 --- a/src/menus/play-char-select.c +++ b/src/menus/play-char-select.c @@ -150,7 +150,7 @@ static void M_NewPlayerColors(setup_player_t *p) // Add all unlocked colors for (i = SKINCOLOR_NONE+1; i < numskincolors; i++) { - if (K_ColorUsable(i, follower) == true) + if (K_ColorUsable(i, follower, true) == true) { M_PushMenuColor(&p->colors, i); } diff --git a/src/objects/ring-shooter.c b/src/objects/ring-shooter.c index 3150cf16f..c9812a6b8 100644 --- a/src/objects/ring-shooter.c +++ b/src/objects/ring-shooter.c @@ -63,8 +63,11 @@ static void RemoveRingShooterPointer(mobj_t *base) } // NULL the player's pointer. - player = &players[ rs_base_playerid(base) ]; - P_SetTarget(&player->ringShooter, NULL); + if (playeringame[ rs_base_playerid(base) ]) + { + player = &players[ rs_base_playerid(base) ]; + P_SetTarget(&player->ringShooter, NULL); + } // Remove our player ID rs_base_playerid(base) = -1; diff --git a/src/objects/servant-hand.c b/src/objects/servant-hand.c index 2b9cb7527..80c149cde 100644 --- a/src/objects/servant-hand.c +++ b/src/objects/servant-hand.c @@ -8,7 +8,7 @@ #include "../r_main.h" #include "../g_game.h" -void Obj_ServantHandHandling(player_t *player) +void Obj_ServantHandSpawning(player_t *player) { if (player->pflags & PF_WRONGWAY || player->pflags & PF_POINTME) { @@ -36,71 +36,86 @@ void Obj_ServantHandHandling(player_t *player) } } } - - if (player->hand) - { - player->hand->destscale = mapobjectscale; - } } else if (player->handtimer != 0) { player->handtimer--; } +} + +void Obj_ServantHandThink(mobj_t *hand) +{ + UINT8 handtimer = 0; + player_t *player = NULL; + + if (P_MobjWasRemoved(hand->target)) + { + P_RemoveMobj(hand); + return; + } + + if (hand->target->health && hand->target->player && hand->target->player->hand == hand) + { + player = hand->target->player; + handtimer = hand->target->player->handtimer; + } - if (player->hand) { const fixed_t handpokespeed = 4; - const fixed_t looping = handpokespeed - abs((player->hand->threshold % (handpokespeed*2)) - handpokespeed); + const fixed_t looping = handpokespeed - abs((hand->threshold % (handpokespeed*2)) - handpokespeed); fixed_t xoffs = 0, yoffs = 0; - player->hand->color = player->skincolor; - player->hand->angle = player->besthanddirection; - - if (player->hand->fuse != 0) + if (hand->fuse != 0) { ; } else if (looping != 0) { - xoffs = FixedMul(2 * looping * mapobjectscale, FINECOSINE(player->hand->angle >> ANGLETOFINESHIFT)), - yoffs = FixedMul(2 * looping * mapobjectscale, FINESINE(player->hand->angle >> ANGLETOFINESHIFT)), + xoffs = FixedMul(2 * looping * mapobjectscale, FINECOSINE(hand->angle >> ANGLETOFINESHIFT)), + yoffs = FixedMul(2 * looping * mapobjectscale, FINESINE(hand->angle >> ANGLETOFINESHIFT)), - player->hand->threshold++; + hand->threshold++; } - else if (player->handtimer == 0) + else if (handtimer == 0) { - player->hand->fuse = 8; + hand->fuse = 8; } else { - player->hand->threshold++; + hand->threshold++; } - if (player->hand->fuse != 0) + if (hand->fuse != 0) { - if ((player->hand->fuse > 4) ^ (player->handtimer < TICRATE/2)) + if ((hand->fuse > 4) ^ (handtimer < TICRATE/2)) { - player->hand->spritexscale = FRACUNIT/3; - player->hand->spriteyscale = 3*FRACUNIT; + hand->spritexscale = FRACUNIT/3; + hand->spriteyscale = 3*FRACUNIT; } else { - player->hand->spritexscale = 2*FRACUNIT; - player->hand->spriteyscale = FRACUNIT/2; + hand->spritexscale = 2*FRACUNIT; + hand->spriteyscale = FRACUNIT/2; } } - P_MoveOrigin(player->hand, - player->mo->x + xoffs, - player->mo->y + yoffs, - player->mo->z + player->mo->height + 30*mapobjectscale - ); - K_FlipFromObject(player->hand, player->mo); + if (player != NULL) + { + hand->color = player->skincolor; + hand->angle = player->besthanddirection; - player->hand->sprzoff = player->mo->sprzoff; + P_MoveOrigin(hand, + player->mo->x + xoffs, + player->mo->y + yoffs, + player->mo->z + player->mo->height + 30*mapobjectscale + ); + K_FlipFromObject(hand, player->mo); - player->hand->renderflags &= ~RF_DONTDRAW; - player->hand->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player)); + hand->sprzoff = player->mo->sprzoff; + + hand->renderflags &= ~RF_DONTDRAW; + hand->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player)); + } } } diff --git a/src/p_inter.c b/src/p_inter.c index 66e860aec..a358184c9 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2331,7 +2331,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da invincible = false; } - if (invincible && type != DMG_STUMBLE) + if (invincible && type != DMG_STUMBLE && type != DMG_WHUMBLE) { const INT32 oldHitlag = target->hitlag; const INT32 oldHitlagInflictor = inflictor ? inflictor->hitlag : 0; @@ -2389,7 +2389,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da { // Check if we should allow wombo combos (hard hits by default, inverted by the presence of DMG_WOMBO). - boolean allowcombo = ((hardhit || (type == DMG_STUMBLE)) == !(damagetype & DMG_WOMBO)); + boolean allowcombo = ((hardhit || (type == DMG_STUMBLE || type == DMG_WHUMBLE)) == !(damagetype & DMG_WOMBO)); // Tumble/stumble is a special case. if (type == DMG_TUMBLE) @@ -2398,11 +2398,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (player->tumbleBounces == 1 && (P_MobjFlip(target)*target->momz > 0)) allowcombo = false; } - else if (type == DMG_STUMBLE) + else if (type == DMG_STUMBLE || type == DMG_WHUMBLE) { // don't allow constant combo if (player->tumbleBounces == TUMBLEBOUNCES-1 && (P_MobjFlip(target)*target->momz > 0)) + { + if (type == DMG_STUMBLE) + return false; // No-sell strings of stumble + allowcombo = false; + } } if (allowcombo == false && (target->eflags & MFE_PAUSED)) @@ -2411,7 +2416,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } // DMG_EXPLODE excluded from flashtic checks to prevent dodging eggbox/SPB with weak spinout - if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0 && type != DMG_EXPLODE && type != DMG_STUMBLE) + if ((target->hitlag == 0 || allowcombo == false) && player->flashing > 0 && type != DMG_EXPLODE && type != DMG_STUMBLE && type != DMG_WHUMBLE) { // Post-hit invincibility K_DoInstashield(player); @@ -2439,9 +2444,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da damage = 0; } - // Instawhip breaks the rules and does "damaging stumble", - // but sting and stumble shouldn't be rewarding Battle hits otherwise. - if ((type == DMG_STING || type == DMG_STUMBLE) && !(inflictor && inflictor->type == MT_INSTAWHIP)) + // Sting and stumble shouldn't be rewarding Battle hits. + if (type == DMG_STING || type == DMG_STUMBLE) { damage = 0; } @@ -2537,6 +2541,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da ringburst = 0; break; case DMG_STUMBLE: + case DMG_WHUMBLE: K_StumblePlayer(player); ringburst = 0; break; @@ -2559,7 +2564,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da break; } - if (type != DMG_STUMBLE) + if (type != DMG_STUMBLE && type != DMG_WHUMBLE) { if (type != DMG_STING) player->flashing = K_GetKartFlashing(player); diff --git a/src/p_local.h b/src/p_local.h index 6b5846145..98168afe2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -544,6 +544,7 @@ struct BasicFF_t #define DMG_KARMA 0x05 // Karma Bomb explosion -- works like DMG_EXPLODE, but steals half of their bumpers & deletes the rest #define DMG_VOLTAGE 0x06 #define DMG_STUMBLE 0x07 +#define DMG_WHUMBLE 0x08 //// Death types - cannot be combined with damage types #define DMG_INSTAKILL 0x80 #define DMG_DEATHPIT 0x81 diff --git a/src/p_mobj.c b/src/p_mobj.c index 67c60aa93..acc48e89a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7385,6 +7385,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_MantaRingThink(mobj); break; } + case MT_SERVANTHAND: + { + Obj_ServantHandThink(mobj); + if (P_MobjWasRemoved(mobj)) + return false; + break; + } case MT_BALLHOG: { mobj_t *ghost = P_SpawnGhostMobj(mobj); @@ -9839,10 +9846,11 @@ static boolean P_FuseThink(mobj_t *mobj) } case MT_SERVANTHAND: { - if (!mobj->target - || P_MobjWasRemoved(mobj->target) + if (P_MobjWasRemoved(mobj->target) + || !mobj->target->health || !mobj->target->player - || mobj->target->player->handtimer == 0) + || mobj->target->player->handtimer == 0 + || mobj->target->player->hand != mobj) { P_RemoveMobj(mobj); return false; @@ -13811,8 +13819,15 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi y + FixedMul(length, FINESINE(fineangle)), z, MT_LOOPCENTERPOINT); - if (!P_MobjWasRemoved(loopanchor)) - Obj_LinkLoopAnchor(loopanchor, loopcenter, mthing->args[0]); + if (P_MobjWasRemoved(loopanchor)) + { + // No recovery. + return; + } + + loopanchor->spawnpoint = NULL; + + Obj_LinkLoopAnchor(loopanchor, loopcenter, mthing->args[0]); } for (r = 0; r < numitems; r++) @@ -13832,15 +13847,15 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numi if (!inclusive) mobj = P_SpawnMobjFromMapThing(&dummything, x, y, z, itemtype); - if (!mobj) + if (P_MobjWasRemoved(mobj)) continue; - if (isloopend) - { - Obj_InitLoopEndpoint(mobj, loopanchor); - } - mobj->spawnpoint = NULL; + + if (!isloopend) + continue; + + Obj_InitLoopEndpoint(mobj, loopanchor); } } @@ -13898,11 +13913,12 @@ static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 n mobj = P_SpawnMobjFromMapThing(&dummything, x + v[0], y + v[1], z + v[2], itemtype); - if (!mobj) + if (P_MobjWasRemoved(mobj)) continue; - mobj->z -= mobj->height/2; mobj->spawnpoint = NULL; + + mobj->z -= mobj->height/2; } } diff --git a/src/p_saveg.c b/src/p_saveg.c index 885b7b5c0..c3db1351f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -185,7 +185,7 @@ static boolean P_UnArchivePlayer(savebuffer_t *save) savedata.bots[pid].score = READUINT32(save->p); } - return (pid == 0xFE); + return (pid == 0xFE); } static void P_NetArchivePlayers(savebuffer_t *save) @@ -500,6 +500,9 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, players[i].trickboostdecay); WRITEUINT8(save->p, players[i].trickboost); + WRITEUINT8(save->p, players[i].dashRingPullTics); + WRITEUINT8(save->p, players[i].dashRingPushTics); + WRITEUINT32(save->p, players[i].ebrakefor); WRITEUINT32(save->p, players[i].roundscore); @@ -918,6 +921,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) players[i].trickboostdecay = READUINT8(save->p); players[i].trickboost = READUINT8(save->p); + players[i].dashRingPullTics = READUINT8(save->p); + players[i].dashRingPushTics = READUINT8(save->p); + players[i].ebrakefor = READUINT32(save->p); players[i].roundscore = READUINT32(save->p); @@ -4074,7 +4080,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) if (diff2 & MD2_RENDERFLAGS) mobj->renderflags = READUINT32(save->p); if (diff2 & MD2_TID) - P_SetThingTID(mobj, READINT16(save->p)); + { + INT16 tid = READINT16(save->p); + P_SetThingTID(mobj, tid); + } if (diff2 & MD2_SPRITESCALE) { mobj->spritexscale = READFIXED(save->p); @@ -5662,7 +5671,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) } WRITEUINT8(save->p, encoremode); - + WRITEUINT8(save->p, mapmusrng); WRITEUINT32(save->p, leveltime); @@ -5833,7 +5842,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) } encoremode = (boolean)READUINT8(save->p); - + mapmusrng = READUINT8(save->p); if (!P_LoadLevel(true, reloading)) diff --git a/src/p_user.c b/src/p_user.c index 74b5d6231..00d3420ab 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4249,6 +4249,25 @@ void P_PlayerThink(player_t *player) player->playerstate = PST_DEAD; } + // Erasing invalid player pointers + { +#define PlayerPointerErase(field) \ + if (field && P_MobjWasRemoved(field)) \ + P_SetTarget(&field, NULL); \ + + PlayerPointerErase(player->followmobj); + PlayerPointerErase(player->stumbleIndicator); + PlayerPointerErase(player->sliptideZipIndicator); + PlayerPointerErase(player->whip); + PlayerPointerErase(player->hand); + PlayerPointerErase(player->ringShooter); + PlayerPointerErase(player->hoverhyudoro); + PlayerPointerErase(player->flickyAttacker); + PlayerPointerErase(player->powerup.flickyController); + +#undef PlayerPointerErase + } + player->old_drawangle = player->drawangle; P_TickAltView(&player->awayview); @@ -4302,7 +4321,7 @@ void P_PlayerThink(player_t *player) else if (player->kickstartaccel < ACCEL_KICKSTART) { player->kickstartaccel++; - if ((player->kickstartaccel == ACCEL_KICKSTART) && P_IsLocalPlayer(player)) + if ((player->kickstartaccel == ACCEL_KICKSTART) && !K_PlayerUsesBotMovement(player) && P_IsDisplayPlayer(player)) { S_StartSound(NULL, sfx_ding); } diff --git a/src/v_video.cpp b/src/v_video.cpp index 5c06f45e8..17519f894 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1083,8 +1083,6 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) .done(); } -#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; @@ -1095,26 +1093,25 @@ static UINT32 V_GetHWConsBackColor(void) 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 + case 5: hwcolor = 0xff000000; break; // Red + case 6: hwcolor = 0xff800000; break; // Orange + case 7: hwcolor = 0xdaa52000; break; // Gold + case 8: hwcolor = 0xffdd0000; break; // Yellow + case 9: hwcolor = 0xc5e80000; break; // Peridot + case 10: hwcolor = 0x00800000; break; // Green + case 11: hwcolor = 0x15f2b000; break; // Aquamarine + case 12: hwcolor = 0x00ffff00; break; // Cyan + case 13: hwcolor = 0x4682b400; break; // Steel + case 14: hwcolor = 0x0000ff00; break; // Blue + case 15: hwcolor = 0x9844ff00; break; // Purple + case 16: hwcolor = 0xff00ff00; break; // Magenta + case 17: hwcolor = 0xee82ee00; break; // Lavender + case 18: hwcolor = 0xf570a500; break; // Rose // Default green default: hwcolor = 0x00800000; break; } return hwcolor; } -#endif // THANK YOU MPC!!! // and thanks toaster for cleaning it up. @@ -1674,31 +1671,7 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color) if (color == INT32_MAX) color = cons_backcolor.value; - UINT32 hwcolor; - switch (color) - { - case 0: hwcolor = 0xffffff00; break; // White - case 1: hwcolor = 0x00000000; break; // Black // Note this is different from V_DrawFadeConsBack - 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; - } + UINT32 hwcolor = V_GetHWConsBackColor(); #ifdef HWRENDER if (rendermode == render_opengl)