From 7444c22950207a6de474a66f549f2a176407a374 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Fri, 28 Apr 2023 00:24:26 +0200 Subject: [PATCH 1/2] Add an option to display the path travalled by the local player This is useful to avoid getting lost on larger maps. --- src/am_map.cpp | 114 ++++++++++++++++++++++++++++++++++++-- wadsrc/static/menudef.txt | 5 ++ 2 files changed, 114 insertions(+), 5 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 8510eafa19..d6916b27d5 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -197,6 +197,8 @@ CUSTOM_CVAR(Int, am_emptyspacemargin, 0, CVAR_ARCHIVE) CVAR(Bool, am_followplayer, true, CVAR_ARCHIVE) CVAR(Bool, am_portaloverlay, true, CVAR_ARCHIVE) CVAR(Bool, am_showgrid, false, CVAR_ARCHIVE) +CVAR(Bool, am_path, false, CVAR_ARCHIVE) +CVAR(Int, am_pathlength, 1000, CVAR_ARCHIVE) CVAR(Float, am_zoomdir, 0.f, CVAR_ARCHIVE) static const char *const DEFAULT_FONT_NAME = "AMMNUMx"; @@ -296,6 +298,7 @@ CVAR (Color, am_thingcolor_ncmonster, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_item, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_citem, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_portalcolor, 0x404040, CVAR_ARCHIVE); +CVAR (Color, am_pathcolor, 0x4080c0, CVAR_ARCHIVE); CVAR (Color, am_ovyourcolor, 0xfce8d8, CVAR_ARCHIVE); CVAR (Color, am_ovwallcolor, 0x00ff00, CVAR_ARCHIVE); @@ -318,6 +321,7 @@ CVAR (Color, am_ovthingcolor_ncmonster, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_citem, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovportalcolor, 0x004022, CVAR_ARCHIVE); +CVAR (Color, am_ovpathcolor, 0x4080c0, CVAR_ARCHIVE); //============================================================================= // @@ -381,6 +385,7 @@ static const char *ColorNames[] = { "SecretSectorColor", "UnexploredSecretColor", "PortalColor", + "PathColor", "AlmostBackgroundColor", nullptr }; @@ -413,6 +418,7 @@ struct AMColorset SecretSectorColor, UnexploredSecretColor, PortalColor, + PathColor, AlmostBackgroundColor, AM_NUM_COLORS }; @@ -538,7 +544,8 @@ static FColorCVarRef *cv_standard[] = { &am_interlevelcolor, &am_secretsectorcolor, &am_unexploredsecretcolor, - &am_portalcolor + &am_portalcolor, + &am_pathcolor }; static FColorCVarRef *cv_overlay[] = { @@ -565,7 +572,8 @@ static FColorCVarRef *cv_overlay[] = { &am_ovinterlevelcolor, &am_ovsecretsectorcolor, &am_ovunexploredsecretcolor, - &am_ovportalcolor + &am_ovportalcolor, + &am_ovpathcolor }; CCMD(am_restorecolors) @@ -608,8 +616,9 @@ static unsigned char DoomColors[]= { NOT_USED, // interteleport NOT_USED, // secretsector NOT_USED, // unexploredsecretsector + 0x40,0x40,0x40, // portal + 0x40,0x80,0xb0, // path 0x10,0x10,0x10, // almostbackground - 0x40,0x40,0x40 // portal }; static unsigned char StrifeColors[]= { @@ -636,8 +645,9 @@ static unsigned char StrifeColors[]= { NOT_USED, // interteleport NOT_USED, // secretsector NOT_USED, // unexploredsecretsector + 0x40,0x40,0x40, // portal + 0x40,0x80,0xb0, // path 0x10,0x10,0x10, // almostbackground - 0x40,0x40,0x40 // portal }; static unsigned char RavenColors[]= { @@ -664,8 +674,9 @@ static unsigned char RavenColors[]= { NOT_USED, // interteleport NOT_USED, // secretsector NOT_USED, // unexploredsecretsector + 0x50,0x50,0x50, // portal + 0x40,0x80,0xb0, // path 0x10,0x10,0x10, // almostbackground - 0x50,0x50,0x50 // portal }; #undef NOT_USED @@ -971,6 +982,8 @@ class DAutomap :public DAutomapBase TArray points; + TArray path_history; // history of points the local player has travelled to + // translates between frame-buffer and map distances double FTOM(double x) { @@ -1015,6 +1028,8 @@ class DAutomap :public DAutomapBase bool clipMline(mline_t *ml, fline_t *fl); void drawMline(mline_t *ml, const AMColor &color); void drawMline(mline_t *ml, int colorindex); + void collectPath(); + void drawPath(int color); void drawGrid(int color); void drawSubsectors(); void drawSeg(seg_t *seg, const AMColor &color); @@ -1544,6 +1559,10 @@ void DAutomap::doFollowPlayer () void DAutomap::Ticker () { + // Player path is collected even while the automap isn't visible or if am_path is disabled. + // This way, you can toggle am_path during gameplay and still see your previously travelled path. + collectPath(); + if (!automapactive) return; @@ -1808,6 +1827,88 @@ void DAutomap::drawMline (mline_t *ml, int colorindex) drawMline(ml, AMColors[colorindex]); } +//============================================================================= +// +// Computes the list of lines to be drawn in drawPath() based on local player +// position. +// +//============================================================================= + +void DAutomap::collectPath () +{ + DVector2 pos = players[consoleplayer].camera->InterpolatedPosition(r_viewpoint.TicFrac); + mline_t ml; + if (path_history.Size() >= 1) + { + // Create a path between the last point and current point if there's enough distance + // travelled by the player since the last point. + mline_t last_line = path_history.Last(); + constexpr int MIN_DISTANCE_BETWEEN_POINTS = 32; + if (abs(last_line.b.x - pos.X) >= MIN_DISTANCE_BETWEEN_POINTS || abs(last_line.b.y - pos.Y) >= MIN_DISTANCE_BETWEEN_POINTS) + { + // If the distance between two points is very high, the player has likely teleported so no path should be drawn between the points. + constexpr int MAX_DISTANCE_BETWEEN_TICKS = 100; + if (abs(last_line.b.x - pos.X) >= MAX_DISTANCE_BETWEEN_TICKS || abs(last_line.b.y - pos.Y) >= MAX_DISTANCE_BETWEEN_TICKS) + { + ml.a.x = pos.X; + ml.a.y = pos.Y; + } + else + { + ml.a.x = last_line.b.x; + ml.a.y = last_line.b.y; + } + + ml.b.x = pos.X; + ml.b.y = pos.Y; + + if (path_history.Size() > am_pathlength) + { + // Path is too long; remove the oldest lines. + path_history.Delete(0); + } + path_history.Push(ml); + } + } + else + { + // Create the first line in the path history. + ml.a.x = pos.X; + ml.a.y = pos.Y; + ml.b.x = pos.X; + ml.b.y = pos.Y; + path_history.Push(ml); + } +} + +//============================================================================= +// +// Draws the path taken by the local player. +// This can be useful to avoid getting lost in larger maps. +// +//============================================================================= + +void DAutomap::drawPath (int color) +{ + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + TArray path_history_rotated = path_history; + for (mline_t line : path_history_rotated) + { + rotatePoint(&line.a.x, &line.a.y); + rotatePoint(&line.b.x, &line.b.y); + drawMline(&line, color); + } + } + else + { + for (mline_t line : path_history) + { + drawMline(&line, color); + } + } +} + //============================================================================= // // Draws flat (floor/ceiling tile) aligned grid lines. @@ -3310,6 +3411,9 @@ void DAutomap::Drawer (int bottom) if (am_showgrid) drawGrid(AMColors.GridColor); + + if (am_path) + drawPath(AMColors.PathColor); drawWalls(allmap); drawPlayers(); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index e0c8d8c810..f5d0f0d658 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1336,6 +1336,8 @@ OptionMenu AutomapOptions protected StaticText "" Option "$AUTOMAPMNU_ROTATE", "am_rotate", "RotateTypes" Option "$AUTOMAPMNU_FOLLOW", "am_followplayer", "OnOff" + Option "$AUTOMAPMNU_PATH", "am_path", "OnOff" + Slider "$AUTOMAPMNU_PATHLENGTH", "am_pathlength", 100, 10000, 100, 0 Option "$AUTOMAPMNU_OVERLAY", "am_overlay", "OverlayTypes" Option "$AUTOMAPMNU_TEXTURED", "am_textured", "OnOff" Slider "$AUTOMAPMNU_LINEALPHA", "am_linealpha", 0.1, 1.0, 0.1, 1 @@ -1395,6 +1397,7 @@ OptionMenu MapControlsMenu protected MapControl "$MAPCNTRLMNU_TOGGLEZOOM", "am_gobig" MapControl "$MAPCNTRLMNU_TOGGLEFOLLOW", "am_togglefollow" MapControl "$MAPCNTRLMNU_ROTATE", "toggle am_rotate" + MapControl "$MAPCNTRLMNU_PATH", "toggle am_path" MapControl "$MAPCNTRLMNU_TOGGLEGRID", "am_togglegrid" MapControl "$MAPCNTRLMNU_TOGGLETEXTURE", "am_toggletexture" @@ -1434,6 +1437,7 @@ OptionMenu MapColorMenu protected ColorPicker "$MAPCOLORMNU_UNEXPLOREDSECRETCOLOR", "am_unexploredsecretcolor" ColorPicker "$MAPCOLORMNU_SPECIALWALLCOLOR", "am_specialwallcolor" ColorPicker "$MAPCOLORMNU_PORTAL", "am_portalcolor" + ColorPicker "$MAPCOLORMNU_PATH", "am_pathcolor" } OptionMenu MapColorMenuCheats protected @@ -1465,6 +1469,7 @@ OptionMenu MapColorMenuOverlay protected ColorPicker "$MAPCOLORMNU_UNEXPLOREDSECRETCOLOR", "am_ovunexploredsecretcolor" ColorPicker "$MAPCOLORMNU_SPECIALWALLCOLOR", "am_ovspecialwallcolor" ColorPicker "$MAPCOLORMNU_PORTAL", "am_ovportalcolor" + ColorPicker "$MAPCOLORMNU_PATH", "am_ovpathcolor" } OptionMenu MapColorMenuCheatsOverlay protected From d853f9b355d4bdd411191966de738a5f5ec37cf9 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Thu, 21 Sep 2023 03:52:19 +0200 Subject: [PATCH 2/2] Use velocity to detect teleports in `am_path` drawing --- src/am_map.cpp | 11 +++++++---- src/am_map.h | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index d6916b27d5..9caac9b1b0 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1846,9 +1846,10 @@ void DAutomap::collectPath () constexpr int MIN_DISTANCE_BETWEEN_POINTS = 32; if (abs(last_line.b.x - pos.X) >= MIN_DISTANCE_BETWEEN_POINTS || abs(last_line.b.y - pos.Y) >= MIN_DISTANCE_BETWEEN_POINTS) { - // If the distance between two points is very high, the player has likely teleported so no path should be drawn between the points. - constexpr int MAX_DISTANCE_BETWEEN_TICKS = 100; - if (abs(last_line.b.x - pos.X) >= MAX_DISTANCE_BETWEEN_TICKS || abs(last_line.b.y - pos.Y) >= MAX_DISTANCE_BETWEEN_TICKS) + // If the player's velocity is lower than the distance between the last two ticks (with some tolerance), + // the player has likely teleported so no path should be drawn between the points. + constexpr float EPSILON = 10.0; + if ((pos - last_tick_pos).Length() > (players[consoleplayer].camera->VelXYToSpeed() + EPSILON)) { ml.a.x = pos.X; ml.a.y = pos.Y; @@ -1862,7 +1863,7 @@ void DAutomap::collectPath () ml.b.x = pos.X; ml.b.y = pos.Y; - if (path_history.Size() > am_pathlength) + if (path_history.Size() > uint32_t(am_pathlength)) { // Path is too long; remove the oldest lines. path_history.Delete(0); @@ -1879,6 +1880,8 @@ void DAutomap::collectPath () ml.b.y = pos.Y; path_history.Push(ml); } + + last_tick_pos = players[consoleplayer].camera->InterpolatedPosition(r_viewpoint.TicFrac); } //============================================================================= diff --git a/src/am_map.h b/src/am_map.h index 3665e44383..306e19611b 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -44,6 +44,9 @@ public: // called instead of view drawer if automap active. virtual void Drawer(int bottom) = 0; + // Used for am_path drawing to calculate distance between ticks. + DVector2 last_tick_pos; + virtual void NewResolution() = 0; virtual void LevelInit() = 0; virtual void UpdateShowAllLines() = 0;