From bbbe76d2ca4a12745bb54e35be48fd1b3714cfe0 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 16 Jan 2020 03:09:02 -0800 Subject: [PATCH 01/56] Expose viewmobj as r_viewmobj --- src/r_main.c | 55 +++++++++++++++++++++++++-------------------------- src/r_state.h | 1 + 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/r_main.c b/src/r_main.c index 4cbf101b7..f25ea96fd 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -71,6 +71,7 @@ angle_t viewangle, aimingangle; fixed_t viewcos, viewsin; sector_t *viewsector; player_t *viewplayer; +mobj_t *r_viewmobj; // // precalculated math tables @@ -741,8 +742,6 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) // R_SetupFrame // -static mobj_t *viewmobj; - // WARNING: a should be unsigned but to add with 2048, it isn't! #define AIMINGTODY(a) FixedDiv((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160)>>FRACBITS, fovtan) @@ -799,16 +798,16 @@ void R_SetupFrame(player_t *player) if (player->awayviewtics) { // cut-away view stuff - viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN - I_Assert(viewmobj != NULL); - viewz = viewmobj->z + 20*FRACUNIT; + r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN + I_Assert(r_viewmobj != NULL); + viewz = r_viewmobj->z + 20*FRACUNIT; aimingangle = player->awayviewaiming; - viewangle = viewmobj->angle; + viewangle = r_viewmobj->angle; } else if (!player->spectator && chasecam) // use outside cam view { - viewmobj = NULL; + r_viewmobj = NULL; viewz = thiscam->z + (thiscam->height>>1); aimingangle = thiscam->aiming; viewangle = thiscam->angle; @@ -818,11 +817,11 @@ void R_SetupFrame(player_t *player) { viewz = player->viewz; - viewmobj = player->mo; - I_Assert(viewmobj != NULL); + r_viewmobj = player->mo; + I_Assert(r_viewmobj != NULL); aimingangle = player->aiming; - viewangle = viewmobj->angle; + viewangle = r_viewmobj->angle; if (!demoplayback && player->playerstate != PST_DEAD) { @@ -856,13 +855,13 @@ void R_SetupFrame(player_t *player) } else { - viewx = viewmobj->x; - viewy = viewmobj->y; + viewx = r_viewmobj->x; + viewy = r_viewmobj->y; viewx += quake.x; viewy += quake.y; - if (viewmobj->subsector) - viewsector = viewmobj->subsector->sector; + if (r_viewmobj->subsector) + viewsector = r_viewmobj->subsector->sector; else viewsector = R_PointInSubsector(viewx, viewy)->sector; } @@ -884,12 +883,12 @@ void R_SkyboxFrame(player_t *player) thiscam = &camera; // cut-away view stuff - viewmobj = skyboxmo[0]; + r_viewmobj = skyboxmo[0]; #ifdef PARANOIA - if (!viewmobj) + if (!r_viewmobj) { const size_t playeri = (size_t)(player - players); - I_Error("R_SkyboxFrame: viewmobj null (player %s)", sizeu1(playeri)); + I_Error("R_SkyboxFrame: r_viewmobj null (player %s)", sizeu1(playeri)); } #endif if (player->awayviewtics) @@ -920,13 +919,13 @@ void R_SkyboxFrame(player_t *player) } } } - viewangle += viewmobj->angle; + viewangle += r_viewmobj->angle; viewplayer = player; - viewx = viewmobj->x; - viewy = viewmobj->y; - viewz = viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle! + viewx = r_viewmobj->x; + viewy = r_viewmobj->y; + viewz = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle! if (mapheaderinfo[gamemap-1]) { @@ -966,29 +965,29 @@ void R_SkyboxFrame(player_t *player) else if (mh->skybox_scaley < 0) y = (campos.y - skyboxmo[1]->y) * -mh->skybox_scaley; - if (viewmobj->angle == 0) + if (r_viewmobj->angle == 0) { viewx += x; viewy += y; } - else if (viewmobj->angle == ANGLE_90) + else if (r_viewmobj->angle == ANGLE_90) { viewx -= y; viewy += x; } - else if (viewmobj->angle == ANGLE_180) + else if (r_viewmobj->angle == ANGLE_180) { viewx -= x; viewy -= y; } - else if (viewmobj->angle == ANGLE_270) + else if (r_viewmobj->angle == ANGLE_270) { viewx += y; viewy -= x; } else { - angle_t ang = viewmobj->angle>>ANGLETOFINESHIFT; + angle_t ang = r_viewmobj->angle>>ANGLETOFINESHIFT; viewx += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang)); viewy += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang)); } @@ -999,8 +998,8 @@ void R_SkyboxFrame(player_t *player) viewz += campos.z * -mh->skybox_scalez; } - if (viewmobj->subsector) - viewsector = viewmobj->subsector->sector; + if (r_viewmobj->subsector) + viewsector = r_viewmobj->subsector->sector; else viewsector = R_PointInSubsector(viewx, viewy)->sector; diff --git a/src/r_state.h b/src/r_state.h index 75566923b..e7838e9fb 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -83,6 +83,7 @@ extern fixed_t viewx, viewy, viewz; extern angle_t viewangle, aimingangle; extern sector_t *viewsector; extern player_t *viewplayer; +extern mobj_t *r_viewmobj; extern consvar_t cv_allowmlook; extern consvar_t cv_maxportals; From 542e38e717e2a8cf38a9ce5b9fa2affe56424781 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 16 Jan 2020 03:09:16 -0800 Subject: [PATCH 02/56] Don't draw player mobj in first person This solves that annoying albeit slightly amusing bug where your sprite clips into your view during a quake. For OpenGL, this also solves the player's model rendering while in first person. So you'll no longer be looking through Sonic's body! --- src/hardware/hw_main.c | 6 ++++-- src/r_things.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f5f3edfc1..e658051a6 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5422,7 +5422,8 @@ static void HWR_AddSprites(sector_t *sec) { for (thing = sec->thinglist; thing; thing = thing->snext) { - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) + if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || + thing == r_viewmobj) continue; approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); @@ -5445,7 +5446,8 @@ static void HWR_AddSprites(sector_t *sec) { // Draw everything in sector, no checks for (thing = sec->thinglist; thing; thing = thing->snext) - if (!(thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)) + if (!(thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || + thing == r_viewmobj)) HWR_ProjectSprite(thing); } diff --git a/src/r_things.c b/src/r_things.c index ef496335e..2a18c06a4 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1845,7 +1845,8 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) { for (thing = sec->thinglist; thing; thing = thing->snext) { - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) + if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || + thing == r_viewmobj) continue; approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); @@ -1868,7 +1869,8 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) { // Draw everything in sector, no checks for (thing = sec->thinglist; thing; thing = thing->snext) - if (!(thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)) + if (!(thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || + thing == r_viewmobj)) R_ProjectSprite(thing); } From 999094f2f6f395c2a63db0789c8e1545e47e13df Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Fri, 17 Jan 2020 16:11:17 -0300 Subject: [PATCH 03/56] backwards compat --- src/dehacked.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 082adda24..0dbfe3318 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9427,7 +9427,7 @@ struct { {"SH_FORCE",SH_FORCE}, {"SH_FORCEHP",SH_FORCEHP}, // to be used as a bitmask only // Mostly for use with Mario mode. - {"SH_FIREFLOWER", SH_FIREFLOWER}, + {"SH_FIREFLOWER",SH_FIREFLOWER}, {"SH_STACK",SH_STACK}, {"SH_NOSTACK",SH_NOSTACK}, @@ -9442,7 +9442,7 @@ struct { {"CR_ROPEHANG",CR_ROPEHANG}, {"CR_MACESPIN",CR_MACESPIN}, {"CR_MINECART",CR_MINECART}, - {"CR_ROLLOUT", CR_ROLLOUT}, + {"CR_ROLLOUT",CR_ROLLOUT}, {"CR_PTERABYTE",CR_PTERABYTE}, // Ring weapons (ringweapons_t) @@ -9609,7 +9609,7 @@ struct { {"NUM_WEAPONS",NUM_WEAPONS}, // Value for infinite lives - {"INFLIVES", INFLIVES}, + {"INFLIVES",INFLIVES}, // Got Flags, for player->gotflag! // Used to be MF_ for some stupid reason, now they're GF_ to stop them looking like mobjflags @@ -9671,9 +9671,10 @@ struct { {"FF_PLATFORM",FF_PLATFORM}, ///< You can jump up through this to the top. {"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity. {"FF_INTANGIBLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangible, but the sides are still solid. + {"FF_INTANGABLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangable, but the sides are still solid. {"FF_SHATTER",FF_SHATTER}, ///< Used with ::FF_BUSTUP. Bustable on mere touch. {"FF_SPINBUST",FF_SPINBUST}, ///< Used with ::FF_BUSTUP. Also bustable if you're in your spinning frames. - {"FF_STRONGBUST",FF_STRONGBUST }, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee). + {"FF_STRONGBUST",FF_STRONGBUST}, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee). {"FF_RIPPLE",FF_RIPPLE}, ///< Ripple the flats {"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. From 762223db7ceca9ed428da723c84f121c6292bf4c Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 17 Jan 2020 20:45:55 -0800 Subject: [PATCH 04/56] Duplicated code is gone, so sad --- src/hardware/hw_main.c | 44 +++----------------- src/r_things.c | 93 ++++++++++++++++++++++++------------------ src/r_things.h | 9 ++++ 3 files changed, 68 insertions(+), 78 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index e658051a6..7ab0929da 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5399,7 +5399,7 @@ static void HWR_AddSprites(sector_t *sec) #ifdef HWPRECIP precipmobj_t *precipthing; #endif - fixed_t approx_dist, limit_dist, hoop_limit_dist; + fixed_t limit_dist, hoop_limit_dist; // BSP is traversed by subsector. // A sector might have been split into several @@ -5418,37 +5418,10 @@ static void HWR_AddSprites(sector_t *sec) // If a limit exists, handle things a tiny bit different. limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS; hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; - if (limit_dist || hoop_limit_dist) + for (thing = sec->thinglist; thing; thing = thing->snext) { - for (thing = sec->thinglist; thing; thing = thing->snext) - { - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || - thing == r_viewmobj) - continue; - - approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - - if (thing->sprite == SPR_HOOP) - { - if (hoop_limit_dist && approx_dist > hoop_limit_dist) - continue; - } - else - { - if (limit_dist && approx_dist > limit_dist) - continue; - } - + if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist)) HWR_ProjectSprite(thing); - } - } - else - { - // Draw everything in sector, no checks - for (thing = sec->thinglist; thing; thing = thing->snext) - if (!(thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || - thing == r_viewmobj)) - HWR_ProjectSprite(thing); } #ifdef HWPRECIP @@ -5457,15 +5430,8 @@ static void HWR_AddSprites(sector_t *sec) { for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) { - if (precipthing->precipflags & PCF_INVISIBLE) - continue; - - approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); - - if (approx_dist > limit_dist) - continue; - - HWR_ProjectPrecipitationSprite(precipthing); + if (R_PrecipThingVisible(precipthing, limit_dist)) + HWR_ProjectPrecipitationSprite(precipthing); } } #endif diff --git a/src/r_things.c b/src/r_things.c index 2a18c06a4..2a2872a34 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1808,7 +1808,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) mobj_t *thing; precipmobj_t *precipthing; // Tails 08-25-2002 INT32 lightnum; - fixed_t approx_dist, limit_dist, hoop_limit_dist; + fixed_t limit_dist, hoop_limit_dist; if (rendermode != render_soft) return; @@ -1841,37 +1841,10 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) // If a limit exists, handle things a tiny bit different. limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS; hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS; - if (limit_dist || hoop_limit_dist) + for (thing = sec->thinglist; thing; thing = thing->snext) { - for (thing = sec->thinglist; thing; thing = thing->snext) - { - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || - thing == r_viewmobj) - continue; - - approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); - - if (thing->sprite == SPR_HOOP) - { - if (hoop_limit_dist && approx_dist > hoop_limit_dist) - continue; - } - else - { - if (limit_dist && approx_dist > limit_dist) - continue; - } - + if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist)) R_ProjectSprite(thing); - } - } - else - { - // Draw everything in sector, no checks - for (thing = sec->thinglist; thing; thing = thing->snext) - if (!(thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW || - thing == r_viewmobj)) - R_ProjectSprite(thing); } // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off @@ -1879,15 +1852,8 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) { for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) { - if (precipthing->precipflags & PCF_INVISIBLE) - continue; - - approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); - - if (approx_dist > limit_dist) - continue; - - R_ProjectPrecipitationSprite(precipthing); + if (R_PrecipThingVisible(precipthing, limit_dist)) + R_ProjectPrecipitationSprite(precipthing); } } } @@ -2582,6 +2548,55 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) } } +/* Check if thing may be drawn from our current view. */ +boolean R_ThingVisible (mobj_t *thing) +{ + return (!( + thing->sprite == SPR_NULL || + ( thing->flags2 & (MF2_DONTDRAW) ) || + thing == r_viewmobj + )); +} + +boolean R_ThingVisibleWithinDist (mobj_t *thing, + fixed_t limit_dist, + fixed_t hoop_limit_dist) +{ + fixed_t approx_dist; + + if (! R_ThingVisible(thing)) + return false; + + approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y); + + if (thing->sprite == SPR_HOOP) + { + if (hoop_limit_dist && approx_dist > hoop_limit_dist) + return false; + } + else + { + if (limit_dist && approx_dist > limit_dist) + return false; + } + + return true; +} + +/* Check if precipitation may be drawn from our current view. */ +boolean R_PrecipThingVisible (precipmobj_t *precipthing, + fixed_t limit_dist) +{ + fixed_t approx_dist; + + if (( precipthing->precipflags & PCF_INVISIBLE )) + return false; + + approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); + + return ( approx_dist <= limit_dist ); +} + // // R_DrawMasked // diff --git a/src/r_things.h b/src/r_things.h index 1b74dd74e..76587868d 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -61,6 +61,15 @@ void R_InitSprites(void); void R_ClearSprites(void); void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); +boolean R_ThingVisible (mobj_t *thing); + +boolean R_ThingVisibleWithinDist (mobj_t *thing, + fixed_t draw_dist, + fixed_t nights_draw_dist); + +boolean R_PrecipThingVisible (precipmobj_t *precipthing, + fixed_t precip_draw_dist); + /** Used to count the amount of masked elements * per portal to later group them in separate * drawnode lists. From 94a2f0bb4fd40562262f2e37a7fc392b2aa42e75 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 17 Jan 2020 20:56:32 -0800 Subject: [PATCH 05/56] Don't draw Tails' tails in first person (MF2_LINKDRAW) --- src/hardware/hw_main.c | 2 +- src/r_things.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 7ab0929da..d4682fc9d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5695,7 +5695,7 @@ static void HWR_ProjectSprite(mobj_t *thing) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) { // bodge support - not nearly as comprehensive as r_things.c, but better than nothing - if (thing->tracer->sprite == SPR_NULL || thing->tracer->flags2 & MF2_DONTDRAW) + if (! R_ThingVisible(thing->tracer)) return; } diff --git a/src/r_things.c b/src/r_things.c index 2a2872a34..cba080448 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1413,7 +1413,7 @@ static void R_ProjectSprite(mobj_t *thing) thing = thing->tracer; - if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) + if (! R_ThingVisible(thing)) return; tr_x = thing->x - viewx; From 0c7c5742a80b1fd849cf4aaa4f8f12045d4ba44b Mon Sep 17 00:00:00 2001 From: Tatsuru <44866610+Ikkarin@users.noreply.github.com> Date: Sat, 18 Jan 2020 12:06:04 -0300 Subject: [PATCH 06/56] Put cv_exitmove in the menus --- src/m_menu.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index ec4e51c9c..8d62028e4 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1584,32 +1584,33 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Players required for exit", &cv_playersforexit, 96}, {IT_STRING | IT_CVAR, NULL, "Starposts", &cv_coopstarposts, 101}, {IT_STRING | IT_CVAR, NULL, "Life sharing", &cv_cooplives, 106}, + {IT_STRING | IT_CVAR, NULL, "Post goal free roaming", &cv_exitmove, 111}, - {IT_HEADER, NULL, "Race, Competition", NULL, 115}, - {IT_STRING | IT_CVAR, NULL, "Level completion countdown", &cv_countdowntime, 121}, - {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_competitionboxes, 126}, + {IT_HEADER, NULL, "Race, Competition", NULL, 120}, + {IT_STRING | IT_CVAR, NULL, "Level completion countdown", &cv_countdowntime, 126}, + {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_competitionboxes, 131}, - {IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 135}, - {IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 141}, - {IT_STRING | IT_CVAR, NULL, "Score Limit", &cv_pointlimit, 146}, - {IT_STRING | IT_CVAR, NULL, "Overtime on Tie", &cv_overtime, 151}, - {IT_STRING | IT_CVAR, NULL, "Player respawn delay", &cv_respawntime, 156}, + {IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 140}, + {IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 146}, + {IT_STRING | IT_CVAR, NULL, "Score Limit", &cv_pointlimit, 151}, + {IT_STRING | IT_CVAR, NULL, "Overtime on Tie", &cv_overtime, 156}, + {IT_STRING | IT_CVAR, NULL, "Player respawn delay", &cv_respawntime, 161}, - {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_matchboxes, 166}, - {IT_STRING | IT_CVAR, NULL, "Weapon Rings", &cv_specialrings, 171}, - {IT_STRING | IT_CVAR, NULL, "Power Stones", &cv_powerstones, 176}, + {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_matchboxes, 171}, + {IT_STRING | IT_CVAR, NULL, "Weapon Rings", &cv_specialrings, 176}, + {IT_STRING | IT_CVAR, NULL, "Power Stones", &cv_powerstones, 181}, - {IT_STRING | IT_CVAR, NULL, "Flag respawn delay", &cv_flagtime, 186}, - {IT_STRING | IT_CVAR, NULL, "Hiding time", &cv_hidetime, 191}, + {IT_STRING | IT_CVAR, NULL, "Flag respawn delay", &cv_flagtime, 191}, + {IT_STRING | IT_CVAR, NULL, "Hiding time", &cv_hidetime, 196}, - {IT_HEADER, NULL, "Teams", NULL, 200}, - {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 206}, - {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 211}, + {IT_HEADER, NULL, "Teams", NULL, 205}, + {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 211}, + {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 216}, #ifndef NONET - {IT_HEADER, NULL, "Advanced", NULL, 220}, - {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 226}, - {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 240}, + {IT_HEADER, NULL, "Advanced", NULL, 225}, + {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 231}, + {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 245}, #endif }; @@ -10632,8 +10633,8 @@ static void M_ServerOptions(INT32 choice) OP_ServerOptionsMenu[ 2].status = IT_GRAYEDOUT; // Max players OP_ServerOptionsMenu[ 3].status = IT_GRAYEDOUT; // Allow add-on downloading OP_ServerOptionsMenu[ 4].status = IT_GRAYEDOUT; // Allow players to join - OP_ServerOptionsMenu[34].status = IT_GRAYEDOUT; // Master server - OP_ServerOptionsMenu[35].status = IT_GRAYEDOUT; // Attempts to resynchronise + OP_ServerOptionsMenu[35].status = IT_GRAYEDOUT; // Master server + OP_ServerOptionsMenu[36].status = IT_GRAYEDOUT; // Attempts to resynchronise } else { @@ -10641,10 +10642,10 @@ static void M_ServerOptions(INT32 choice) OP_ServerOptionsMenu[ 2].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[ 3].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[ 4].status = IT_STRING | IT_CVAR; - OP_ServerOptionsMenu[34].status = (netgame + OP_ServerOptionsMenu[35].status = (netgame ? IT_GRAYEDOUT : (IT_STRING | IT_CVAR | IT_CV_STRING)); - OP_ServerOptionsMenu[35].status = IT_STRING | IT_CVAR; + OP_ServerOptionsMenu[36].status = IT_STRING | IT_CVAR; } #endif From cdc3386d48a5571205dacdf981a95494c3499b36 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sat, 18 Jan 2020 12:10:48 -0300 Subject: [PATCH 07/56] Fix missing constant --- src/dehacked.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index 0dbfe3318..4c36639a2 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8847,7 +8847,7 @@ static const char *const MOBJEFLAG_LIST[] = { #ifdef HAVE_BLUA static const char *const MAPTHINGFLAG_LIST[4] = { - NULL, + "EXTRA", // Extra flag for objects. "OBJECTFLIP", // Reverse gravity flag for objects. "OBJECTSPECIAL", // Special flag used with certain objects. "AMBUSH" // Deaf monsters/do not react to sound. From 8348123a70474869d3dc9bae127e421f76fa2080 Mon Sep 17 00:00:00 2001 From: Tatsuru <44866610+Ikkarin@users.noreply.github.com> Date: Sat, 18 Jan 2020 13:15:24 -0300 Subject: [PATCH 08/56] Goal posts --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 8d62028e4..62bea7ae0 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1584,7 +1584,7 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Players required for exit", &cv_playersforexit, 96}, {IT_STRING | IT_CVAR, NULL, "Starposts", &cv_coopstarposts, 101}, {IT_STRING | IT_CVAR, NULL, "Life sharing", &cv_cooplives, 106}, - {IT_STRING | IT_CVAR, NULL, "Post goal free roaming", &cv_exitmove, 111}, + {IT_STRING | IT_CVAR, NULL, "Post-goal free roaming", &cv_exitmove, 111}, {IT_HEADER, NULL, "Race, Competition", NULL, 120}, {IT_STRING | IT_CVAR, NULL, "Level completion countdown", &cv_countdowntime, 126}, From 512435c59f2d31c8b892a5838a83df3db620c56d Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 18 Jan 2020 20:18:20 +0100 Subject: [PATCH 09/56] Fix mouse in controls setup menu --- src/m_menu.c | 6 ++++++ src/m_menu.h | 3 +++ src/sdl/i_video.c | 22 ++++++++++++++++------ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 0d19a6a43..f8c14dd69 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3645,6 +3645,12 @@ void M_SetupNextMenu(menu_t *menudef) hidetitlemap = false; } +// Guess I'll put this here, idk +boolean M_MouseNeeded(void) +{ + return (currentMenu == &MessageDef && currentMenu->prevMenu == &OP_ChangeControlsDef); +} + // // M_Ticker // diff --git a/src/m_menu.h b/src/m_menu.h index 3504868c9..3d7fb3b1c 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -320,6 +320,9 @@ typedef struct menu_s void M_SetupNextMenu(menu_t *menudef); void M_ClearMenus(boolean callexitmenufunc); +// Maybe this goes here????? Who knows. +boolean M_MouseNeeded(void); + extern menu_t *currentMenu; extern menu_t MainDef; diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 2b8633e5b..13e2423c4 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -110,7 +110,6 @@ static SDL_bool disable_fullscreen = SDL_FALSE; #define USE_FULLSCREEN (disable_fullscreen||!allow_fullscreen)?0:cv_fullscreen.value static SDL_bool disable_mouse = SDL_FALSE; #define USE_MOUSEINPUT (!disable_mouse && cv_usemouse.value && havefocus) -#define IGNORE_MOUSE (!cv_alwaysgrabmouse.value && (menuactive || paused || con_destlines || chat_on || gamestate != GS_LEVEL)) #define MOUSE_MENU false //(!disable_mouse && cv_usemouse.value && menuactive && !USE_FULLSCREEN) #define MOUSEBUTTONS_MAX MOUSEBUTTONS @@ -362,6 +361,17 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code) return 0; } +static boolean IgnoreMouse(void) +{ + if (cv_alwaysgrabmouse.value) + return false; + if (menuactive) + return !M_MouseNeeded(); + if (paused || con_destlines || chat_on || gamestate != GS_LEVEL) + return true; + return false; +} + static void SDLdoGrabMouse(void) { SDL_ShowCursor(SDL_DISABLE); @@ -388,7 +398,7 @@ void I_UpdateMouseGrab(void) { if (SDL_WasInit(SDL_INIT_VIDEO) == SDL_INIT_VIDEO && window != NULL && SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window - && USE_MOUSEINPUT && !IGNORE_MOUSE) + && USE_MOUSEINPUT && !IgnoreMouse()) SDLdoGrabMouse(); } @@ -596,7 +606,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) } //else firsttimeonmouse = SDL_FALSE; - if (USE_MOUSEINPUT && !IGNORE_MOUSE) + if (USE_MOUSEINPUT && !IgnoreMouse()) SDLdoGrabMouse(); } else if (!mousefocus && !kbfocus) @@ -647,7 +657,7 @@ static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt) if (USE_MOUSEINPUT) { - if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window) || (IGNORE_MOUSE && !firstmove)) + if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window) || (IgnoreMouse() && !firstmove)) { SDLdoUngrabMouse(); firstmove = false; @@ -700,7 +710,7 @@ static void Impl_HandleMouseButtonEvent(SDL_MouseButtonEvent evt, Uint32 type) // this apparently makes a mouse button down event but not a mouse button up event, // resulting in whatever key was pressed down getting "stuck" if we don't ignore it. // -- Monster Iestyn (28/05/18) - if (SDL_GetMouseFocus() != window || IGNORE_MOUSE) + if (SDL_GetMouseFocus() != window || IgnoreMouse()) return; /// \todo inputEvent.button.which @@ -1082,7 +1092,7 @@ void I_StartupMouse(void) } else firsttimeonmouse = SDL_FALSE; - if (cv_usemouse.value && !IGNORE_MOUSE) + if (cv_usemouse.value && !IgnoreMouse()) SDLdoGrabMouse(); else SDLdoUngrabMouse(); From 1317dba3e42a6f700e38f930d296f6f4128e97bf Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 18 Jan 2020 22:13:34 -0800 Subject: [PATCH 10/56] Refactor MUSICDEF parsing, actually count lines If you use strtok for (CR)LF, it'll skip the empty lines bruh. --- src/s_sound.c | 305 ++++++++++++++++++++++++-------------------------- 1 file changed, 147 insertions(+), 158 deletions(-) diff --git a/src/s_sound.c b/src/s_sound.c index c4c92ebf5..848fd671a 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1472,188 +1472,112 @@ static UINT16 W_CheckForMusicDefInPwad(UINT16 wadid) return INT16_MAX; // not found } -void S_LoadMusicDefs(UINT16 wadnum) +static boolean +ReadMusicDefFields (UINT16 wadnum, int line, char *stoken, musicdef_t **defp) { - UINT16 lumpnum; - char *lump, *buf; - char *musdeftext; - char *stoken; + musicdef_t *def; + char *value; char *textline; - size_t size; - INT32 i; - musicdef_t *def = NULL; - UINT16 line = 1; // for better error msgs + int i; - lumpnum = W_CheckForMusicDefInPwad(wadnum); - if (lumpnum == INT16_MAX) - return; - - lump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); - size = W_LumpLengthPwad(wadnum, lumpnum); - - // Null-terminated MUSICDEF lump. - musdeftext = malloc(size+1); - if (!musdeftext) - I_Error("S_LoadMusicDefs: No more free memory for the parser\n"); - M_Memcpy(musdeftext, lump, size); - musdeftext[size] = '\0'; - - // for strtok - buf = malloc(size+1); - if (!buf) - I_Error("S_LoadMusicDefs: No more free memory for the parser\n"); - M_Memcpy(buf, musdeftext, size+1); - - stoken = strtok(buf, "\r\n "); - // Find music def - while (stoken) + if (!stricmp(stoken, "lump")) { - /*if ((stoken[0] == '/' && stoken[1] == '/') - || (stoken[0] == '#')) // skip comments + value = strtok(NULL, " "); + if (!value) { - stoken = strtok(NULL, "\r\n"); // skip end of line - if (def) - stoken = strtok(NULL, "\r\n= "); - else - stoken = strtok(NULL, "\r\n "); - line++; - } - else*/ if (!stricmp(stoken, "lump")) - { - value = strtok(NULL, "\r\n "); - - if (!value) - { - CONS_Alert(CONS_WARNING, "MUSICDEF: Lump '%s' is missing name. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); - stoken = strtok(NULL, "\r\n"); // skip end of line - goto skip_lump; - } - - // No existing musicdefs - /*if (!musicdefstart) - { - musicdefstart = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL); - STRBUFCPY(musicdefstart->name, value); - strlwr(musicdefstart->name); - def = musicdefstart; - //CONS_Printf("S_LoadMusicDefs: Initialized musicdef w/ song '%s'\n", def->name); - } - else*/ - { - musicdef_t *prev = NULL; - def = musicdefstart; - - // Search if this is a replacement - //CONS_Printf("S_LoadMusicDefs: Searching for song replacement...\n"); - while (def) - { - if (!stricmp(def->name, value)) - { - //CONS_Printf("S_LoadMusicDefs: Found song replacement '%s'\n", def->name); - break; - } - - prev = def; - def = def->next; - } - - // Nothing found, add to the end. - if (!def) - { - def = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL); - STRBUFCPY(def->name, value); - strlwr(def->name); - def->bpm = TICRATE<<(FRACBITS-1); // FixedDiv((60*TICRATE)<next = def; - //CONS_Printf("S_LoadMusicDefs: Added song '%s'\n", def->name); - } - } - -skip_lump: - stoken = strtok(NULL, "\r\n "); - line++; + CONS_Alert(CONS_WARNING, + "MUSICDEF: Field '%s' is missing name. (file %s, line %d)\n", + stoken, wadfiles[wadnum]->filename, line); + return false; } else { - // If this is set true, the line was invalid. - boolean brokenline = false; + musicdef_t *prev = NULL; + def = musicdefstart; - // Delimit only by line break. - value = strtok(NULL, "\r\n"); + // Search if this is a replacement + //CONS_Printf("S_LoadMusicDefs: Searching for song replacement...\n"); + while (def) + { + if (!stricmp(def->name, value)) + { + //CONS_Printf("S_LoadMusicDefs: Found song replacement '%s'\n", def->name); + break; + } + prev = def; + def = def->next; + } + + // Nothing found, add to the end. + if (!def) + { + def = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL); + STRBUFCPY(def->name, value); + strlwr(def->name); + def->bpm = TICRATE<<(FRACBITS-1); // FixedDiv((60*TICRATE)<next = def; + //CONS_Printf("S_LoadMusicDefs: Added song '%s'\n", def->name); + } + + (*defp) = def; + } + } + else + { + value = strtok(NULL, ""); + + if (value) + { // Find the equals sign. value = strchr(value, '='); + } - // It's not there?! - if (!value) - brokenline = true; - else - { - // Skip the equals sign. - value++; - - // Now skip funny whitespace. - if (value[0] == '\0') // :NOTHING: - brokenline = true; - else - value += strspn(value, "\t "); - } - - // If the line is valid, copy the text line from the lump data. - if (!brokenline) - { - // strtok returns memory that already belongs to the input string. - value = musdeftext + (value - buf); - - // Find the length of the line. - size = strcspn(value, "\r\n"); - - // Copy the line. - textline = malloc(size+1); - if (!textline) - I_Error("S_LoadMusicDefs: No more free memory for text line\n"); - M_Memcpy(textline, value, size); - textline[size] = '\0'; - } - else - { - CONS_Alert(CONS_WARNING, "MUSICDEF: Field '%s' is missing value. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); - stoken = strtok(NULL, "\r\n"); // skip end of line - goto skip_field; - } + if (!value) + { + CONS_Alert(CONS_WARNING, + "MUSICDEF: Field '%s' is missing value. (file %s, line %d)\n", + stoken, wadfiles[wadnum]->filename, line); + return false; + } + else + { + def = (*defp); if (!def) { - CONS_Alert(CONS_ERROR, "MUSICDEF: No music definition before field '%s'. (file %s, line %d)\n", stoken, wadfiles[wadnum]->filename, line); - free(textline); - free(buf); - free(musdeftext); - return; + CONS_Alert(CONS_ERROR, + "MUSICDEF: No music definition before field '%s'. (file %s, line %d)\n", + stoken, wadfiles[wadnum]->filename, line); + return false; } - i = atoi(textline); + // Skip the equals sign. + value++; + // Now skip funny whitespace. + value += strspn(value, "\t "); + + textline = value; + i = atoi(value); + + /* based ignored lumps */ if (!stricmp(stoken, "usage")) { #if 0 // Ignore for now STRBUFCPY(def->usage, textline); - //CONS_Printf("S_LoadMusicDefs: Set usage to '%s'\n", def->usage); #endif } else if (!stricmp(stoken, "source")) { #if 0 // Ignore for now STRBUFCPY(def->source, textline); - //CONS_Printf("S_LoadMusicDefs: Set source to '%s'\n", def->usage); #endif } else if (!stricmp(stoken, "title")) { STRBUFCPY(def->title, textline); - //CONS_Printf("S_LoadMusicDefs: Set title to '%s'\n", def->source); } else if (!stricmp(stoken, "alttitle")) { STRBUFCPY(def->alttitle, textline); - //CONS_Printf("S_LoadMusicDefs: Set alttitle to '%s'\n", def->source); } else if (!stricmp(stoken, "authors")) { STRBUFCPY(def->authors, textline); - //CONS_Printf("S_LoadMusicDefs: Set authors to '%s'\n", def->source); } else if (!stricmp(stoken, "soundtestpage")) { def->soundtestpage = (UINT8)i; } else if (!stricmp(stoken, "soundtestcond")) { @@ -1670,21 +1594,86 @@ skip_lump: if (bpmf > 0) def->bpm = FixedDiv((60*TICRATE)<filename, line); + CONS_Alert(CONS_WARNING, + "MUSICDEF: Invalid field '%s'. (file %s, line %d)\n", + stoken, wadfiles[wadnum]->filename, line); } - - // Free the temporary text line from memory. - free(textline); - -skip_field: - stoken = strtok(NULL, "\r\n= "); - line++; } } - free(buf); + return true; +} + +void S_LoadMusicDefs(UINT16 wadnum) +{ + UINT16 lumpnum; + char *lump; + char *musdeftext; + size_t size; + + char *lf; + char *stoken; + + size_t nlf; + size_t ncr; + + musicdef_t *def = NULL; + int line = 1; // for better error msgs + + lumpnum = W_CheckForMusicDefInPwad(wadnum); + if (lumpnum == INT16_MAX) + return; + + lump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + size = W_LumpLengthPwad(wadnum, lumpnum); + + // Null-terminated MUSICDEF lump. + musdeftext = malloc(size+1); + if (!musdeftext) + I_Error("S_LoadMusicDefs: No more free memory for the parser\n"); + M_Memcpy(musdeftext, lump, size); + musdeftext[size] = '\0'; + + // Find music def + stoken = musdeftext; + for (;;) + { + lf = strpbrk(stoken, "\r\n"); + if (lf) + { + if (*lf == '\n') + nlf = 1; + else + nlf = 0; + *lf++ = '\0';/* now we can delimit to here */ + } + + stoken = strtok(stoken, " "); + if (stoken) + { + if (! ReadMusicDefFields(wadnum, line, stoken, &def)) + break; + } + + if (lf) + { + do + { + line += nlf; + ncr = strspn(lf, "\r");/* skip CR */ + lf += ncr; + nlf = strspn(lf, "\n"); + lf += nlf; + } + while (nlf || ncr) ; + + stoken = lf;/* now the next nonempty line */ + } + else + break;/* EOF */ + } + free(musdeftext); - return; } // From 9dbc54284ecdc46080f0e00a5f35040ba94922fc Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 18 Jan 2020 23:12:30 -0800 Subject: [PATCH 11/56] Opt into new MUSICDEF format (2.2.0 compatibility) The "VERSION" directive enables features available in a certain version of SRB2. It may be used as "VERSION 2.2.0". --- src/s_sound.c | 92 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 13 deletions(-) diff --git a/src/s_sound.c b/src/s_sound.c index 848fd671a..d11fc4321 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1441,6 +1441,12 @@ static tic_t pause_starttic; /// Music Definitions /// ------------------------ +enum +{ + MUSICDEF_220, + MUSICDEF_221, +}; + musicdef_t soundtestsfx = { "_STSFX", // prevents exactly one valid track name from being used on the sound test "Sound Effects", @@ -1472,10 +1478,27 @@ static UINT16 W_CheckForMusicDefInPwad(UINT16 wadid) return INT16_MAX; // not found } +static void +MusicDefStrcpy (char *p, const char *s, size_t n, int version) +{ + strlcpy(p, s, n); + if (version == MUSICDEF_220) + { + while (( p = strchr(p, '_') )) + { + n = strspn(p, "_"); + memset(p, ' ', n); // turn _ into spaces. + p += n; + } + } +} + static boolean -ReadMusicDefFields (UINT16 wadnum, int line, char *stoken, musicdef_t **defp) +ReadMusicDefFields (UINT16 wadnum, int line, boolean fields, char *stoken, + musicdef_t **defp, int *versionp) { musicdef_t *def; + int version; char *value; char *textline; @@ -1525,14 +1548,47 @@ ReadMusicDefFields (UINT16 wadnum, int line, char *stoken, musicdef_t **defp) (*defp) = def; } } + else if (!stricmp(stoken, "version")) + { + if (fields)/* is this not the first field? */ + { + CONS_Alert(CONS_WARNING, + "MUSICDEF: Field '%s' must come first. (file %s, line %d)\n", + stoken, wadfiles[wadnum]->filename, line); + return false; + } + else + { + value = strtok(NULL, " "); + if (!value) + { + CONS_Alert(CONS_WARNING, + "MUSICDEF: Field '%s' is missing version. (file %s, line %d)\n", + stoken, wadfiles[wadnum]->filename, line); + return false; + } + else + { + if (strcasecmp(value, "2.2.0")) + (*versionp) = MUSICDEF_221; + } + } + } else { - value = strtok(NULL, ""); + version = (*versionp); - if (value) + if (version == MUSICDEF_220) + value = strtok(NULL, " ="); + else { - // Find the equals sign. - value = strchr(value, '='); + value = strtok(NULL, ""); + + if (value) + { + // Find the equals sign. + value = strchr(value, '='); + } } if (!value) @@ -1554,11 +1610,14 @@ ReadMusicDefFields (UINT16 wadnum, int line, char *stoken, musicdef_t **defp) return false; } - // Skip the equals sign. - value++; + if (version != MUSICDEF_220) + { + // Skip the equals sign. + value++; - // Now skip funny whitespace. - value += strspn(value, "\t "); + // Now skip funny whitespace. + value += strspn(value, "\t "); + } textline = value; i = atoi(value); @@ -1573,11 +1632,14 @@ ReadMusicDefFields (UINT16 wadnum, int line, char *stoken, musicdef_t **defp) STRBUFCPY(def->source, textline); #endif } else if (!stricmp(stoken, "title")) { - STRBUFCPY(def->title, textline); + MusicDefStrcpy(def->title, textline, + sizeof def->title, version); } else if (!stricmp(stoken, "alttitle")) { - STRBUFCPY(def->alttitle, textline); + MusicDefStrcpy(def->alttitle, textline, + sizeof def->alttitle, version); } else if (!stricmp(stoken, "authors")) { - STRBUFCPY(def->authors, textline); + MusicDefStrcpy(def->authors, textline, + sizeof def->authors, version); } else if (!stricmp(stoken, "soundtestpage")) { def->soundtestpage = (UINT8)i; } else if (!stricmp(stoken, "soundtestcond")) { @@ -1618,7 +1680,9 @@ void S_LoadMusicDefs(UINT16 wadnum) size_t ncr; musicdef_t *def = NULL; + int version = MUSICDEF_220; int line = 1; // for better error msgs + boolean fields = false; lumpnum = W_CheckForMusicDefInPwad(wadnum); if (lumpnum == INT16_MAX) @@ -1651,8 +1715,10 @@ void S_LoadMusicDefs(UINT16 wadnum) stoken = strtok(stoken, " "); if (stoken) { - if (! ReadMusicDefFields(wadnum, line, stoken, &def)) + if (! ReadMusicDefFields(wadnum, line, fields, stoken, + &def, &version)) break; + fields = true; } if (lf) From ad505a6fe7cd3a0b91644e27f5f1c033644eaa35 Mon Sep 17 00:00:00 2001 From: Confusion Date: Sun, 19 Jan 2020 17:55:22 +0300 Subject: [PATCH 12/56] Fix title screen broken when leaving during resynch --- src/d_clisrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 5fa09e230..704fc0901 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2540,6 +2540,7 @@ void CL_Reset(void) multiplayer = false; servernode = 0; server = true; + resynch_local_inprogress = false; doomcom->numnodes = 1; doomcom->numslots = 1; SV_StopServer(); From c1097813f47f717a63b687a670f5e090308b6b52 Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Mon, 20 Jan 2020 16:14:20 +0100 Subject: [PATCH 13/56] Fix "cam2_turnmultiplier" In splitscreen stuff, player 2's "cam2_turnmultiplier" implementation was wrong compared to player 1's "cam_turnmultiplier" This commit makes player 2's multiplier work just like player 1's does --- src/g_game.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index a80d0f40a..0bec68d6e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1497,9 +1497,9 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) else { if (turnright) - cmd->angleturn = (INT16)(cmd->angleturn - (((angleturn[tspeed]<>FRACBITS)); + cmd->angleturn = (INT16)(cmd->angleturn - ((angleturn[tspeed] * cv_cam2_turnmultiplier.value)>>FRACBITS)); else if (turnleft) - cmd->angleturn = (INT16)(cmd->angleturn + (((angleturn[tspeed]<>FRACBITS)); + cmd->angleturn = (INT16)(cmd->angleturn + ((angleturn[tspeed] * cv_cam2_turnmultiplier.value)>>FRACBITS)); if (analogjoystickmove && lookjoystickvector.xaxis != 0) { From 2d8ea7125c24e1e3c6e8b56bdaabfeaa54354e25 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 20 Jan 2020 15:36:27 -0800 Subject: [PATCH 14/56] Remove unnecessary optimization --- src/s_sound.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/s_sound.c b/src/s_sound.c index d11fc4321..d84e20ab4 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1485,11 +1485,7 @@ MusicDefStrcpy (char *p, const char *s, size_t n, int version) if (version == MUSICDEF_220) { while (( p = strchr(p, '_') )) - { - n = strspn(p, "_"); - memset(p, ' ', n); // turn _ into spaces. - p += n; - } + *p++ = ' '; // turn _ into spaces. } } From 49a4c7d5f3db21808e1d4875b6f5d5b6989a5ac7 Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Tue, 21 Jan 2020 14:53:05 +0100 Subject: [PATCH 15/56] Separate "turnmultiplier"s for splitscreen players This fixes player 2 using player 1's "cam_turnmultiplier" instead of player 2's "cam2_turnmultiplier" --- src/g_game.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 646147e73..f1b9b0b5c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1140,7 +1140,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) INT32 *myaiming = (ssplayer == 1 ? &localaiming : &localaiming2); angle_t drawangleoffset = (player->powers[pw_carry] == CR_ROLLOUT) ? ANGLE_180 : 0; - INT32 chasecam, chasefreelook, alwaysfreelook, usejoystick, invertmouse, mousemove; + INT32 chasecam, chasefreelook, alwaysfreelook, usejoystick, invertmouse, turnmultiplier, mousemove; controlstyle_e controlstyle = G_ControlStyle(ssplayer); INT32 *mx; INT32 *my; INT32 *mly; @@ -1163,6 +1163,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) alwaysfreelook = cv_alwaysfreelook.value; usejoystick = cv_usejoystick.value; invertmouse = cv_invertmouse.value; + turnmultiplier = cv_cam_turnmultiplier.value; mousemove = cv_mousemove.value; mx = &mousex; my = &mousey; @@ -1176,6 +1177,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) alwaysfreelook = cv_alwaysfreelook2.value; usejoystick = cv_usejoystick2.value; invertmouse = cv_invertmouse2.value; + turnmultiplier = cv_cam2_turnmultiplier.value; mousemove = cv_mousemove2.value; mx = &mouse2x; my = &mouse2y; @@ -1293,14 +1295,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { if (turnright && turnleft); else if (turnright) - cmd->angleturn = (INT16)(cmd->angleturn - ((angleturn[tspeed] * cv_cam_turnmultiplier.value)>>FRACBITS)); + cmd->angleturn = (INT16)(cmd->angleturn - ((angleturn[tspeed] * turnmultiplier)>>FRACBITS)); else if (turnleft) - cmd->angleturn = (INT16)(cmd->angleturn + ((angleturn[tspeed] * cv_cam_turnmultiplier.value)>>FRACBITS)); + cmd->angleturn = (INT16)(cmd->angleturn + ((angleturn[tspeed] * turnmultiplier)>>FRACBITS)); if (analogjoystickmove && lookjoystickvector.xaxis != 0) { // JOYAXISRANGE should be 1023 (divide by 1024) - cmd->angleturn = (INT16)(cmd->angleturn - ((((lookjoystickvector.xaxis * angleturn[1]) >> 10) * cv_cam_turnmultiplier.value)>>FRACBITS)); // ANALOG! + cmd->angleturn = (INT16)(cmd->angleturn - ((((lookjoystickvector.xaxis * angleturn[1]) >> 10) * turnmultiplier)>>FRACBITS)); // ANALOG! } if (turnright || turnleft || abs(cmd->angleturn) > angleturn[2]) From dfcd058c80db463c4564e1bc7db746e25cc7819e Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 21 Jan 2020 02:29:29 -0800 Subject: [PATCH 16/56] (BRUH MOMENT) activettscale was -1, so do recache after it's set --- src/f_finale.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index bc904d8f2..e37eab764 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2693,8 +2693,18 @@ static void F_FigureActiveTtScale(void) SINT8 newttscale = max(1, min(6, vid.dupx)); SINT8 oldttscale = activettscale; - if (newttscale == testttscale) - return; + if (needpatchrecache) + ttloaded[0] = ttloaded[1] = ttloaded[2] = ttloaded[3] = ttloaded[4] = ttloaded[5] = 0; + else + { + if (newttscale == testttscale) + return; + + // We have a new ttscale, so load gfx + if(oldttscale > 0) + F_UnloadAlacroixGraphics(oldttscale); + } + testttscale = newttscale; // If ttscale is unavailable: look for lower scales, then higher scales. @@ -2712,10 +2722,6 @@ static void F_FigureActiveTtScale(void) activettscale = (newttscale >= 1 && newttscale <= 6) ? newttscale : 0; - // We have a new ttscale, so load gfx - if(oldttscale > 0) - F_UnloadAlacroixGraphics(oldttscale); - if(activettscale > 0) F_LoadAlacroixGraphics(activettscale); } @@ -2757,12 +2763,6 @@ void F_TitleScreenDrawer(void) return; #endif - if (needpatchrecache && (curttmode == TTMODE_ALACROIX)) - { - ttloaded[0] = ttloaded[1] = ttloaded[2] = ttloaded[3] = ttloaded[4] = ttloaded[5] = 0; - F_LoadAlacroixGraphics(activettscale); - } - switch(curttmode) { case TTMODE_OLD: From c347254e8005b7d9aba5bea4290dded68b5a8a93 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 21 Jan 2020 03:20:50 -0800 Subject: [PATCH 17/56] Reorder Sonic's ass so the OpenGL wipe doesn't see garbage --- src/d_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index 2432c5e9e..74547f9f7 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -651,8 +651,12 @@ void D_SRB2Loop(void) // hack to start on a nice clear console screen. COM_ImmedExecute("cls;version"); - V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE)); I_FinishUpdate(); // page flip or blit buffer + /* + LMFAO this was showing garbage under OpenGL + because I_FinishUpdate was called afterward + */ + V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE)); for (;;) { From f297f4ff5636cbf081b7991875b563dc06eef3d1 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 21 Jan 2020 03:28:33 -0800 Subject: [PATCH 18/56] Sonic is dead again --- src/d_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index 74547f9f7..32972c151 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -656,7 +656,9 @@ void D_SRB2Loop(void) LMFAO this was showing garbage under OpenGL because I_FinishUpdate was called afterward */ - V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE)); + /* Smells like a hack... Don't fade Sonic's ass into the title screen. */ + if (gamestate != GS_TITLESCREEN) + V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(W_GetNumForName("CONSBACK"), PU_CACHE)); for (;;) { From 9cd101c68ddb9618e215e2f4c6dff90c7d1b6a9d Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 21 Jan 2020 14:55:50 -0800 Subject: [PATCH 19/56] Revert "Fix Ploadflat closing the game with "Too many flats in level" error message" This reverts commit ea129f701c86f87daa7355e6f031d0633951cdfa. --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 42a6438a0..9a270d2f3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -672,7 +672,7 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat) // INT32 P_AddLevelFlatRuntime(const char *flatname) { - return Ploadflat(levelflats, flatname); + return Ploadflat(0, flatname); } // help function for $$$.sav checking From d90c0b8fbd0e122073b5a8adba09db832a39daf7 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 21 Jan 2020 15:11:16 -0800 Subject: [PATCH 20/56] Don't check "Too many flats in level" with P_AddLevelFlatRuntime Also moved the debug down in case anyone uses that. --- src/p_setup.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 9a270d2f3..9b5b7e5c2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -585,15 +585,11 @@ Ploadflat (levelflat_t *levelflat, const char *flatname) if (strnicmp(levelflat[i].name, flatname, 8) == 0) return i; } + + if (numlevelflats >= MAXLEVELFLATS) + I_Error("Too many flats in level\n"); } -#ifndef ZDEBUG - CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); -#endif - - if (numlevelflats >= MAXLEVELFLATS) - I_Error("Too many flats in level\n"); - if (levelflat) levelflat += numlevelflats; else @@ -656,6 +652,10 @@ flatfound: levelflat->u.flat.baselumpnum = LUMPERROR; } +#ifndef ZDEBUG + CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); +#endif + return ( numlevelflats++ ); } From 2373a0aa8308816e2e6037fea736bf58a116b4dc Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 21 Jan 2020 16:47:47 -0800 Subject: [PATCH 21/56] Actually actually match the old behavior and check existing levelflats in P_AddLevelFlatRuntime BRUH --- src/p_setup.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 9b5b7e5c2..132684163 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -566,7 +566,7 @@ levelflat refers to an array of level flats, or NULL if we want to allocate it now. */ static INT32 -Ploadflat (levelflat_t *levelflat, const char *flatname) +Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize) { #ifndef NO_PNG_LUMPS UINT8 buffer[8]; @@ -577,27 +577,26 @@ Ploadflat (levelflat_t *levelflat, const char *flatname) size_t i; - if (levelflat) + // Scan through the already found flats, return if it matches. + for (i = 0; i < numlevelflats; i++) { - // Scan through the already found flats, return if it matches. - for (i = 0; i < numlevelflats; i++) - { - if (strnicmp(levelflat[i].name, flatname, 8) == 0) - return i; - } - - if (numlevelflats >= MAXLEVELFLATS) - I_Error("Too many flats in level\n"); + if (strnicmp(levelflat[i].name, flatname, 8) == 0) + return i; } - if (levelflat) - levelflat += numlevelflats; - else + if (resize) { // allocate new flat memory levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL); levelflat = levelflats + numlevelflats; } + else + { + if (numlevelflats >= MAXLEVELFLATS) + I_Error("Too many flats in level\n"); + + levelflat += numlevelflats; + } // Store the name. strlcpy(levelflat->name, flatname, sizeof (levelflat->name)); @@ -663,7 +662,7 @@ flatfound: // allocate an id for it, and set the levelflat (to speedup search) INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat) { - return Ploadflat(levelflat, flatname); + return Ploadflat(levelflat, flatname, false); } // help function for Lua and $$$.sav reading @@ -672,7 +671,7 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat) // INT32 P_AddLevelFlatRuntime(const char *flatname) { - return Ploadflat(0, flatname); + return Ploadflat(levelflats, flatname, true); } // help function for $$$.sav checking From d374bf4f9ba239d86b04f93878a496c21280eaf0 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 22 Jan 2020 03:05:08 +0100 Subject: [PATCH 22/56] Let clients rejoin the server without losing their status This is accomplished by simply preserving the player's body after disconnecting. Bodies will despawn after the number of minutes specified by the "rejointimeout" console variable (float). A value of 0 disables the feature completely. Clients rejoining are identified by their IP address, and may rejoin even if the server is full or joins are disabled, for as long as their body remains. From a technical standpoint, when the user disconnects, the player they were controlling does not leave, the underlying player_t just keeps working normally, except it does not receive any input anymore. When the user reconnects, they are simply "relinked" to their player_t. Those "soulless" players can be identified through their "quittime" field, which is the number of tics elapsed since the user disconnected, or zero if still connected. "quittime" is exposed to Lua. --- src/command.c | 2 +- src/d_clisrv.c | 316 +++++++++++++++++++++++++++---------------- src/d_clisrv.h | 5 +- src/d_netcmd.c | 35 ++--- src/d_player.h | 1 + src/g_game.c | 4 +- src/hu_stuff.c | 14 +- src/lua_consolelib.c | 2 +- src/lua_hook.h | 2 +- src/lua_hooklib.c | 2 +- src/lua_playerlib.c | 4 + src/p_saveg.c | 2 + src/p_tick.c | 13 +- 13 files changed, 252 insertions(+), 150 deletions(-) diff --git a/src/command.c b/src/command.c index 31c9b50ad..8a0fc3f4e 100644 --- a/src/command.c +++ b/src/command.c @@ -1407,7 +1407,7 @@ static void Got_NetVar(UINT8 **p, INT32 playernum) // not from server or remote admin, must be hacked/buggy client CONS_Alert(CONS_WARNING, M_GetText("Illegal netvar command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } netid = READUINT16(*p); diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e85664d38..d40027a3d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -21,6 +21,7 @@ #include "d_net.h" #include "d_main.h" #include "g_game.h" +#include "st_stuff.h" #include "hu_stuff.h" #include "keys.h" #include "g_input.h" // JOY1 @@ -391,7 +392,7 @@ static void ExtraDataTicker(void) { if (server) { - SendKick(i, KICK_MSG_CON_FAIL); + SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic)); } CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]); @@ -437,6 +438,9 @@ void SendKick(UINT8 playernum, UINT8 msg) { UINT8 buf[2]; + if (!(server && cv_rejointimeout.value)) + msg &= ~KICK_MSG_KEEP_BODY; + buf[0] = playernum; buf[1] = msg; SendNetXCmd(XD_KICK, &buf, 2); @@ -1064,7 +1068,7 @@ static void SV_SendResynch(INT32 node) if (resynch_score[node] > (unsigned)cv_resynchattempts.value*250) { - SendKick(nodetoplayer[node], KICK_MSG_CON_FAIL); + SendKick(nodetoplayer[node], KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); resynch_score[node] = 0; } } @@ -2403,6 +2407,7 @@ void CL_ClearPlayer(INT32 playernum) if (players[playernum].mo) P_RemoveMobj(players[playernum].mo); memset(&players[playernum], 0, sizeof (player_t)); + memset(playeraddress[playernum], 0, sizeof(*playeraddress)); } // @@ -2410,7 +2415,7 @@ void CL_ClearPlayer(INT32 playernum) // // Removes a player from the current game // -static void CL_RemovePlayer(INT32 playernum, INT32 reason) +static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) { // Sanity check: exceptional cases (i.e. c-fails) can cause multiple // kick commands to be issued for the same player. @@ -2423,9 +2428,6 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason) playerpernode[node]--; if (playerpernode[node] <= 0) { - // If a resynch was in progress, well, it no longer needs to be. - SV_InitResynchVars(playernode[playernum]); - nodeingame[playernode[playernum]] = false; Net_CloseConnection(playernode[playernum]); ResetNode(node); @@ -2812,9 +2814,12 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) char buf[3 + MAX_REASONLENGTH]; char *reason = buf; kickreason_t kickreason = KR_KICK; + boolean keepbody; pnum = READUINT8(*p); msg = READUINT8(*p); + keepbody = (msg & KICK_MSG_KEEP_BODY) != 0; + msg &= ~KICK_MSG_KEEP_BODY; if (pnum == serverplayer && IsPlayerAdmin(playernum)) { @@ -2874,6 +2879,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) */ pnum = playernum; msg = KICK_MSG_CON_FAIL; + keepbody = true; } //CONS_Printf("\x82%s ", player_names[pnum]); @@ -2942,7 +2948,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) kickreason = KR_TIMEOUT; break; case KICK_MSG_PLAYER_QUIT: - if (netgame) // not splitscreen/bots + if (netgame && !players[pnum].quittime) // not splitscreen/bots or soulless body HU_AddChatText(va("\x82*%s left the game", player_names[pnum]), false); kickreason = KR_LEAVE; break; @@ -2983,6 +2989,24 @@ 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 if (keepbody) + { + if (server && !demoplayback) + { + INT32 node = playernode[pnum]; + playerpernode[node]--; + if (playerpernode[node] <= 0) + { + nodeingame[node] = false; + Net_CloseConnection(node); + ResetNode(node); + } + } + + playernode[pnum] = UINT8_MAX; + + players[pnum].quittime = 1; + } else CL_RemovePlayer(pnum, kickreason); } @@ -2991,6 +3015,9 @@ consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, N consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}}; consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; +consvar_t cv_rejointimeout = {"rejointimeout", "Off", CV_SAVE|CV_FLOAT, rejointimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; + static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; consvar_t cv_resynchattempts = {"resynchattempts", "10", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL }; consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL }; @@ -3060,6 +3087,7 @@ static void ResetNode(INT32 node) nodewaiting[node] = 0; playerpernode[node] = 0; sendingsavegame[node] = false; + SV_InitResynchVars(node); } void SV_ResetServer(void) @@ -3075,13 +3103,8 @@ void SV_ResetServer(void) tictoclear = maketic; for (i = 0; i < MAXNETNODES; i++) - { ResetNode(i); - // Make sure resynch status doesn't get carried over! - SV_InitResynchVars(i); - } - for (i = 0; i < MAXPLAYERS; i++) { #ifdef HAVE_BLUA @@ -3089,6 +3112,7 @@ void SV_ResetServer(void) #endif playeringame[i] = false; playernode[i] = UINT8_MAX; + memset(playeraddress[i], 0, sizeof(*playeraddress)); sprintf(player_names[i], "Player %d", i + 1); adminplayers[i] = -1; // Populate the entire adminplayers array with -1. } @@ -3179,6 +3203,37 @@ void D_QuitNetGame(void) #endif } +static INT32 FindRejoinerNum(SINT8 node) +{ + char strippednodeaddress[64]; + const char *nodeaddress; + char *port; + INT32 i; + + // Make sure there is no dead dress before proceeding to the stripping + if (!I_GetNodeAddress) + return -1; + nodeaddress = I_GetNodeAddress(node); + if (!nodeaddress) + return -1; + + // Strip the address of its port + strcpy(strippednodeaddress, nodeaddress); + port = strchr(strippednodeaddress, ':'); + if (port) + *port = '\0'; + + // Check if any player matches the stripped address + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX + && !strcmp(playeraddress[i], strippednodeaddress)) + return i; + } + + return -1; +} + // Adds a node to the game (player will follow at map change or at savegame....) static inline void SV_AddNode(INT32 node) { @@ -3195,13 +3250,16 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) { INT16 node, newplayernum; boolean splitscreenplayer; + boolean rejoined; + player_t *newplayer; + char *port; if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { // protect against hacked/buggy client CONS_Alert(CONS_WARNING, M_GetText("Illegal add player command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -3210,15 +3268,34 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) splitscreenplayer = newplayernum & 0x80; newplayernum &= ~0x80; - // 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); - playeringame[newplayernum] = true; + rejoined = playeringame[newplayernum]; + + if (!rejoined) + { + // 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); + playeringame[newplayernum] = true; + G_AddPlayer(newplayernum); + if (newplayernum+1 > doomcom->numslots) + doomcom->numslots = (INT16)(newplayernum+1); + + if (server && I_GetNodeAddress) + { + strcpy(playeraddress[newplayernum], I_GetNodeAddress(node)); + port = strchr(playeraddress[newplayernum], ':'); + if (port) + *port = '\0'; + } + } + + newplayer = &players[newplayernum]; + + newplayer->jointime = 0; + newplayer->quittime = 0; + READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME); - G_AddPlayer(newplayernum); - if (newplayernum+1 > doomcom->numslots) - doomcom->numslots = (INT16)(newplayernum+1); // the server is creating my player if (node == mynode) @@ -3236,29 +3313,67 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) secondarydisplayplayer = newplayernum; DEBFILE("spawning my brother\n"); if (botingame) - players[newplayernum].bot = 1; + newplayer->bot = 1; } D_SendPlayerConfig(); addedtogame = true; + + if (rejoined) + { + if (newplayer->mo) + { + if (!splitscreenplayer) + localangle = newplayer->mo->angle; + else + localangle2 = newplayer->mo->angle; + + newplayer->viewheight = 41*newplayer->height/48; + + if (newplayer->mo->eflags & MFE_VERTICALFLIP) + newplayer->viewz = newplayer->mo->z + newplayer->mo->height - newplayer->viewheight; + else + newplayer->viewz = newplayer->mo->z + newplayer->viewheight; + } + + // wake up the status bar + ST_Start(); + // wake up the heads up text + HU_Start(); + + if (camera.chase && !splitscreenplayer) + P_ResetCamera(newplayer, &camera); + if (camera2.chase && splitscreenplayer) + P_ResetCamera(newplayer, &camera2); + } } if (netgame) { - if (server && cv_showjoinaddress.value) - { - const char *address; - if (I_GetNodeAddress && (address = I_GetNodeAddress(node)) != NULL) - HU_AddChatText(va("\x82*%s has joined the game (player %d) (%s)", player_names[newplayernum], newplayernum, address), false); // merge join notification + IP to avoid clogging console/chat. - } + char joinmsg[256]; + + if (rejoined) + strcpy(joinmsg, M_GetText("\x82*%s has rejoined the game (player %d)")); else - HU_AddChatText(va("\x82*%s has joined the game (player %d)", player_names[newplayernum], newplayernum), false); // if you don't wanna see the join address. + strcpy(joinmsg, M_GetText("\x82*%s has joined the game (player %d)")); + strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum)); + + // Merge join notification + IP to avoid clogging console/chat + if (server && cv_showjoinaddress.value && I_GetNodeAddress) + { + const char *address = I_GetNodeAddress(node); + if (address) + strcat(joinmsg, va(" (%s)", address)); + } + + HU_AddChatText(joinmsg, false); } if (server && multiplayer && motd[0] != '\0') COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); #ifdef HAVE_BLUA - LUAh_PlayerJoin(newplayernum); + if (!rejoined) + LUAh_PlayerJoin(newplayernum); #endif } @@ -3267,11 +3382,7 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) INT32 node, n, newplayer = false; UINT8 buf[2 + MAXPLAYERNAME]; UINT8 *p; - UINT8 newplayernum = 0; - - // What is the reason for this? Why can't newplayernum always be 0? - if (dedicated) - newplayernum = 1; + INT32 newplayernum; for (node = 0; node < MAXNETNODES; node++) { @@ -3280,68 +3391,22 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) { 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 + newplayernum = FindRejoinerNum(node); + if (newplayernum == -1) + { // search for a free playernum // we can't use playeringame since it is not updated here - for (; newplayernum < MAXPLAYERS; newplayernum++) + for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++) { + if (playeringame[newplayernum]) + continue; for (n = 0; n < MAXNETNODES; n++) if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum) break; if (n == MAXNETNODES) break; } + } // should never happen since we check the playernum // before accepting the join @@ -3368,8 +3433,6 @@ static boolean SV_AddWaitingPlayers(const char *name, const char *name2) SendNetXCmd(XD_ADDPLAYER, &buf, p - buf); DEBFILE(va("Server added player %d node %d\n", newplayernum, node)); - // use the next free slot (we can't put playeringame[newplayernum] = true here) - newplayernum++; } } @@ -3495,16 +3558,19 @@ static size_t TotalTextCmdPerTic(tic_t tic) static void HandleConnect(SINT8 node) { char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; + INT32 rejoinernum; INT32 i; + rejoinernum = FindRejoinerNum(node); + if (bannednode && bannednode[node]) SV_SendRefuse(node, M_GetText("You have been banned\nfrom the server")); else if (netbuffer->u.clientcfg.version != VERSION || netbuffer->u.clientcfg.subversion != SUBVERSION) SV_SendRefuse(node, va(M_GetText("Different SRB2 versions cannot\nplay a netgame!\n(server version %d.%d.%d)"), VERSION/100, VERSION%100, SUBVERSION)); - else if (!cv_allownewplayer.value && node) + else if (!cv_allownewplayer.value && node && rejoinernum == -1) SV_SendRefuse(node, M_GetText("The server is not accepting\njoins for the moment")); - else if (D_NumPlayers() >= cv_maxplayers.value) + else if (D_NumPlayers() >= cv_maxplayers.value && rejoinernum == -1) SV_SendRefuse(node, va(M_GetText("Maximum players reached: %d"), cv_maxplayers.value)); else if (netgame && netbuffer->u.clientcfg.localplayers > 1) // Hacked client? SV_SendRefuse(node, M_GetText("Too many players from\nthis node.")); @@ -3519,7 +3585,7 @@ static void HandleConnect(SINT8 node) for (i = 0; i < netbuffer->u.clientcfg.localplayers - playerpernode[node]; i++) { strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1); - if (!EnsurePlayerNameIsGood(names[i], -1)) + if (!EnsurePlayerNameIsGood(names[i], rejoinernum)) { SV_SendRefuse(node, "Bad player name"); return; @@ -3956,7 +4022,7 @@ static void HandlePacketFromPlayer(SINT8 node) } else { - SendKick(netconsole, KICK_MSG_CON_FAIL); + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n", netconsole, realstart, consistancy[realstart%BACKUPTICS], SHORT(netbuffer->u.clientpak.consistancy))); @@ -4075,6 +4141,7 @@ static void HandlePacketFromPlayer(SINT8 node) kickmsg = KICK_MSG_TIMEOUT; else kickmsg = KICK_MSG_PLAYER_QUIT; + kickmsg |= KICK_MSG_KEEP_BODY; SendKick(netconsole, kickmsg); nodetoplayer[node] = -1; @@ -4096,7 +4163,7 @@ static void HandlePacketFromPlayer(SINT8 node) { CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node); if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL); + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); break; } resynch_local_inprogress = false; @@ -4114,7 +4181,7 @@ static void HandlePacketFromPlayer(SINT8 node) { CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node); if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL); + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); break; } @@ -4174,7 +4241,7 @@ static void HandlePacketFromPlayer(SINT8 node) { CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node); if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL); + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); break; } resynch_local_inprogress = true; @@ -4186,7 +4253,7 @@ static void HandlePacketFromPlayer(SINT8 node) { CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node); if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL); + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); break; } @@ -4210,7 +4277,7 @@ static void HandlePacketFromPlayer(SINT8 node) { CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node); if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL); + SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); break; } if (client) @@ -4406,7 +4473,7 @@ static void CL_SendClientCmd(void) packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16); HSendPacket(servernode, false, 0, packetsize); } - else if (gamestate != GS_NULL) + else if (gamestate != GS_NULL && addedtogame) { G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1); netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]); @@ -4582,6 +4649,11 @@ static void Local_Maketic(INT32 realtics) localcmds.angleturn |= TICCMD_RECEIVED; } +// This function is utter bullshit and is responsible for +// the random desynch that happens when a player spawns. +// This is because ticcmds are resent to clients if a packet +// was dropped, and thus modifying them can lead to several +// clients having their ticcmds set to different values. void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle) { tic_t tic; @@ -4615,28 +4687,36 @@ void SV_SpawnPlayer(INT32 playernum, INT32 x, INT32 y, angle_t angle) // create missed tic static void SV_Maketic(void) { - INT32 j; + INT32 i; - for (j = 0; j < MAXNETNODES; j++) - if (playerpernode[j]) + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + // We didn't receive this tic + if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0) { - INT32 player = nodetoplayer[j]; - if ((netcmds[maketic%BACKUPTICS][player].angleturn & TICCMD_RECEIVED) == 0) - { // we didn't receive this tic - INT32 i; + ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i]; + ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i]; - DEBFILE(va("MISS tic%4d for node %d\n", maketic, j)); -#if defined(PARANOIA) && 0 - CONS_Debug(DBG_NETPLAY, "Client Misstic %d\n", maketic); -#endif - // copy the old tic - for (i = 0; i < playerpernode[j]; i++, player = nodetoplayer2[j]) - { - netcmds[maketic%BACKUPTICS][player] = netcmds[(maketic-1)%BACKUPTICS][player]; - netcmds[maketic%BACKUPTICS][player].angleturn &= ~TICCMD_RECEIVED; - } + if (players[i].quittime) + { + // Copy the angle/aiming from the previous tic + // and empty the other inputs + memset(ticcmd, 0, sizeof(netcmds[0][0])); + ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED; + ticcmd->aiming = prevticcmd->aiming; + } + else + { + DEBFILE(va("MISS tic%4d for player %d\n", maketic, i)); + // Copy the input from the previous tic + *ticcmd = *prevticcmd; + ticcmd->angleturn &= ~TICCMD_RECEIVED; } } + } // all tic are now proceed make the next maketic++; @@ -4758,7 +4838,7 @@ static inline void PingUpdate(void) // ok your net has been bad for too long, you deserve to die. { pingtimeout[i] = 0; - SendKick(i, KICK_MSG_PING_HIGH); + SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY); } } /* diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 99fae32fb..5ee11056a 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -463,6 +463,7 @@ extern consvar_t cv_playbackspeed; #define KICK_MSG_PING_HIGH 6 #define KICK_MSG_CUSTOM_KICK 7 #define KICK_MSG_CUSTOM_BAN 8 +#define KICK_MSG_KEEP_BODY 0x80 typedef enum { @@ -490,7 +491,9 @@ extern UINT32 realpingtable[MAXPLAYERS]; extern UINT32 playerpingtable[MAXPLAYERS]; extern tic_t servermaxping; -extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed; +extern consvar_t cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_rejointimeout; +extern consvar_t cv_resynchattempts, cv_blamecfail; +extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed; // Used in d_net, the only dependence tic_t ExpandTics(INT32 low); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index cfcc1b2c5..af1bb8948 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -572,6 +572,7 @@ void D_RegisterServerCommands(void) // d_clisrv CV_RegisterVar(&cv_maxplayers); + CV_RegisterVar(&cv_rejointimeout); CV_RegisterVar(&cv_resynchattempts); CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_noticedownload); @@ -1091,7 +1092,7 @@ static void SetPlayerName(INT32 playernum, char *newname) { CONS_Printf(M_GetText("Player %d sent a bad name change\n"), playernum+1); if (server && netgame) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); } } @@ -1449,7 +1450,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) if (kick) { CONS_Alert(CONS_WARNING, M_GetText("Illegal color change received from %s (team: %d), color: %d)\n"), player_names[playernum], p->ctfteam, p->skincolor); - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } } @@ -2032,7 +2033,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal map change received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -2142,7 +2143,7 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal pause command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -2215,7 +2216,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -2278,7 +2279,7 @@ static void Got_Clearscores(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal clear scores command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -2625,7 +2626,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) // this should never happen unless the client is hacked/buggy CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); } if (NetPacket.packet.verification) // Special marker that the server sent the request @@ -2634,7 +2635,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } playernum = NetPacket.packet.playernum; @@ -2667,7 +2668,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); } return; } @@ -2716,7 +2717,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) if (server && ((NetPacket.packet.newteam < 0 || NetPacket.packet.newteam > 3) || error)) { CONS_Alert(CONS_WARNING, M_GetText("Illegal team change received from player %s\n"), player_names[playernum]); - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); } //Safety first! @@ -3000,7 +3001,7 @@ static void Got_Verification(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal verification received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -3050,7 +3051,7 @@ static void Got_Removal(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal demotion received from %s (serverplayer is %s)\n"), player_names[playernum], player_names[serverplayer]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -3124,7 +3125,7 @@ static void Got_MotD_f(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal motd change received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); Z_Free(mymotd); return; } @@ -3180,7 +3181,7 @@ static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal runsoc command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -3338,7 +3339,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick) { CONS_Alert(CONS_WARNING, M_GetText("Illegal addfile command received from %s\n"), player_names[playernum]); - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -3387,7 +3388,7 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal addfile command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -4170,7 +4171,7 @@ static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal exitlevel command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } diff --git a/src/d_player.h b/src/d_player.h index 62f38193f..db55a9913 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -510,6 +510,7 @@ typedef struct player_s UINT8 bot; tic_t jointime; // Timer when player joins game to change skin/color + tic_t quittime; // Time elapsed since user disconnected, zero if connected #ifdef HWRENDER fixed_t fovadd; // adjust FOV for hw rendering #endif diff --git a/src/g_game.c b/src/g_game.c index 2a12dd298..956751bb9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2307,6 +2307,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) INT32 skin; UINT32 availabilities; tic_t jointime; + tic_t quittime; boolean spectator; boolean outofcoop; INT16 bot; @@ -2320,6 +2321,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) ctfteam = players[player].ctfteam; exiting = players[player].exiting; jointime = players[player].jointime; + quittime = players[player].quittime; spectator = players[player].spectator; outofcoop = players[player].outofcoop; pflags = (players[player].pflags & (PF_FLIPCAM|PF_ANALOGMODE|PF_DIRECTIONCHAR|PF_AUTOBRAKE|PF_TAGIT|PF_GAMETYPEOVER)); @@ -2391,6 +2393,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) p->pflags = pflags; p->ctfteam = ctfteam; p->jointime = jointime; + p->quittime = quittime; p->spectator = spectator; p->outofcoop = outofcoop; @@ -2974,7 +2977,6 @@ void G_AddPlayer(INT32 playernum) } } - p->jointime = 0; p->playerstate = PST_REBORN; p->height = mobjinfo[MT_PLAYER].height; diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 1ad04f6ff..66ed8b11a 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -659,7 +659,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) M_GetText("Illegal say command received from %s while muted\n") : M_GetText("Illegal csay command received from non-admin %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } @@ -673,7 +673,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) { CONS_Alert(CONS_WARNING, M_GetText("Illegal say command received from %s containing invalid characters\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); return; } } @@ -2367,7 +2367,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (!splitscreen) // don't draw it on splitscreen, { - if (!(tab[i].num == serverplayer)) + if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) HU_drawPing(x+ 253, y, playerpingtable[tab[i].num], false, 0); //else // V_DrawSmallString(x+ 246, y+4, V_YELLOWMAP, "SERVER"); @@ -2566,7 +2566,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) V_DrawRightAlignedThinString(x+128, y, ((players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); if (!splitscreen) { - if (!(tab[i].num == serverplayer)) + if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0); //else //V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); @@ -2690,7 +2690,7 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer) V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count)); if (!splitscreen) { - if (!(tab[i].num == serverplayer)) + if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0); //else // V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER"); @@ -2721,7 +2721,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline supercheck = supercheckdef; strlcpy(name, tab[i].name, 7); - if (!(tab[i].num == serverplayer)) + if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0); //else // V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER"); @@ -2829,7 +2829,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor strlcpy(name, tab[i].name, 7); if (!splitscreen) // don't draw it on splitscreen, { - if (!(tab[i].num == serverplayer)) + if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0); //else // V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 4d23f73b2..90ea85382 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -87,7 +87,7 @@ deny: CONS_Alert(CONS_WARNING, M_GetText("Illegal lua command received from %s\n"), player_names[playernum]); if (server) - SendKick(playernum, KICK_MSG_CON_FAIL); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); } // Wrapper for COM_AddCommand commands diff --git a/src/lua_hook.h b/src/lua_hook.h index 6617bca93..c092c0a94 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -91,7 +91,7 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage -void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting +void LUAh_PlayerQuit(player_t *plr, kickreason_t reason); // Hook for player quitting void LUAh_IntermissionThinker(void); // Hook for Y_Ticker #endif diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index ef87d0b6f..acc82a66a 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1295,7 +1295,7 @@ UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj) return shouldCollide; } -void LUAh_PlayerQuit(player_t *plr, int reason) +void LUAh_PlayerQuit(player_t *plr, kickreason_t reason) { hook_p hookp; if (!gL || !(hooksAvailable[hook_PlayerQuit/8] & (1<<(hook_PlayerQuit%8)))) diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index c501fbbb2..1dd4c45b5 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -362,6 +362,8 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->bot); else if (fastcmp(field,"jointime")) lua_pushinteger(L, plr->jointime); + else if (fastcmp(field,"quittime")) + lua_pushinteger(L, plr->quittime); #ifdef HWRENDER else if (fastcmp(field,"fovadd")) lua_pushfixed(L, plr->fovadd); @@ -701,6 +703,8 @@ static int player_set(lua_State *L) return NOSET; else if (fastcmp(field,"jointime")) plr->jointime = (tic_t)luaL_checkinteger(L, 3); + else if (fastcmp(field,"quittime")) + plr->quittime = (tic_t)luaL_checkinteger(L, 3); #ifdef HWRENDER else if (fastcmp(field,"fovadd")) plr->fovadd = luaL_checkfixed(L, 3); diff --git a/src/p_saveg.c b/src/p_saveg.c index 89447db80..1db1e893e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -255,6 +255,7 @@ static void P_NetArchivePlayers(void) WRITEINT32(save_p, players[i].onconveyor); WRITEUINT32(save_p, players[i].jointime); + WRITEUINT32(save_p, players[i].quittime); WRITEUINT16(save_p, flags); @@ -446,6 +447,7 @@ static void P_NetUnArchivePlayers(void) players[i].onconveyor = READINT32(save_p); players[i].jointime = READUINT32(save_p); + players[i].quittime = READUINT32(save_p); flags = READUINT16(save_p); diff --git a/src/p_tick.c b/src/p_tick.c index e0f60bd22..6f28d0de0 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -590,10 +590,19 @@ void P_Ticker(boolean run) { INT32 i; - //Increment jointime even if paused. + // Increment jointime and quittime even if paused for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) - ++players[i].jointime; + { + players[i].jointime++; + + if (players[i].quittime) + { + players[i].quittime++; + if (server && players[i].quittime >= FixedMul(cv_rejointimeout.value, 60 * TICRATE)) + SendKick(i, KICK_MSG_PLAYER_QUIT); + } + } if (objectplacing) { From 73d0549fa43da04aa8954c53766aa727b2c71204 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 22 Jan 2020 03:11:05 +0100 Subject: [PATCH 23/56] Ignore players towards exit count 30 seconds after their disconnection --- src/g_game.c | 2 ++ src/p_user.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index 956751bb9..30519b379 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2999,6 +2999,8 @@ boolean G_EnoughPlayersFinished(void) { if (!playeringame[i] || players[i].spectator || players[i].bot) continue; + if (players[i].quittime > 30 * TICRATE) + continue; if (players[i].lives <= 0) continue; diff --git a/src/p_user.c b/src/p_user.c index ea42a2c36..4044428b8 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11479,6 +11479,8 @@ void P_PlayerThink(player_t *player) { if (!playeringame[i] || players[i].spectator || players[i].bot) continue; + if (players[i].quittime > 30 * TICRATE) + continue; if (players[i].lives <= 0) continue; From d03c928baa35e133683df7395bbb775aa29cd5a7 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 22 Jan 2020 03:14:44 +0100 Subject: [PATCH 24/56] Give flashing tics to disconnected players and prevent drowning --- src/p_enemy.c | 3 +++ src/p_user.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 74a11fe67..186b0854d 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -748,6 +748,9 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed if (player->bot) continue; // ignore bots + if (player->quittime) + continue; // Ignore uncontrolled bodies + if (dist > 0 && P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist) continue; // Too far away diff --git a/src/p_user.c b/src/p_user.c index 4044428b8..2d87c910b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -11921,6 +11921,10 @@ void P_PlayerThink(player_t *player) player->pflags &= ~PF_USEDOWN; } + // IF PLAYER NOT HERE THEN FLASH END IF + if (player->quittime && player->powers[pw_flashing] < flashingtics - 1) + player->powers[pw_flashing] = flashingtics - 1; + // Counters, time dependent power ups. // Time Bonus & Ring Bonus count settings @@ -11964,12 +11968,12 @@ void P_PlayerThink(player_t *player) else player->powers[pw_underwater] = 0; } - else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer + else if (player->powers[pw_underwater] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && (player->spectator || player->quittime))) // underwater timer player->powers[pw_underwater]--; if (player->powers[pw_spacetime] && (player->pflags & PF_GODMODE || (player->powers[pw_shield] & SH_PROTECTWATER))) player->powers[pw_spacetime] = 0; - else if (player->powers[pw_spacetime] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && player->spectator)) // underwater timer + else if (player->powers[pw_spacetime] && !(maptol & TOL_NIGHTS) && !((netgame || multiplayer) && (player->spectator || player->quittime))) // underwater timer player->powers[pw_spacetime]--; if (player->powers[pw_gravityboots] && player->powers[pw_gravityboots] < UINT16_MAX) From 412ba38a81b79909383bdeb94f12baf381b791d0 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 22 Jan 2020 03:19:15 +0100 Subject: [PATCH 25/56] Refactor player spawning code a little --- src/g_game.c | 126 ++++++++++++++++++++++++++------------------------ src/g_game.h | 4 +- src/p_setup.c | 6 +-- 3 files changed, 71 insertions(+), 65 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 30519b379..ce28766ec 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2547,74 +2547,24 @@ static boolean G_CheckSpot(INT32 playernum, mapthing_t *mthing) // or a not-so-appropriate spot, if it initially fails // due to a lack of starts open or something. // -void G_SpawnPlayer(INT32 playernum, boolean starpost) +void G_SpawnPlayer(INT32 playernum) { - mapthing_t *spawnpoint; - if (!playeringame[playernum]) return; P_SpawnPlayer(playernum); - - if (starpost) //Don't even bother with looking for a place to spawn. - { - P_MovePlayerToStarpost(playernum); -#ifdef HAVE_BLUA - LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :) -#endif - return; - } - - // -- CTF -- - // Order: CTF->DM->Coop - if (gametype == GT_CTF && players[playernum].ctfteam) - { - if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start - && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start - spawnpoint = G_FindCoopStart(playernum); // fallback - } - - // -- DM/Tag/CTF-spectator/etc -- - // Order: DM->CTF->Coop - else if (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF - || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && !(players[playernum].pflags & PF_TAGIT))) - { - if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start - && !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start - spawnpoint = G_FindCoopStart(playernum); // fallback - } - - // -- Other game modes -- - // Order: Coop->DM->CTF - else - { - if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start - && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start - spawnpoint = G_FindCTFStart(playernum); // fallback - } - - //No spawns found. ANYWHERE. - if (!spawnpoint) - { - if (nummapthings) - { - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) - CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n")); - spawnpoint = &mapthings[0]; - } - else - { - if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) - CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n")); - //P_MovePlayerToSpawn handles this fine if the spawnpoint is NULL. - } - } - P_MovePlayerToSpawn(playernum, spawnpoint); - + G_MovePlayerToSpawnOrStarpost(playernum); #ifdef HAVE_BLUA LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :) #endif +} +void G_MovePlayerToSpawnOrStarpost(INT32 playernum) +{ + if (players[playernum].starposttime) + P_MovePlayerToStarpost(playernum); + else + P_MovePlayerToSpawn(playernum, G_FindMapStart(playernum)); } mapthing_t *G_FindCTFStart(INT32 playernum) @@ -2711,6 +2661,60 @@ mapthing_t *G_FindCoopStart(INT32 playernum) return NULL; } +mapthing_t *G_FindMapStart(INT32 playernum) +{ + mapthing_t *spawnpoint; + + if (!playeringame[playernum]) + return NULL; + + // -- CTF -- + // Order: CTF->DM->Coop + if (gametype == GT_CTF && players[playernum].ctfteam) + { + if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start + && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start + spawnpoint = G_FindCoopStart(playernum); // fallback + } + + // -- DM/Tag/CTF-spectator/etc -- + // Order: DM->CTF->Coop + else if (gametype == GT_MATCH || gametype == GT_TEAMMATCH || gametype == GT_CTF + || ((gametype == GT_TAG || gametype == GT_HIDEANDSEEK) && !(players[playernum].pflags & PF_TAGIT))) + { + if (!(spawnpoint = G_FindMatchStart(playernum)) // find a DM start + && !(spawnpoint = G_FindCTFStart(playernum))) // find a CTF start + spawnpoint = G_FindCoopStart(playernum); // fallback + } + + // -- Other game modes -- + // Order: Coop->DM->CTF + else + { + if (!(spawnpoint = G_FindCoopStart(playernum)) // find a Co-op start + && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start + spawnpoint = G_FindCTFStart(playernum); // fallback + } + + //No spawns found. ANYWHERE. + if (!spawnpoint) + { + if (nummapthings) + { + if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n")); + spawnpoint = &mapthings[0]; + } + else + { + if (playernum == consoleplayer || (splitscreen && playernum == secondarydisplayplayer)) + CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n")); + } + } + + return spawnpoint; +} + // Go back through all the projectiles and remove all references to the old // player mobj, replacing them with the new one. void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo) @@ -2889,7 +2893,7 @@ void G_DoReborn(INT32 playernum) { if (!playeringame[i]) continue; - G_SpawnPlayer(i, (players[i].starposttime)); + G_SpawnPlayer(i); } // restore time in netgame (see also p_setup.c) @@ -2935,7 +2939,7 @@ void G_DoReborn(INT32 playernum) P_RemoveMobj(player->mo); } - G_SpawnPlayer(playernum, (player->starposttime)); + G_SpawnPlayer(playernum); if (oldmo) G_ChangePlayerReferences(oldmo, players[playernum].mo); } diff --git a/src/g_game.h b/src/g_game.h index e7f4a4677..7c4bd2161 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -133,7 +133,9 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc); mapthing_t *G_FindCTFStart(INT32 playernum); mapthing_t *G_FindMatchStart(INT32 playernum); mapthing_t *G_FindCoopStart(INT32 playernum); -void G_SpawnPlayer(INT32 playernum, boolean starpost); +mapthing_t *G_FindMapStart(INT32 playernum); +void G_MovePlayerToSpawnOrStarpost(INT32 playernum); +void G_SpawnPlayer(INT32 playernum); // Can be called by the startup code or M_Responder. // A normal game starts at map 1, but a warp test can start elsewhere diff --git a/src/p_setup.c b/src/p_setup.c index 673a9024e..b45d3bd80 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3057,11 +3057,11 @@ boolean P_SetupLevel(boolean skipprecip) if (players[i].starposttime) { - G_SpawnPlayer(i, true); + G_SpawnPlayer(i); P_ClearStarPost(players[i].starpostnum); } else - G_SpawnPlayer(i, false); + G_SpawnPlayer(i); } } @@ -3133,7 +3133,7 @@ boolean P_SetupLevel(boolean skipprecip) if (players[playersactive[i]].mo) P_RemoveMobj(players[playersactive[i]].mo); - G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location. + G_SpawnPlayer(playersactive[i]); //respawn the lucky player in his dedicated spawn location. } else CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n")); From 2527b6c3892ea616fa17b689a9f1a04b67dd0df5 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 22 Jan 2020 03:20:27 +0100 Subject: [PATCH 26/56] Teleport disconnected players to starpost if they fall in a pit --- src/p_spec.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index dba4e17b5..7547f604f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4415,10 +4415,18 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers case 6: // Death Pit (Camera Mod) case 7: // Death Pit (No Camera Mod) if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT); + { + if (player->quittime) + G_MovePlayerToSpawnOrStarpost(player - players); + else + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT); + } break; case 8: // Instant Kill - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); + if (player->quittime) + G_MovePlayerToSpawnOrStarpost(player - players); + else + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); break; case 9: // Ring Drainer (Floor Touch) case 10: // Ring Drainer (No Floor Touch) From cfec8609f943c2b7520027e06cd5fa0839e02754 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 22 Jan 2020 04:01:06 +0100 Subject: [PATCH 27/56] Fix missing declaration --- src/d_clisrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index fc50177ef..0106d559c 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -77,6 +77,7 @@ char motd[254], server_context[8]; // Message of the Day, Unique Context (even w // Server specific vars UINT8 playernode[MAXPLAYERS]; +char playeraddress[MAXPLAYERS][64]; // Minimum timeout for sending the savegame // The actual timeout will be longer depending on the savegame length From fb28ede66049396d531c1d910646882a037569c4 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Wed, 22 Jan 2020 16:58:57 +0100 Subject: [PATCH 28/56] Rename R_IsPointInSubsector to R_PointInSubsectorOrNull/Nil The old name made it really easy to accidentally read R_IsPointInSubsector as R_PointInSubsector, and anyway it didn't even make sense... --- src/lua_baselib.c | 6 +++--- src/m_cheat.c | 8 ++++---- src/p_mobj.c | 2 +- src/p_user.c | 4 ++-- src/r_main.c | 4 ++-- src/r_main.h | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 7a16f3c69..66bd30e32 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2193,11 +2193,11 @@ static int lib_rPointInSubsector(lua_State *L) return 1; } -static int lib_rIsPointInSubsector(lua_State *L) +static int lib_rPointInSubsectorOrNil(lua_State *L) { fixed_t x = luaL_checkfixed(L, 1); fixed_t y = luaL_checkfixed(L, 2); - subsector_t *sub = R_IsPointInSubsector(x, y); + subsector_t *sub = R_PointInSubsectorOrNull(x, y); //HUDSAFE INLEVEL if (sub) @@ -3141,7 +3141,7 @@ static luaL_Reg lib[] = { {"R_PointToDist",lib_rPointToDist}, {"R_PointToDist2",lib_rPointToDist2}, {"R_PointInSubsector",lib_rPointInSubsector}, - {"R_IsPointInSubsector",lib_rIsPointInSubsector}, + {"R_PointInSubsectorOrNil",lib_rPointInSubsectorOrNil}, // r_things (sprite) {"R_Char2Frame",lib_rChar2Frame}, diff --git a/src/m_cheat.c b/src/m_cheat.c index c284acf3e..980d9fc21 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -452,7 +452,7 @@ void Command_RTeleport_f(void) else inty = 0; - ss = R_IsPointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); + ss = R_PointInSubsectorOrNull(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT); if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) { CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); @@ -530,7 +530,7 @@ void Command_Teleport_f(void) inty = mt->y<z<sector->ceilingheight - ss->sector->floorheight < p->mo->height) { CONS_Alert(CONS_NOTICE, M_GetText("Spawnpoint not in a valid location.\n")); @@ -597,7 +597,7 @@ void Command_Teleport_f(void) return; } - ss = R_IsPointInSubsector(mo2->x, mo2->y); + ss = R_PointInSubsectorOrNull(mo2->x, mo2->y); if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) { CONS_Alert(CONS_NOTICE, M_GetText("Starpost not in a valid location.\n")); @@ -653,7 +653,7 @@ void Command_Teleport_f(void) } } - ss = R_IsPointInSubsector(intx, inty); + ss = R_PointInSubsectorOrNull(intx, inty); if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height) { CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n")); diff --git a/src/p_mobj.c b/src/p_mobj.c index a8599ceb5..c4ba9c14f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11114,7 +11114,7 @@ void P_SpawnPrecipitation(void) x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<>3); - precipsector = R_IsPointInSubsector(x, y); + precipsector = R_PointInSubsectorOrNull(x, y); // No sector? Stop wasting time, // move on to the next entry in the blockmap diff --git a/src/p_user.c b/src/p_user.c index a1df8a58b..74349e185 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3160,7 +3160,7 @@ static void P_DoClimbing(player_t *player) platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale)); - glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy); + glidesector = R_PointInSubsectorOrNull(player->mo->x + platx, player->mo->y + platy); { boolean floorclimb = false; @@ -10235,7 +10235,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall } // 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)); + newsubsec = R_PointInSubsectorOrNull(((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1), ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1)); if (!newsubsec) newsubsec = thiscam->subsector; diff --git a/src/r_main.c b/src/r_main.c index a93cd6f49..f4daac834 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -701,9 +701,9 @@ subsector_t *R_PointInSubsector(fixed_t x, fixed_t y) } // -// R_IsPointInSubsector, same as above but returns 0 if not in subsector +// R_PointInSubsectorOrNull, same as above but returns 0 if not in subsector // -subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y) +subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y) { node_t *node; INT32 side, i; diff --git a/src/r_main.h b/src/r_main.h index 3e575fbd7..d72e94973 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -64,7 +64,7 @@ fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1); fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); -subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y); +subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y); boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph); From f0daea39d43d1a3cd54385474dd6c27e65da2e4c Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 22 Jan 2020 22:19:00 -0800 Subject: [PATCH 29/56] Don't set controls to keys out of array bounds Shout-out to TAG's config that somehow had `setcontrol2 "custom3" "KEY931926528"`, cuasing the game to crash only in Splitscreen. --- src/g_input.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/g_input.c b/src/g_input.c index ac901703f..2efae9cf3 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -662,7 +662,14 @@ INT32 G_KeyStringtoNum(const char *keystr) return keystr[0]; if (!strncmp(keystr, "KEY", 3) && keystr[3] >= '0' && keystr[3] <= '9') - return atoi(&keystr[3]); + { + /* what if we out of range bruh? */ + j = atoi(&keystr[3]); + if (j < NUMINPUTS) + return j; + else + return 0; + } for (j = 0; j < NUMKEYNAMES; j++) if (!stricmp(keynames[j].name, keystr)) From ce20642fa7597d2a4418d1572894b0b90f1cdb42 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Thu, 23 Jan 2020 18:52:16 +0100 Subject: [PATCH 30/56] Do not protect non-IT players in tag gametypes --- src/p_user.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index b01f702fa..832a6a30e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -12211,7 +12211,8 @@ void P_PlayerThink(player_t *player) } // IF PLAYER NOT HERE THEN FLASH END IF - if (player->quittime && player->powers[pw_flashing] < flashingtics - 1) + if (player->quittime && player->powers[pw_flashing] < flashingtics - 1 + && !(G_TagGametype() && !(player->pflags & PF_TAGIT)) && !player->gotflag) player->powers[pw_flashing] = flashingtics - 1; // Counters, time dependent power ups. From b0b22b53d6a99f7a40f386e85e580e4de4866cde Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Thu, 23 Jan 2020 19:58:13 +0100 Subject: [PATCH 31/56] Ignore disconnected players in tag gametypes Disconnected players do not become IT at round start. If all non-ITs are disconnected, the round ends. If all ITs are disconnected, one of the non-ITs becomes IT, or the round ends if in Hide & Seek. --- src/p_inter.c | 4 ++-- src/p_setup.c | 2 +- src/p_tick.c | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/p_inter.c b/src/p_inter.c index 71dcd70a1..8090b7406 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2257,9 +2257,9 @@ void P_CheckSurvivors(void) { if (players[i].spectator) spectators++; - else if (players[i].pflags & PF_TAGIT) + else if ((players[i].pflags & PF_TAGIT) && players[i].quittime < 30 * TICRATE) taggers++; - else if (!(players[i].pflags & PF_GAMETYPEOVER)) + else if (!(players[i].pflags & PF_GAMETYPEOVER) && players[i].quittime < 30 * TICRATE) { survivorarray[survivors] = i; survivors++; diff --git a/src/p_setup.c b/src/p_setup.c index 679060d44..729ee00c2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3097,7 +3097,7 @@ static void P_InitTagGametype(void) //Also, you'd never have to loop through all 32 players slots to find anything ever again. for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && !players[i].spectator) + if (playeringame[i] && !(players[i].spectator && players[i].quittime)) { playersactive[realnumplayers] = i; //stores the player's node in the array. realnumplayers++; diff --git a/src/p_tick.c b/src/p_tick.c index 4dd3bb30a..a4b8aa097 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -599,6 +599,10 @@ void P_Ticker(boolean run) if (players[i].quittime) { players[i].quittime++; + + if (players[i].quittime == 30 * TICRATE) + P_CheckSurvivors(); + if (server && players[i].quittime >= FixedMul(cv_rejointimeout.value, 60 * TICRATE)) SendKick(i, KICK_MSG_PLAYER_QUIT); } From ba127008cfcbc861feb146f7fb6706f6421ab8a0 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Thu, 23 Jan 2020 19:59:41 +0100 Subject: [PATCH 32/56] Do not spam player quit net commands --- src/p_tick.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index a4b8aa097..348f2557c 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -603,7 +603,8 @@ void P_Ticker(boolean run) if (players[i].quittime == 30 * TICRATE) P_CheckSurvivors(); - if (server && players[i].quittime >= FixedMul(cv_rejointimeout.value, 60 * TICRATE)) + if (server && players[i].quittime >= FixedMul(cv_rejointimeout.value, 60 * TICRATE) + && !(players[i].quittime % TICRATE)) SendKick(i, KICK_MSG_PLAYER_QUIT); } } From 3d9466e5f550a8d11da4989f62e32eb0ea888c11 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 13:57:39 -0800 Subject: [PATCH 33/56] Semantics --- src/g_input.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 2efae9cf3..ed7bc5cb6 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -667,8 +667,7 @@ INT32 G_KeyStringtoNum(const char *keystr) j = atoi(&keystr[3]); if (j < NUMINPUTS) return j; - else - return 0; + return 0; } for (j = 0; j < NUMKEYNAMES; j++) From c3f42859882e6a1a789668d9b78d1310dd5e7312 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 18:01:59 -0800 Subject: [PATCH 34/56] Put branch name and commit hash in EXENAME for AppVeyor builds srb2win-master-a6d49eaaa70be5f88c26623c7b4a2fa5a770341e.exe --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 6b80b4ec3..cc77f102e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -83,7 +83,8 @@ before_build: - ccache -V - ccache -s - if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" ) -- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX%" +- set "EXENAME=EXENAME=srb2win-%APPVEYOR_REPO_BRANCH%-%APPVEYOR_REPO_COMMIT%.exe" +- set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%" - if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) - set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1" From d3315ae03c57296bfb5a7f9f5959492bdb7de24c Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 18:09:34 -0800 Subject: [PATCH 35/56] Put the abbreviated commit hash in the EXENAME for AppVeyor srb2win-master-a6d49eaaa.exe --- appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index cc77f102e..c4b5263e9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -83,7 +83,9 @@ before_build: - ccache -V - ccache -s - if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" ) -- set "EXENAME=EXENAME=srb2win-%APPVEYOR_REPO_BRANCH%-%APPVEYOR_REPO_COMMIT%.exe" +# get abbreviated (7 char) commit hash +- set "COMMIT=%APPVEYOR_REPO_COMMIT:~0,7%" +- set "EXENAME=EXENAME=srb2win-%APPVEYOR_REPO_BRANCH%-%COMMIT%.exe" - set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%" - if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) - set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1" From b1d931d471bcf2ec9a40f6e7e52518807c5fd14b Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 18:55:25 -0800 Subject: [PATCH 36/56] Well I'm an idiot --- appveyor.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c4b5263e9..96bd6ce84 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -83,9 +83,9 @@ before_build: - ccache -V - ccache -s - if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" ) -# get abbreviated (7 char) commit hash -- set "COMMIT=%APPVEYOR_REPO_COMMIT:~0,7%" -- set "EXENAME=EXENAME=srb2win-%APPVEYOR_REPO_BRANCH%-%COMMIT%.exe" +- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt +- cmd: set /P GITSHORT=<%TMP%/gitshort.txt +- set "EXENAME=EXENAME=srb2win-%APPVEYOR_REPO_BRANCH%-%GITSHORT%.exe" - set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%" - if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) - set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1" @@ -102,8 +102,6 @@ after_build: ) - if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" ) - ccache -s -- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt -- cmd: set /P GITSHORT=<%TMP%/gitshort.txt - set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z - set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z - cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore From ef2febe1e01bc7c93f30d2063bfd754b1a79dd3a Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 19:58:26 -0800 Subject: [PATCH 37/56] Use the pull request repo, branch and commit srb2win-jameds:appveyor-exename-b1d931d47.exe --- appveyor.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 96bd6ce84..543308306 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -83,9 +83,12 @@ before_build: - ccache -V - ccache -s - if [%NOUPX%] == [1] ( set "NOUPX=NOUPX=1" ) else ( set "NOUPX=" ) -- cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt +- if defined [%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%] ( set "COMMIT=%APPVEYOR_PULL_REQUEST_HEAD_COMMIT%" ) else ( set "COMMIT=%APPVEYOR_REPO_COMMIT%" ) +- cmd: git rev-parse --short %COMMIT%>%TMP%/gitshort.txt - cmd: set /P GITSHORT=<%TMP%/gitshort.txt -- set "EXENAME=EXENAME=srb2win-%APPVEYOR_REPO_BRANCH%-%GITSHORT%.exe" +# for pull requests, take the owner's name only, if this isn't the same repo of course +- if [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( set "REPO=%APPVEYOR_REPO_BRANCH" ) else ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a:%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH" ) +- set "EXENAME=EXENAME=srb2win-%REPO%-%GITSHORT%.exe" - set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%" - if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) - set "SRB2_MFLAGS=%SRB2_MFLAGS% %MINGW_FLAGS% %CONFIGURATION%=1" From 6337932190d68d6f825f4f5dd47a6f3655c88f16 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 20:13:57 -0800 Subject: [PATCH 38/56] I promise I know what I'm doing --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 543308306..fac974c17 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -87,7 +87,7 @@ before_build: - cmd: git rev-parse --short %COMMIT%>%TMP%/gitshort.txt - cmd: set /P GITSHORT=<%TMP%/gitshort.txt # for pull requests, take the owner's name only, if this isn't the same repo of course -- if [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( set "REPO=%APPVEYOR_REPO_BRANCH" ) else ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a:%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH" ) +- if [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( set "REPO=%APPVEYOR_REPO_BRANCH%" ) else ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a:%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) - set "EXENAME=EXENAME=srb2win-%REPO%-%GITSHORT%.exe" - set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%" - if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) From e082553f6d3a90baf97e056ab6790ce136f502d0 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 20:34:26 -0800 Subject: [PATCH 39/56] Check if this actually is a PR before using those variables --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index fac974c17..51052ff6e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -87,7 +87,8 @@ before_build: - cmd: git rev-parse --short %COMMIT%>%TMP%/gitshort.txt - cmd: set /P GITSHORT=<%TMP%/gitshort.txt # for pull requests, take the owner's name only, if this isn't the same repo of course -- if [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( set "REPO=%APPVEYOR_REPO_BRANCH%" ) else ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a:%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) +- set "REPO=%APPVEYOR_REPO_BRANCH%" +- if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [] ( if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a:%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) ) - set "EXENAME=EXENAME=srb2win-%REPO%-%GITSHORT%.exe" - set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%" - if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) From 70cf119a8402607116b2f8fbb79028a2de0e8d96 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 20:35:53 -0800 Subject: [PATCH 40/56] Windows is dumb so no colon srb2win-jameds-appveyor-exename-b1d931d47.exe --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 51052ff6e..b111c8f28 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -88,7 +88,7 @@ before_build: - cmd: set /P GITSHORT=<%TMP%/gitshort.txt # for pull requests, take the owner's name only, if this isn't the same repo of course - set "REPO=%APPVEYOR_REPO_BRANCH%" -- if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [] ( if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a:%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) ) +- if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [] ( if not [%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%] == [%APPVEYOR_REPO_NAME%] ( for /f "delims=/" %%a in ("%APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME%") do set "REPO=%%a-%APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH%" ) ) - set "EXENAME=EXENAME=srb2win-%REPO%-%GITSHORT%.exe" - set "SRB2_MFLAGS=-C src WARNINGMODE=1 CCACHE=1 NOOBJDUMP=1 %NOUPX% %EXENAME%" - if [%X86_64%] == [1] ( set "MINGW_FLAGS=MINGW64=1 X86_64=1 GCC81=1" ) else ( set "MINGW_FLAGS=MINGW=1 GCC91=1" ) From 4304fe91e65845e3887935de046876b6313af9c9 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 23 Jan 2020 21:06:48 -0800 Subject: [PATCH 41/56] Name the archive like the EXE --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index b111c8f28..d33d3d3a3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -106,8 +106,8 @@ after_build: ) - if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" ) - ccache -s -- set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z -- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z +- set BUILD_ARCHIVE=%REPO%-%GITSHORT%-%CONFIGURATION%.7z +- set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z - cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore - appveyor PushArtifact %BUILD_ARCHIVE% - cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE% From 8bd897a269fc26e0894019169356eec777d88c0a Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Fri, 24 Jan 2020 19:56:57 +0100 Subject: [PATCH 42/56] Be silent when "kicking" a disconnected player This lets the host manually remove a body if they want, without polluting the chat with redundant messages. --- src/d_clisrv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0106d559c..841a0e322 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2918,7 +2918,8 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) switch (msg) { case KICK_MSG_GO_AWAY: - HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false); + if (!players[pnum].quittime) + HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false); kickreason = KR_KICK; break; case KICK_MSG_PING_HIGH: From 59ed381fc08edd6888967e27545c485ab670210b Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 24 Jan 2020 16:38:46 -0800 Subject: [PATCH 43/56] Credit Tatsuru, he's done a bit --- src/f_finale.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/f_finale.c b/src/f_finale.c index 87e41df78..99ff586f4 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1165,6 +1165,7 @@ static const char *credits[] = { "Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible "Wessel \"sphere\" Smit", "Ben \"Cue\" Woodford", + "Ikaro \"Tatsuru\" Vinhas", // Git contributors with 5+ approved merges of substantive quality, // or contributors with at least one groundbreaking merge, may be named. // Everyone else is acknowledged under "Special Thanks > SRB2 Community Contributors". From c9bc3837f9b05be6e66dc204d98cd511bbf5a475 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 24 Jan 2020 16:44:53 -0800 Subject: [PATCH 44/56] Signed is unsigned, cool --- src/p_tick.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index 348f2557c..0b30ff42d 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -603,7 +603,7 @@ void P_Ticker(boolean run) if (players[i].quittime == 30 * TICRATE) P_CheckSurvivors(); - if (server && players[i].quittime >= FixedMul(cv_rejointimeout.value, 60 * TICRATE) + if (server && players[i].quittime >= (tic_t)FixedMul(cv_rejointimeout.value, 60 * TICRATE) && !(players[i].quittime % TICRATE)) SendKick(i, KICK_MSG_PLAYER_QUIT); } From d30b48cfd1b74f7f2a60a1e1f2a7347dc4aaaf11 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 25 Jan 2020 14:04:16 +0100 Subject: [PATCH 45/56] Fix lava removing fire shield --- src/p_mobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index c4ba9c14f..e6d84086c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3396,7 +3396,7 @@ void P_MobjCheckWater(mobj_t *mobj) if (!((p->powers[pw_super]) || (p->powers[pw_invulnerability]))) { boolean electric = !!(p->powers[pw_shield] & SH_PROTECTELECTRIC); - if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER))) + if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER) && !(mobj->eflags & MFE_TOUCHLAVA))) { // Water removes electric and non-water fire shields... P_FlashPal(p, electric From 2dd13bb2a4f434a6436cb341fccb68cd95e0c6dd Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 25 Jan 2020 11:31:06 -0500 Subject: [PATCH 46/56] Fix damagetype for Cybrak flamethrower. --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index de6ff475c..ef1d161de 100644 --- a/src/info.c +++ b/src/info.c @@ -6487,7 +6487,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 24*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset - 0, // mass + DMG_FIRE, // mass 1, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags From f90c70ebe287e215415164dc341fe7905ceb2dae Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 25 Jan 2020 11:34:30 -0500 Subject: [PATCH 47/56] Make the DMG actually *applied*. Consequence: flame will continue flying through player instead of dying in midair and dropping a flame, but this is actually desirable given the current behaviour looks kind of shitty. --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index ef1d161de..45034fe37 100644 --- a/src/info.c +++ b/src/info.c @@ -6490,7 +6490,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = DMG_FIRE, // mass 1, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags + MF_NOBLOCKMAP|MF_MISSILE|MF_PAIN|MF_NOGRAVITY, // flags S_NULL // raisestate }, From e57589b1068ea3dec70bd3aa501f38371d409b24 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Sat, 25 Jan 2020 19:03:15 -0600 Subject: [PATCH 48/56] Fix the minecart angle thing --- src/p_user.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index 901cd8ae6..fd3f860cf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -10790,12 +10790,23 @@ static void P_MinecartThink(player_t *player) else if (angdiff > ANGLE_180 && angdiff < InvAngle(MINECARTCONEMAX)) player->mo->angle = minecart->angle - MINECARTCONEMAX; - if (angdiff + minecart->angle != player->mo->angle && (!demoplayback || P_AnalogMove(player))) + if (!demoplayback || P_AnalogMove(player)) { + angle_t *ang = NULL; + if (player == &players[consoleplayer]) - localangle = player->mo->angle; + ang = &localangle; else if (player == &players[secondarydisplayplayer]) - localangle2 = player->mo->angle; + ang = &localangle2; + + if (ang) + { + angdiff = *ang - minecart->angle; + if (angdiff < ANGLE_180 && angdiff > MINECARTCONEMAX) + *ang = minecart->angle + MINECARTCONEMAX; + else if (angdiff > ANGLE_180 && angdiff < InvAngle(MINECARTCONEMAX)) + *ang = minecart->angle - MINECARTCONEMAX; + } } } From ea28304d8c291ece7b8e489a932fc4c862241fb3 Mon Sep 17 00:00:00 2001 From: Zwip-Zwap Zapony Date: Sun, 26 Jan 2020 10:53:37 +0100 Subject: [PATCH 49/56] Fix missing "RINGSNUMTICS" in dehacked.c This fixes 16/20 of the HUD items in dehacked.c being off by one (Same case as the MFE_ flags thing) Also fixes dehacked.c mentioning "LAPS", which doesn't exist --- src/dehacked.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 4c36639a2..45f00b8cf 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -9143,6 +9143,7 @@ static const char *const HUDITEMS_LIST[] = { "RINGS", "RINGSNUM", + "RINGSNUMTICS", "SCORE", "SCORENUM", @@ -9162,8 +9163,7 @@ static const char *const HUDITEMS_LIST[] = { "TIMELEFTNUM", "TIMEUP", "HUNTPICS", - "POWERUPS", - "LAP" + "POWERUPS" }; static const char *const MENUTYPES_LIST[] = { From cf7b4d826a82d561b6981dd1fdce106e57fbc234 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sun, 26 Jan 2020 23:46:07 -0300 Subject: [PATCH 50/56] Remove redundancy --- src/g_game.c | 4 ++++ src/p_setup.c | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index f5d7cd2fb..8383782cb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1941,6 +1941,10 @@ boolean G_IsTitleCardAvailable(void) if (gametyperules & GTR_NOTITLECARD) return false; + // The current level has no name. + if (!mapheaderinfo[gamemap-1]->lvlttl[0]) + return false; + // The title card is available. return true; } diff --git a/src/p_setup.c b/src/p_setup.c index 2b0a5efa3..c291dc7c3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3684,8 +3684,7 @@ boolean P_LoadLevel(boolean fromnetsave) return true; // If so... - if ((!(mapheaderinfo[gamemap-1]->levelflags & LF_NOTITLECARD)) && (*mapheaderinfo[gamemap-1]->lvlttl != '\0')) - G_PreLevelTitleCard(); + G_PreLevelTitleCard(); return true; } From 1774ba22b6ea77fbc0442573d08e00439e9b6fbb Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Sun, 26 Jan 2020 23:50:36 -0300 Subject: [PATCH 51/56] Fix title card not showing up at all if focus lost --- src/st_stuff.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index 4676506fc..d99d564c8 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1278,13 +1278,15 @@ void ST_preDrawTitleCard(void) // void ST_runTitleCard(void) { + boolean run = !(paused || P_AutoPause()); + if (!G_IsTitleCardAvailable()) return; if (lt_ticker >= (lt_endtime + TICRATE)) return; - if (!(paused || P_AutoPause())) + if (run || (lt_ticker < PRELEVELTIME)) { // tick lt_ticker++; From 1548a22ea902a201de6779a6877bd225c7cf735e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 27 Jan 2020 00:44:10 -0300 Subject: [PATCH 52/56] Fix M_DrawNightsAttackMountains being broken for obvious reasons --- src/m_menu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index f8c14dd69..049b66d67 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5388,7 +5388,8 @@ static void M_DrawNightsAttackMountains(void) static INT32 bgscrollx; INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); patch_t *background = W_CachePatchName(curbgname, PU_PATCH); - INT32 x = FixedInt(bgscrollx) % SHORT(background->width); + INT16 w = SHORT(background->width); + INT32 x = FixedInt(-bgscrollx) % w; INT32 y = BASEVIDHEIGHT - SHORT(background->height)*2; if (vid.height != BASEVIDHEIGHT * dupz) @@ -5396,11 +5397,13 @@ static void M_DrawNightsAttackMountains(void) V_DrawFill(0, y+50, vid.width, BASEVIDHEIGHT, V_SNAPTOLEFT|31); V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background); - x += SHORT(background->width); + x += w; if (x < BASEVIDWIDTH) V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background); - bgscrollx -= (FRACUNIT/2); + bgscrollx += (FRACUNIT/2); + if (bgscrollx > w< Date: Mon, 27 Jan 2020 13:28:07 -0300 Subject: [PATCH 53/56] Fix F_StartContinue fading out incorrectly in OpenGL --- src/f_finale.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index bc904d8f2..ed89e05cd 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -3628,7 +3628,6 @@ void F_StartContinue(void) } wipestyleflags = WSF_FADEOUT; - F_TryColormapFade(31); G_SetGamestate(GS_CONTINUING); gameaction = ga_nothing; From 31ce0764115e2966c3d9f0ed0b26b0c0bec65f78 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Tue, 28 Jan 2020 14:02:36 +0100 Subject: [PATCH 54/56] Only call P_CheckSurvivors() in tag gametypes --- src/p_tick.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_tick.c b/src/p_tick.c index 0b30ff42d..74472b71f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -600,7 +600,7 @@ void P_Ticker(boolean run) { players[i].quittime++; - if (players[i].quittime == 30 * TICRATE) + if (players[i].quittime == 30 * TICRATE && G_TagGametype()) P_CheckSurvivors(); if (server && players[i].quittime >= (tic_t)FixedMul(cv_rejointimeout.value, 60 * TICRATE) From f4de1938098067327731d8502ff4ec68e74ee027 Mon Sep 17 00:00:00 2001 From: Steel Titanium Date: Thu, 30 Jan 2020 22:11:50 -0500 Subject: [PATCH 55/56] Fix memory leak while chat is on screen --- src/hu_stuff.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 274c2bdfd..69e8c99ff 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1437,7 +1437,7 @@ static void HU_drawMiniChat(void) for (; i>0; i--) { - const char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i-1]); + 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; @@ -1479,6 +1479,9 @@ static void HU_drawMiniChat(void) dy = 0; dx = 0; msglines += linescount+1; + + if (msg) + Z_Free(msg); } y = chaty - charheight*(msglines+1); @@ -1501,7 +1504,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, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_mini[i]); // get the current message, and word wrap it. + 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 @@ -1547,6 +1550,9 @@ static void HU_drawMiniChat(void) } dy += charheight; dx = 0; + + if (msg) + Z_Free(msg); } // decrement addy and make that shit smooth: @@ -1598,7 +1604,7 @@ static void HU_drawChatLog(INT32 offset) { INT32 clrflag = 0; INT32 j = 0; - const char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it. + char *msg = CHAT_WordWrap(x+2, boxw-(charwidth*2), V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, chat_log[i]); // get the current message, and word wrap it. UINT8 *colormap = NULL; while(msg[j]) // iterate through msg { @@ -1638,6 +1644,9 @@ static void HU_drawChatLog(INT32 offset) } dy += charheight; dx = 0; + + if (msg) + Z_Free(msg); } From 7dd0f2b80847e4ca794457c38c52082628b20664 Mon Sep 17 00:00:00 2001 From: Louis-Antoine Date: Sat, 1 Feb 2020 20:19:39 +0100 Subject: [PATCH 56/56] Fix splitscreen player being unable to move --- src/d_clisrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ee4e62b91..79b63bb81 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4678,6 +4678,7 @@ static void Local_Maketic(INT32 realtics) G_BuildTiccmd(&localcmds2, realtics, 2); localcmds.angleturn |= TICCMD_RECEIVED; + localcmds2.angleturn |= TICCMD_RECEIVED; } // This function is utter bullshit and is responsible for