2016-03-01 15:47:10 +00:00
//-----------------------------------------------------------------------------
//
2017-04-17 11:33:19 +00:00
// Copyright 1993-1996 id Software
// Copyright 1994-1996 Raven Software
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is distributed in the hope that it will be useful,
2016-03-01 15:47:10 +00:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2017-04-17 11:33:19 +00:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
//-----------------------------------------------------------------------------
2016-03-01 15:47:10 +00:00
//
//
// DESCRIPTION: the automap code
//
//-----------------------------------------------------------------------------
# include <stdio.h>
2019-01-26 14:21:20 +00:00
# include <array>
2016-03-01 15:47:10 +00:00
# include "doomdef.h"
# include "templates.h"
# include "g_level.h"
# include "st_stuff.h"
# include "p_local.h"
# include "p_lnspec.h"
# include "w_wad.h"
# include "a_sharedglobal.h"
# include "d_event.h"
# include "gi.h"
# include "p_setup.h"
# include "c_bind.h"
2016-09-20 07:11:13 +00:00
# include "serializer.h"
2016-03-01 15:47:10 +00:00
# include "r_renderer.h"
# include "r_sky.h"
# include "sbar.h"
# include "d_player.h"
# include "p_blockmap.h"
# include "m_cheat.h"
# include "c_dispatch.h"
# include "d_netinf.h"
// State.
# include "r_state.h"
# include "r_utility.h"
// Data.
# include "gstrings.h"
# include "am_map.h"
# include "po_man.h"
# include "a_keys.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-03-11 18:02:00 +00:00
# include "actorinlines.h"
2018-11-10 07:04:03 +00:00
# include "earcut.hpp"
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
//=============================================================================
//
// Global state
//
//=============================================================================
enum
{
AM_NUMMARKPOINTS = 10 ,
} ;
// C++ cannot do static const floats in a class, so these need to be global...
static const double PLAYERRADIUS = 16. ; // player radius for automap checking
static const double M_ZOOMIN = ( 1.02 ) ; // how much zoom-in per tic - goes to 2x in 1 second
static const double M_ZOOMOUT = ( 1 / 1.02 ) ; // how much zoom-out per tic - pulls out to 0.5x in 1 second
static FTextureID marknums [ AM_NUMMARKPOINTS ] ; // numbers used for marking by the automap
bool automapactive = false ;
//=============================================================================
//
// Types
//
//=============================================================================
struct fpoint_t
{
int x , y ;
} ;
struct fline_t
{
fpoint_t a , b ;
} ;
struct mpoint_t
{
double x , y ;
} ;
struct mline_t
{
mpoint_t a , b ;
} ;
struct islope_t
{
double slp , islp ;
} ;
2016-03-01 15:47:10 +00:00
//=============================================================================
//
// CVARs
//
//=============================================================================
2019-01-26 14:21:20 +00:00
CVAR ( Bool , am_textured , false , CVAR_ARCHIVE )
CVAR ( Int , am_showsubsector , - 1 , 0 ) ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
CUSTOM_CVAR ( Int , am_showalllines , - 1 , CVAR_NOINITCALL ) // This is a cheat so don't save it.
{
if ( currentUILevel & & currentUILevel - > automap )
currentUILevel - > automap - > UpdateShowAllLines ( ) ;
}
EXTERN_CVAR ( Bool , sv_cheats )
CUSTOM_CVAR ( Int , am_cheat , 0 , 0 )
{
// No automap cheat in net games when cheats are disabled!
if ( netgame & & ! sv_cheats & & self ! = 0 )
{
self = 0 ;
}
}
CVAR ( Int , am_rotate , 0 , CVAR_ARCHIVE ) ;
CVAR ( Int , am_overlay , 0 , CVAR_ARCHIVE ) ;
CVAR ( Bool , am_showsecrets , true , CVAR_ARCHIVE ) ;
CVAR ( Bool , am_showmonsters , true , CVAR_ARCHIVE ) ;
CVAR ( Bool , am_showitems , false , CVAR_ARCHIVE ) ;
CVAR ( Bool , am_showtime , true , CVAR_ARCHIVE ) ;
CVAR ( Bool , am_showtotaltime , false , CVAR_ARCHIVE ) ;
CVAR ( Int , am_colorset , 0 , CVAR_ARCHIVE ) ;
CVAR ( Bool , am_customcolors , true , CVAR_ARCHIVE ) ;
CVAR ( Int , am_map_secrets , 1 , CVAR_ARCHIVE ) ;
CVAR ( Int , am_drawmapback , 1 , CVAR_ARCHIVE ) ;
CVAR ( Bool , am_showkeys , true , CVAR_ARCHIVE ) ;
CVAR ( Int , am_showtriggerlines , 0 , CVAR_ARCHIVE ) ;
CVAR ( Int , am_showthingsprites , 0 , CVAR_ARCHIVE ) ;
CUSTOM_CVAR ( Int , am_emptyspacemargin , 0 , CVAR_ARCHIVE )
2017-12-09 15:38:34 +00:00
{
if ( self < 0 )
{
self = 0 ;
}
2017-12-14 14:17:55 +00:00
else if ( self > 90 )
2017-12-09 15:38:34 +00:00
{
2017-12-14 14:17:55 +00:00
self = 90 ;
2017-12-09 15:38:34 +00:00
}
2019-01-26 14:21:20 +00:00
if ( nullptr ! = StatusBar & & currentUILevel & & currentUILevel - > automap )
2017-12-23 13:48:28 +00:00
{
2019-01-26 14:21:20 +00:00
currentUILevel - > automap - > NewResolution ( ) ;
2017-12-23 13:48:28 +00:00
}
2017-12-09 15:38:34 +00:00
}
2019-01-26 14:21:20 +00:00
//=============================================================================
//
// map functions
//
//=============================================================================
CVAR ( Bool , am_followplayer , true , CVAR_ARCHIVE )
CVAR ( Bool , am_portaloverlay , true , CVAR_ARCHIVE )
CVAR ( Bool , am_showgrid , false , CVAR_ARCHIVE )
CVAR ( Float , am_zoomdir , 0 , CVAR_ARCHIVE )
CCMD ( am_togglefollow )
{
am_followplayer = ! am_followplayer ;
if ( currentUILevel & & currentUILevel - > automap )
currentUILevel - > automap - > ResetFollowLocation ( ) ;
Printf ( " %s \n " , GStrings ( am_followplayer ? " AMSTR_FOLLOWON " : " AMSTR_FOLLOWOFF " ) ) ;
}
CCMD ( am_togglegrid )
{
am_showgrid = ! am_showgrid ;
Printf ( " %s \n " , GStrings ( am_showgrid ? " AMSTR_GRIDON " : " AMSTR_GRIDOFF " ) ) ;
}
CCMD ( am_toggletexture )
{
am_textured = ! am_textured ;
Printf ( " %s \n " , GStrings ( am_textured ? " AMSTR_TEXON " : " AMSTR_TEXOFF " ) ) ;
}
CCMD ( am_setmark )
{
if ( currentUILevel & & currentUILevel - > automap )
{
int m = currentUILevel - > automap - > addMark ( ) ;
if ( m > = 0 )
{
Printf ( " %s %d \n " , GStrings ( " AMSTR_MARKEDSPOT " ) , m ) ;
}
}
}
CCMD ( am_clearmarks )
{
if ( currentUILevel & & currentUILevel - > automap & & currentUILevel - > automap - > clearMarks ( ) )
{
Printf ( " %s \n " , GStrings ( " AMSTR_MARKSCLEARED " ) ) ;
}
}
CCMD ( am_gobig )
{
if ( currentUILevel & & currentUILevel - > automap )
currentUILevel - > automap - > GoBig ( ) ;
}
CCMD ( togglemap )
{
if ( gameaction = = ga_nothing )
{
gameaction = ga_togglemap ;
}
}
CCMD ( am_zoom )
{
if ( argv . argc ( ) > = 2 )
{
am_zoomdir = ( float ) atof ( argv [ 1 ] ) ;
}
}
2016-03-01 15:47:10 +00:00
//=============================================================================
//
// Automap colors
//
//=============================================================================
CVAR ( Color , am_backcolor , 0x6c5440 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_yourcolor , 0xfce8d8 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_wallcolor , 0x2c1808 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_secretwallcolor , 0x000000 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_specialwallcolor , 0xffffff , CVAR_ARCHIVE ) ;
CVAR ( Color , am_tswallcolor , 0x888888 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_fdwallcolor , 0x887058 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_cdwallcolor , 0x4c3820 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_efwallcolor , 0x665555 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_thingcolor , 0xfcfcfc , CVAR_ARCHIVE ) ;
CVAR ( Color , am_gridcolor , 0x8b5a2b , CVAR_ARCHIVE ) ;
CVAR ( Color , am_xhaircolor , 0x808080 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_notseencolor , 0x6c6c6c , CVAR_ARCHIVE ) ;
CVAR ( Color , am_lockedcolor , 0x007800 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_intralevelcolor , 0x0000ff , CVAR_ARCHIVE ) ;
CVAR ( Color , am_interlevelcolor , 0xff0000 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_secretsectorcolor , 0xff00ff , CVAR_ARCHIVE ) ;
2018-03-10 15:36:43 +00:00
CVAR ( Color , am_unexploredsecretcolor , 0xff00ff , CVAR_ARCHIVE ) ;
2016-03-01 15:47:10 +00:00
CVAR ( Color , am_thingcolor_friend , 0xfcfcfc , CVAR_ARCHIVE ) ;
CVAR ( Color , am_thingcolor_monster , 0xfcfcfc , CVAR_ARCHIVE ) ;
CVAR ( Color , am_thingcolor_ncmonster , 0xfcfcfc , CVAR_ARCHIVE ) ;
CVAR ( Color , am_thingcolor_item , 0xfcfcfc , CVAR_ARCHIVE ) ;
CVAR ( Color , am_thingcolor_citem , 0xfcfcfc , CVAR_ARCHIVE ) ;
2016-03-13 11:33:58 +00:00
CVAR ( Color , am_portalcolor , 0x404040 , CVAR_ARCHIVE ) ;
2016-03-01 15:47:10 +00:00
CVAR ( Color , am_ovyourcolor , 0xfce8d8 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovwallcolor , 0x00ff00 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovsecretwallcolor , 0x008844 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovspecialwallcolor , 0xffffff , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovotherwallscolor , 0x008844 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovlockedcolor , 0x008844 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovefwallcolor , 0x008844 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovfdwallcolor , 0x008844 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovcdwallcolor , 0x008844 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovunseencolor , 0x00226e , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovtelecolor , 0xffff00 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovinterlevelcolor , 0xffff00 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovsecretsectorcolor , 0x00ffff , CVAR_ARCHIVE ) ;
2018-03-10 15:36:43 +00:00
CVAR ( Color , am_ovunexploredsecretcolor , 0x00ffff , CVAR_ARCHIVE ) ;
2016-03-01 15:47:10 +00:00
CVAR ( Color , am_ovthingcolor , 0xe88800 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovthingcolor_friend , 0xe88800 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovthingcolor_monster , 0xe88800 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovthingcolor_ncmonster , 0xe88800 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovthingcolor_item , 0xe88800 , CVAR_ARCHIVE ) ;
CVAR ( Color , am_ovthingcolor_citem , 0xe88800 , CVAR_ARCHIVE ) ;
2016-03-13 11:33:58 +00:00
CVAR ( Color , am_ovportalcolor , 0x004022 , CVAR_ARCHIVE ) ;
2016-03-01 15:47:10 +00:00
//=============================================================================
//
// internal representation of a single color
//
//=============================================================================
struct AMColor
{
int Index ;
2017-03-09 18:31:45 +00:00
uint32_t RGB ;
2016-03-01 15:47:10 +00:00
void FromCVar ( FColorCVar & cv )
{
Index = cv . GetIndex ( ) ;
2017-03-09 18:31:45 +00:00
RGB = uint32_t ( cv ) | MAKEARGB ( 255 , 0 , 0 , 0 ) ;
2016-03-01 15:47:10 +00:00
}
void FromRGB ( int r , int g , int b )
{
RGB = MAKEARGB ( 255 , r , g , b ) ;
Index = ColorMatcher . Pick ( r , g , b ) ;
}
void setInvalid ( )
{
Index = - 1 ;
RGB = - 1 ;
}
bool isValid ( ) const
{
return Index > - 1 ;
}
} ;
//=============================================================================
//
// a complete color set
//
//=============================================================================
static const char * ColorNames [ ] = {
" Background " ,
" YourColor " ,
" WallColor " ,
" TwoSidedWallColor " ,
" FloorDiffWallColor " ,
" CeilingDiffWallColor " ,
" ExtraFloorWallColor " ,
" ThingColor " ,
" ThingColor_Item " ,
" ThingColor_CountItem " ,
" ThingColor_Monster " ,
" ThingColor_NocountMonster " ,
" ThingColor_Friend " ,
" SpecialWallColor " ,
" SecretWallColor " ,
" GridColor " ,
" XHairColor " ,
" NotSeenColor " ,
" LockedColor " ,
" IntraTeleportColor " ,
" InterTeleportColor " ,
" SecretSectorColor " ,
2018-03-10 15:36:43 +00:00
" UnexploredSecretColor " ,
2016-03-13 11:33:58 +00:00
" PortalColor " ,
2016-03-01 15:47:10 +00:00
" AlmostBackgroundColor " ,
2019-01-26 14:21:20 +00:00
nullptr
2016-03-01 15:47:10 +00:00
} ;
struct AMColorset
{
enum
{
Background ,
YourColor ,
WallColor ,
TSWallColor ,
FDWallColor ,
CDWallColor ,
EFWallColor ,
ThingColor ,
ThingColor_Item ,
ThingColor_CountItem ,
ThingColor_Monster ,
ThingColor_NocountMonster ,
ThingColor_Friend ,
SpecialWallColor ,
SecretWallColor ,
GridColor ,
XHairColor ,
NotSeenColor ,
LockedColor ,
IntraTeleportColor ,
InterTeleportColor ,
SecretSectorColor ,
2018-03-10 15:36:43 +00:00
UnexploredSecretColor ,
2016-03-13 11:33:58 +00:00
PortalColor ,
2016-03-01 15:47:10 +00:00
AlmostBackgroundColor ,
AM_NUM_COLORS
} ;
AMColor c [ AM_NUM_COLORS ] ;
bool displayLocks ;
bool forcebackground ;
bool defined ; // only for mod specific colorsets: must be true to be usable
void initFromCVars ( FColorCVar * * values )
{
for ( int i = 0 ; i < AlmostBackgroundColor ; i + + )
{
c [ i ] . FromCVar ( * values [ i ] ) ;
}
2017-03-08 17:50:37 +00:00
uint32_t ba = * ( values [ 0 ] ) ;
2016-03-01 15:47:10 +00:00
int r = RPART ( ba ) - 16 ;
int g = GPART ( ba ) - 16 ;
int b = BPART ( ba ) - 16 ;
if ( r < 0 )
r + = 32 ;
if ( g < 0 )
g + = 32 ;
if ( b < 0 )
b + = 32 ;
c [ AlmostBackgroundColor ] . FromRGB ( r , g , b ) ;
displayLocks = true ;
forcebackground = false ;
}
void initFromColors ( const unsigned char * colors , bool showlocks )
{
for ( int i = 0 , j = 0 ; i < AM_NUM_COLORS ; i + + , j + = 3 )
{
if ( colors [ j ] = = 1 & & colors [ j + 1 ] = = 0 & & colors [ j + 2 ] = = 0 )
{
c [ i ] . setInvalid ( ) ;
}
else
{
c [ i ] . FromRGB ( colors [ j ] , colors [ j + 1 ] , colors [ j + 2 ] ) ;
}
}
displayLocks = showlocks ;
forcebackground = false ;
}
void setWhite ( )
{
c [ 0 ] . FromRGB ( 0 , 0 , 0 ) ;
for ( int i = 1 ; i < AM_NUM_COLORS ; i + + )
{
c [ i ] . FromRGB ( 255 , 255 , 255 ) ;
}
}
const AMColor & operator [ ] ( int index ) const
{
return c [ index ] ;
}
bool isValid ( int index ) const
{
return c [ index ] . isValid ( ) ;
}
} ;
2018-05-19 07:49:04 +00:00
//=============================================================================
//
// automap colors forced by linedef
//
//=============================================================================
static const int AUTOMAP_LINE_COLORS [ AMLS_COUNT ] =
{
- 1 , // AMLS_Default (unused)
AMColorset : : WallColor , // AMLS_OneSided,
AMColorset : : TSWallColor , // AMLS_TwoSided
AMColorset : : FDWallColor , // AMLS_FloorDiff
AMColorset : : CDWallColor , // AMLS_CeilingDiff
AMColorset : : EFWallColor , // AMLS_ExtraFloor
AMColorset : : SpecialWallColor , // AMLS_Special
AMColorset : : SecretWallColor , // AMLS_Secret
AMColorset : : NotSeenColor , // AMLS_NotSeen
AMColorset : : LockedColor , // AMLS_Locked
AMColorset : : IntraTeleportColor , // AMLS_IntraTeleport
AMColorset : : InterTeleportColor , // AMLS_InterTeleport
AMColorset : : UnexploredSecretColor , // AMLS_UnexploredSecret
AMColorset : : PortalColor , // AMLS_Portal
} ;
2016-03-01 15:47:10 +00:00
//=============================================================================
//
// predefined colorsets
//
//=============================================================================
static FColorCVar * cv_standard [ ] = {
& am_backcolor ,
& am_yourcolor ,
& am_wallcolor ,
& am_tswallcolor ,
& am_fdwallcolor ,
& am_cdwallcolor ,
& am_efwallcolor ,
& am_thingcolor ,
& am_thingcolor_item ,
& am_thingcolor_citem ,
& am_thingcolor_monster ,
& am_thingcolor_ncmonster ,
& am_thingcolor_friend ,
& am_specialwallcolor ,
& am_secretwallcolor ,
& am_gridcolor ,
& am_xhaircolor ,
& am_notseencolor ,
& am_lockedcolor ,
& am_intralevelcolor ,
& am_interlevelcolor ,
2016-03-13 11:33:58 +00:00
& am_secretsectorcolor ,
2018-03-10 15:36:43 +00:00
& am_unexploredsecretcolor ,
2016-03-13 11:33:58 +00:00
& am_portalcolor
2016-03-01 15:47:10 +00:00
} ;
static FColorCVar * cv_overlay [ ] = {
& am_backcolor , // this will not be used in overlay mode
& am_ovyourcolor ,
& am_ovwallcolor ,
& am_ovotherwallscolor ,
& am_ovfdwallcolor ,
& am_ovcdwallcolor ,
& am_ovefwallcolor ,
& am_ovthingcolor ,
& am_ovthingcolor_item ,
& am_ovthingcolor_citem ,
& am_ovthingcolor_monster ,
& am_ovthingcolor_ncmonster ,
& am_ovthingcolor_friend ,
& am_ovspecialwallcolor ,
& am_ovsecretwallcolor ,
& am_gridcolor , // this will not be used in overlay mode
& am_xhaircolor , // this will not be used in overlay mode
& am_ovunseencolor ,
& am_ovlockedcolor ,
& am_ovtelecolor ,
& am_ovinterlevelcolor ,
2016-03-13 11:33:58 +00:00
& am_ovsecretsectorcolor ,
2018-03-10 15:36:43 +00:00
& am_ovunexploredsecretcolor ,
2016-03-13 11:33:58 +00:00
& am_ovportalcolor
2016-03-01 15:47:10 +00:00
} ;
CCMD ( am_restorecolors )
{
for ( unsigned i = 0 ; i < countof ( cv_standard ) ; i + + )
{
cv_standard [ i ] - > ResetToDefault ( ) ;
}
for ( unsigned i = 0 ; i < countof ( cv_overlay ) ; i + + )
{
cv_overlay [ i ] - > ResetToDefault ( ) ;
}
}
# define NOT_USED 1,0,0 // use almost black as indicator for an unused color
static unsigned char DoomColors [ ] = {
0x00 , 0x00 , 0x00 , // background
0xff , 0xff , 0xff , // yourcolor
0xfc , 0x00 , 0x00 , // wallcolor
0x80 , 0x80 , 0x80 , // tswallcolor
0xbc , 0x78 , 0x48 , // fdwallcolor
0xfc , 0xfc , 0x00 , // cdwallcolor
0xbc , 0x78 , 0x48 , // efwallcolor
0x74 , 0xfc , 0x6c , // thingcolor
0x74 , 0xfc , 0x6c , // thingcolor_item
0x74 , 0xfc , 0x6c , // thingcolor_citem
0x74 , 0xfc , 0x6c , // thingcolor_monster
0x74 , 0xfc , 0x6c , // thingcolor_ncmonster
0x74 , 0xfc , 0x6c , // thingcolor_friend
NOT_USED , // specialwallcolor
NOT_USED , // secretwallcolor
0x4c , 0x4c , 0x4c , // gridcolor
0x80 , 0x80 , 0x80 , // xhaircolor
0x6c , 0x6c , 0x6c , // notseencolor
0xfc , 0xfc , 0x00 , // lockedcolor
NOT_USED , // intrateleport
NOT_USED , // interteleport
NOT_USED , // secretsector
2018-03-10 15:36:43 +00:00
NOT_USED , // unexploredsecretsector
2016-03-01 15:47:10 +00:00
0x10 , 0x10 , 0x10 , // almostbackground
2016-03-13 11:33:58 +00:00
0x40 , 0x40 , 0x40 // portal
2016-03-01 15:47:10 +00:00
} ;
static unsigned char StrifeColors [ ] = {
0x00 , 0x00 , 0x00 , // background
239 , 239 , 0 , // yourcolor
199 , 195 , 195 , // wallcolor
119 , 115 , 115 , // tswallcolor
55 , 59 , 91 , // fdwallcolor
119 , 115 , 115 , // cdwallcolor
55 , 59 , 91 , // efwallcolor
187 , 59 , 0 , // thingcolor
219 , 171 , 0 , // thingcolor_item
219 , 171 , 0 , // thingcolor_citem
0xfc , 0x00 , 0x00 , // thingcolor_monster
0xfc , 0x00 , 0x00 , // thingcolor_ncmonster
0xfc , 0x00 , 0x00 , // thingcolor_friend
NOT_USED , // specialwallcolor
NOT_USED , // secretwallcolor
0x4c , 0x4c , 0x4c , // gridcolor
0x80 , 0x80 , 0x80 , // xhaircolor
0x6c , 0x6c , 0x6c , // notseencolor
119 , 115 , 115 , // lockedcolor
NOT_USED , // intrateleport
NOT_USED , // interteleport
NOT_USED , // secretsector
2018-03-10 15:36:43 +00:00
NOT_USED , // unexploredsecretsector
2016-03-01 15:47:10 +00:00
0x10 , 0x10 , 0x10 , // almostbackground
2016-03-13 11:33:58 +00:00
0x40 , 0x40 , 0x40 // portal
2016-03-01 15:47:10 +00:00
} ;
static unsigned char RavenColors [ ] = {
0x6c , 0x54 , 0x40 , // background
0xff , 0xff , 0xff , // yourcolor
75 , 50 , 16 , // wallcolor
88 , 93 , 86 , // tswallcolor
208 , 176 , 133 , // fdwallcolor
103 , 59 , 31 , // cdwallcolor
208 , 176 , 133 , // efwallcolor
236 , 236 , 236 , // thingcolor
236 , 236 , 236 , // thingcolor_item
236 , 236 , 236 , // thingcolor_citem
236 , 236 , 236 , // thingcolor_monster
236 , 236 , 236 , // thingcolor_ncmonster
236 , 236 , 236 , // thingcolor_friend
NOT_USED , // specialwallcolor
NOT_USED , // secretwallcolor
75 , 50 , 16 , // gridcolor
0x00 , 0x00 , 0x00 , // xhaircolor
0x00 , 0x00 , 0x00 , // notseencolor
103 , 59 , 31 , // lockedcolor
NOT_USED , // intrateleport
NOT_USED , // interteleport
NOT_USED , // secretsector
2018-03-10 15:36:43 +00:00
NOT_USED , // unexploredsecretsector
2016-03-01 15:47:10 +00:00
0x10 , 0x10 , 0x10 , // almostbackground
2016-03-13 11:33:58 +00:00
0x50 , 0x50 , 0x50 // portal
2016-03-01 15:47:10 +00:00
} ;
# undef NOT_USED
static AMColorset AMColors ;
static AMColorset AMMod ;
static AMColorset AMModOverlay ;
2016-12-03 14:44:46 +00:00
void AM_ClearColorsets ( )
{
AMModOverlay . defined = false ;
AMMod . defined = false ;
}
2019-01-26 14:21:20 +00:00
2016-03-01 15:47:10 +00:00
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
static void AM_initColors ( bool overlayed )
{
if ( overlayed )
{
if ( am_customcolors & & AMModOverlay . defined )
{
AMColors = AMModOverlay ;
}
else
{
AMColors . initFromCVars ( cv_overlay ) ;
}
}
else if ( am_customcolors & & AMMod . defined )
{
AMColors = AMMod ;
}
else switch ( am_colorset )
{
default :
/* Use the custom colors in the am_* cvars */
AMColors . initFromCVars ( cv_standard ) ;
break ;
case 1 : // Doom
// Use colors corresponding to the original Doom's
AMColors . initFromColors ( DoomColors , false ) ;
break ;
case 2 : // Strife
// Use colors corresponding to the original Strife's
AMColors . initFromColors ( StrifeColors , false ) ;
break ;
case 3 : // Raven
// Use colors corresponding to the original Raven's
AMColors . initFromColors ( RavenColors , true ) ;
break ;
}
}
//=============================================================================
//
// custom color parser
//
//=============================================================================
2016-03-01 15:47:10 +00:00
void FMapInfoParser : : ParseAMColors ( bool overlay )
{
bool colorset = false ;
AMColorset & cset = overlay ? AMModOverlay : AMMod ;
cset . setWhite ( ) ;
cset . defined = true ;
sc . MustGetToken ( ' { ' ) ;
while ( sc . GetToken ( ) )
{
if ( sc . TokenType = = ' } ' ) return ;
sc . TokenMustBe ( TK_Identifier ) ;
FString nextKey = sc . String ;
sc . MustGetToken ( ' = ' ) ;
if ( nextKey . CompareNoCase ( " base " ) = = 0 )
{
if ( colorset ) sc . ScriptError ( " 'base' must be specified before the first color " ) ;
sc . MustGetToken ( TK_StringConst ) ;
if ( sc . Compare ( " doom " ) )
{
cset . initFromColors ( DoomColors , false ) ;
}
else if ( sc . Compare ( " raven " ) )
{
cset . initFromColors ( RavenColors , true ) ;
}
else if ( sc . Compare ( " strife " ) )
{
cset . initFromColors ( StrifeColors , false ) ;
}
else
{
sc . ScriptError ( " Unknown value for 'base'. Must be 'Doom', 'Strife' or 'Raven'. " ) ;
}
}
else if ( nextKey . CompareNoCase ( " showlocks " ) = = 0 )
{
if ( sc . CheckToken ( TK_False ) )
cset . displayLocks = false ;
else
{
sc . MustGetToken ( TK_True ) ;
cset . displayLocks = true ;
}
}
else
{
int i ;
2019-01-26 14:21:20 +00:00
for ( i = 0 ; ColorNames [ i ] ! = nullptr ; i + + )
2016-03-01 15:47:10 +00:00
{
if ( nextKey . CompareNoCase ( ColorNames [ i ] ) = = 0 )
{
sc . MustGetToken ( TK_StringConst ) ;
FString color = sc . String ;
FString colorName = V_GetColorStringByName ( color ) ;
if ( ! colorName . IsEmpty ( ) ) color = colorName ;
2019-01-26 14:21:20 +00:00
int colorval = V_GetColorFromString ( nullptr , color ) ;
2016-03-01 15:47:10 +00:00
cset . c [ i ] . FromRGB ( RPART ( colorval ) , GPART ( colorval ) , BPART ( colorval ) ) ;
colorset = true ;
break ;
}
}
2019-01-26 14:21:20 +00:00
if ( ColorNames [ i ] = = nullptr )
2016-03-01 15:47:10 +00:00
{
sc . ScriptError ( " Unknown key '%s' " , nextKey . GetChars ( ) ) ;
}
}
}
}
//=============================================================================
//
// The vector graphics for the automap.
// A line drawing of the player pointing right,
// starting from the middle.
//
//=============================================================================
static TArray < mline_t > MapArrow ;
static TArray < mline_t > CheatMapArrow ;
static TArray < mline_t > CheatKey ;
static TArray < mline_t > EasyKey ;
2019-01-26 14:21:20 +00:00
static std : : array < mline_t , 3 > thintriangle_guy = { {
{ - .5 , - .7 , 1 , 0 } ,
{ 1 , 0 , - .5 , .7 } ,
{ - .5 , .7 , - .5 , - .7 }
} } ;
2016-03-01 15:47:10 +00:00
2016-03-25 20:54:59 +00:00
//=============================================================================
//
// vector graphics
//
//=============================================================================
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
static void AM_ParseArrow ( TArray < mline_t > & Arrow , const char * lumpname )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
const int R = int ( ( 8 * PLAYERRADIUS ) / 7 ) ;
2016-03-01 15:47:10 +00:00
FScanner sc ;
int lump = Wads . CheckNumForFullName ( lumpname , true ) ;
if ( lump > = 0 )
{
sc . OpenLumpNum ( lump ) ;
sc . SetCMode ( true ) ;
while ( sc . GetToken ( ) )
{
mline_t line ;
sc . TokenMustBe ( ' ( ' ) ;
sc . MustGetFloat ( ) ;
2016-03-25 20:54:59 +00:00
line . a . x = sc . Float * R ;
2016-03-01 15:47:10 +00:00
sc . MustGetToken ( ' , ' ) ;
sc . MustGetFloat ( ) ;
2016-03-25 20:54:59 +00:00
line . a . y = sc . Float * R ;
2016-03-01 15:47:10 +00:00
sc . MustGetToken ( ' ) ' ) ;
sc . MustGetToken ( ' , ' ) ;
sc . MustGetToken ( ' ( ' ) ;
sc . MustGetFloat ( ) ;
2016-03-25 20:54:59 +00:00
line . b . x = sc . Float * R ;
2016-03-01 15:47:10 +00:00
sc . MustGetToken ( ' , ' ) ;
sc . MustGetFloat ( ) ;
2016-03-25 20:54:59 +00:00
line . b . y = sc . Float * R ;
2016-03-01 15:47:10 +00:00
sc . MustGetToken ( ' ) ' ) ;
Arrow . Push ( line ) ;
}
}
}
2019-01-26 14:21:20 +00:00
void AM_StaticInit ( )
{
MapArrow . Clear ( ) ;
CheatMapArrow . Clear ( ) ;
CheatKey . Clear ( ) ;
EasyKey . Clear ( ) ;
if ( gameinfo . mMapArrow . IsNotEmpty ( ) ) AM_ParseArrow ( MapArrow , gameinfo . mMapArrow ) ;
if ( gameinfo . mCheatMapArrow . IsNotEmpty ( ) ) AM_ParseArrow ( CheatMapArrow , gameinfo . mCheatMapArrow ) ;
AM_ParseArrow ( CheatKey , gameinfo . mCheatKey ) ;
AM_ParseArrow ( EasyKey , gameinfo . mEasyKey ) ;
if ( MapArrow . Size ( ) = = 0 ) I_FatalError ( " No automap arrow defined " ) ;
char namebuf [ 9 ] ;
for ( int i = 0 ; i < AM_NUMMARKPOINTS ; i + + )
{
mysnprintf ( namebuf , countof ( namebuf ) , " AMMNUM%d " , i ) ;
marknums [ i ] = TexMan . CheckForTexture ( namebuf , ETextureType : : MiscPatch ) ;
}
}
//=============================================================================
//
// the actual automap class definition
//
//=============================================================================
IMPLEMENT_CLASS ( DAutomapBase , true , false ) ;
class DAutomap : public DAutomapBase
{
DECLARE_CLASS ( DAutomap , DAutomapBase )
enum
{
F_PANINC = 140 / TICRATE , // how much the automap moves window per tic in frame-buffer coordinates moves 140 pixels at 320x200 in 1 second
} ;
//FLevelLocals *Level;
// scale on entry
// used by MTOF to scale from map-to-frame-buffer coords
double scale_mtof = .2 ;
// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
double scale_ftom ;
int bigstate ;
int MapPortalGroup ;
// Disable the ML_DONTDRAW line flag if x% of all lines in a map are flagged with it
// (To counter annoying mappers who think they are smart by making the automap unusable)
bool am_showallenabled ;
// location of window on screen
int f_x ;
int f_y ;
// size of window on screen
int f_w ;
int f_h ;
int amclock ;
mpoint_t m_paninc ; // how far the window pans each tic (map coords)
double mtof_zoommul ; // how far the window zooms in each tic (map coords)
double m_x , m_y ; // LL x,y where the window is on the map (map coords)
double m_x2 , m_y2 ; // UR x,y where the window is on the map (map coords)
//
// width/height of window on map (map coords)
//
double m_w ;
double m_h ;
// based on level size
double min_x , min_y , max_x , max_y ;
double max_w ; // max_x-min_x,
double max_h ; // max_y-min_y
// based on player size
double min_w ;
double min_h ;
double min_scale_mtof ; // used to tell when to stop zooming out
double max_scale_mtof ; // used to tell when to stop zooming in
// old stuff for recovery later
double old_m_w , old_m_h ;
double old_m_x , old_m_y ;
// old location used by the Follower routine
mpoint_t f_oldloc ;
mpoint_t markpoints [ AM_NUMMARKPOINTS ] ; // where the points are
int markpointnum = 0 ; // next point to be assigned
FTextureID mapback ; // the automap background
double mapystart = 0 ; // y-value for the start of the map bitmap...used in the parallax stuff.
double mapxstart = 0 ; //x-value for the bitmap.
TArray < FVector2 > points ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
// translates between frame-buffer and map distances
double FTOM ( double x )
{
return x * scale_ftom ;
}
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
double MTOF ( double x )
{
return x * scale_mtof ;
}
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
// translates between frame-buffer and map coordinates
int CXMTOF ( double x )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
return int ( MTOF ( ( x ) - m_x ) /* - f_x*/ ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
int CYMTOF ( double y )
{
return int ( f_h - MTOF ( ( y ) - m_y ) /* + f_y*/ ) ;
}
void calcMinMaxMtoF ( ) ;
void DrawMarker ( FTexture * tex , double x , double y , int yadjust ,
INTBOOL flip , double xscale , double yscale , int translation , double alpha , uint32_t fillcolor , FRenderStyle renderstyle ) ;
void rotatePoint ( double * x , double * y ) ;
void rotate ( double * x , double * y , DAngle an ) ;
void doFollowPlayer ( ) ;
void saveScaleAndLoc ( ) ;
void restoreScaleAndLoc ( ) ;
void minOutWindowScale ( ) ;
void activateNewScale ( ) ;
void findMinMaxBoundaries ( ) ;
void ClipRotatedExtents ( double pivotx , double pivoty ) ;
void ScrollParchment ( double dmapx , double dmapy ) ;
void changeWindowLoc ( ) ;
void maxOutWindowScale ( ) ;
void changeWindowScale ( ) ;
void clearFB ( const AMColor & color ) ;
bool clipMline ( mline_t * ml , fline_t * fl ) ;
void drawMline ( mline_t * ml , const AMColor & color ) ;
void drawMline ( mline_t * ml , int colorindex ) ;
void drawGrid ( int color ) ;
void drawSubsectors ( ) ;
void drawSeg ( seg_t * seg , const AMColor & color ) ;
void drawPolySeg ( FPolySeg * seg , const AMColor & color ) ;
void showSS ( ) ;
void drawWalls ( bool allmap ) ;
void drawLineCharacter ( const mline_t * lineguy , size_t lineguylines , double scale , DAngle angle , const AMColor & color , double x , double y ) ;
void drawPlayers ( ) ;
void drawKeys ( ) ;
void drawThings ( ) ;
void drawMarks ( ) ;
void drawAuthorMarkers ( ) ;
void drawCrosshair ( const AMColor & color ) ;
public :
bool Responder ( event_t * ev , bool last ) override ;
void Ticker ( void ) override ;
void Drawer ( int bottom ) override ;
void NewResolution ( ) override ;
void LevelInit ( ) override ;
void UpdateShowAllLines ( ) override ;
void Serialize ( FSerializer & arc ) override ;
void GoBig ( ) override ;
void ResetFollowLocation ( ) override ;
int addMark ( ) override ;
bool clearMarks ( ) override ;
DVector2 GetPosition ( ) override ;
void startDisplay ( ) override ;
} ;
IMPLEMENT_CLASS ( DAutomap , false , false )
//=============================================================================
//
//
//
//=============================================================================
2016-03-01 15:47:10 +00:00
//=============================================================================
//
// called by the coordinate drawer
//
//=============================================================================
2019-01-26 14:21:20 +00:00
DVector2 DAutomap : : GetPosition ( )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
return DVector2 ( ( m_x + m_w / 2 ) , ( m_y + m_h / 2 ) ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : activateNewScale ( )
2016-03-01 15:47:10 +00:00
{
m_x + = m_w / 2 ;
m_y + = m_h / 2 ;
m_w = FTOM ( f_w ) ;
m_h = FTOM ( f_h ) ;
m_x - = m_w / 2 ;
m_y - = m_h / 2 ;
m_x2 = m_x + m_w ;
m_y2 = m_y + m_h ;
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : saveScaleAndLoc ( )
2016-03-01 15:47:10 +00:00
{
old_m_x = m_x ;
old_m_y = m_y ;
old_m_w = m_w ;
old_m_h = m_h ;
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : restoreScaleAndLoc ( )
2016-03-01 15:47:10 +00:00
{
m_w = old_m_w ;
m_h = old_m_h ;
if ( ! am_followplayer )
{
m_x = old_m_x ;
m_y = old_m_y ;
}
else
{
2016-03-25 20:54:59 +00:00
m_x = players [ consoleplayer ] . camera - > X ( ) - m_w / 2 ;
m_y = players [ consoleplayer ] . camera - > Y ( ) - m_h / 2 ;
2016-03-01 15:47:10 +00:00
}
m_x2 = m_x + m_w ;
m_y2 = m_y + m_h ;
// Change the scaling multipliers
2016-03-25 20:54:59 +00:00
scale_mtof = f_w / m_w ;
scale_ftom = 1. / scale_mtof ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// adds a marker at the current location
//
//=============================================================================
2019-01-26 14:21:20 +00:00
int DAutomap : : addMark ( )
2016-03-01 15:47:10 +00:00
{
if ( marknums [ 0 ] . isValid ( ) )
{
2019-01-26 14:21:20 +00:00
auto m = markpointnum ;
2016-03-01 15:47:10 +00:00
markpoints [ markpointnum ] . x = m_x + m_w / 2 ;
markpoints [ markpointnum ] . y = m_y + m_h / 2 ;
markpointnum = ( markpointnum + 1 ) % AM_NUMMARKPOINTS ;
2019-01-26 14:21:20 +00:00
return m ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
return - 1 ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// Determines bounding box of all vertices,
// sets global variables controlling zoom range.
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : findMinMaxBoundaries ( )
2016-03-01 15:47:10 +00:00
{
2016-03-25 23:34:56 +00:00
min_x = min_y = FLT_MAX ;
2016-03-01 15:47:10 +00:00
max_x = max_y = FIXED_MIN ;
2019-01-26 14:21:20 +00:00
for ( auto & vert : Level - > vertexes )
2016-03-01 15:47:10 +00:00
{
2017-01-08 23:46:16 +00:00
if ( vert . fX ( ) < min_x )
min_x = vert . fX ( ) ;
else if ( vert . fX ( ) > max_x )
max_x = vert . fX ( ) ;
2016-03-01 15:47:10 +00:00
2017-01-08 23:46:16 +00:00
if ( vert . fY ( ) < min_y )
min_y = vert . fY ( ) ;
else if ( vert . fY ( ) > max_y )
max_y = vert . fY ( ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
max_w = max_x - min_x ;
max_h = max_y - min_y ;
2016-03-01 15:47:10 +00:00
min_w = 2 * PLAYERRADIUS ; // const? never changed?
min_h = 2 * PLAYERRADIUS ;
2019-01-26 14:21:20 +00:00
calcMinMaxMtoF ( ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : calcMinMaxMtoF ( )
2016-03-01 15:47:10 +00:00
{
2017-12-09 15:38:34 +00:00
const double safe_frame = 1.0 - am_emptyspacemargin / 100.0 ;
double a = safe_frame * ( SCREENWIDTH / max_w ) ;
double b = safe_frame * ( StatusBar - > GetTopOfStatusbar ( ) / max_h ) ;
2016-03-01 15:47:10 +00:00
min_scale_mtof = a < b ? a : b ;
2016-03-25 20:54:59 +00:00
max_scale_mtof = SCREENHEIGHT / ( 2 * PLAYERRADIUS ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : ClipRotatedExtents ( double pivotx , double pivoty )
2016-03-01 15:47:10 +00:00
{
if ( am_rotate = = 0 | | ( am_rotate = = 2 & & ! viewactive ) )
{
if ( m_x + m_w / 2 > max_x )
m_x = max_x - m_w / 2 ;
else if ( m_x + m_w / 2 < min_x )
m_x = min_x - m_w / 2 ;
if ( m_y + m_h / 2 > max_y )
m_y = max_y - m_h / 2 ;
else if ( m_y + m_h / 2 < min_y )
m_y = min_y - m_h / 2 ;
}
m_x2 = m_x + m_w ;
m_y2 = m_y + m_h ;
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : ScrollParchment ( double dmapx , double dmapy )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
mapxstart = mapxstart - dmapx * scale_mtof ;
mapystart = mapystart - dmapy * scale_mtof ;
2016-03-01 15:47:10 +00:00
2016-03-30 22:41:21 +00:00
mapxstart = clamp ( mapxstart , - 40000. , 40000. ) ;
2016-04-17 08:19:56 +00:00
mapystart = clamp ( mapystart , - 40000. , 40000. ) ;
2016-03-30 22:41:21 +00:00
2016-03-01 15:47:10 +00:00
if ( mapback . isValid ( ) )
{
2018-12-07 02:01:40 +00:00
FTexture * backtex = TexMan . GetTexture ( mapback ) ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
if ( backtex ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2018-12-06 00:11:04 +00:00
int pwidth = backtex - > GetDisplayWidth ( ) ;
int pheight = backtex - > GetDisplayHeight ( ) ;
2016-03-01 15:47:10 +00:00
while ( mapxstart > 0 )
mapxstart - = pwidth ;
while ( mapxstart < = - pwidth )
mapxstart + = pwidth ;
while ( mapystart > 0 )
mapystart - = pheight ;
while ( mapystart < = - pheight )
mapystart + = pheight ;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : changeWindowLoc ( )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
if ( m_paninc . x | | m_paninc . y )
2016-03-01 15:47:10 +00:00
{
am_followplayer = false ;
2016-03-25 23:34:56 +00:00
f_oldloc . x = FLT_MAX ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
double oldmx = m_x , oldmy = m_y ;
double incx , incy , oincx , oincy ;
2016-03-01 15:47:10 +00:00
incx = m_paninc . x ;
incy = m_paninc . y ;
2016-03-25 20:54:59 +00:00
oincx = incx = m_paninc . x * SCREENWIDTH / 320 ;
oincy = incy = m_paninc . y * SCREENHEIGHT / 200 ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotate ( & incx , & incy , players [ consoleplayer ] . camera - > Angles . Yaw - 90. ) ;
2016-03-01 15:47:10 +00:00
}
m_x + = incx ;
m_y + = incy ;
2019-01-26 14:21:20 +00:00
ClipRotatedExtents ( oldmx + m_w / 2 , oldmy + m_h / 2 ) ;
ScrollParchment ( m_x ! = oldmx ? oincx : 0 , m_y ! = oldmy ? - oincy : 0 ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : startDisplay ( )
2016-03-01 15:47:10 +00:00
{
int pnum ;
2016-03-25 23:34:56 +00:00
f_oldloc . x = FLT_MAX ;
2016-03-01 15:47:10 +00:00
amclock = 0 ;
m_paninc . x = m_paninc . y = 0 ;
2016-03-25 20:54:59 +00:00
mtof_zoommul = 1. ;
2016-03-01 15:47:10 +00:00
m_w = FTOM ( SCREENWIDTH ) ;
m_h = FTOM ( SCREENHEIGHT ) ;
// find player to center on initially
if ( ! playeringame [ pnum = consoleplayer ] )
for ( pnum = 0 ; pnum < MAXPLAYERS ; pnum + + )
if ( playeringame [ pnum ] )
break ;
assert ( pnum > = 0 & & pnum < MAXPLAYERS ) ;
2016-03-25 20:54:59 +00:00
m_x = players [ pnum ] . camera - > X ( ) - m_w / 2 ;
m_y = players [ pnum ] . camera - > Y ( ) - m_h / 2 ;
2019-01-26 14:21:20 +00:00
changeWindowLoc ( ) ;
2016-03-01 15:47:10 +00:00
// for saving & restoring
old_m_x = m_x ;
old_m_y = m_y ;
old_m_w = m_w ;
old_m_h = m_h ;
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
bool DAutomap : : clearMarks ( )
2016-03-01 15:47:10 +00:00
{
for ( int i = AM_NUMMARKPOINTS - 1 ; i > = 0 ; i - - )
markpoints [ i ] . x = - 1 ; // means empty
markpointnum = 0 ;
return marknums [ 0 ] . isValid ( ) ;
}
//=============================================================================
//
// called right after the level has been loaded
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : LevelInit ( )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
if ( Level - > info - > MapBackground . Len ( ) = = 0 )
2016-03-01 15:47:10 +00:00
{
2018-03-25 18:26:16 +00:00
mapback = TexMan . CheckForTexture ( " AUTOPAGE " , ETextureType : : MiscPatch ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2019-01-26 14:21:20 +00:00
mapback = TexMan . CheckForTexture ( Level - > info - > MapBackground , ETextureType : : MiscPatch ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
clearMarks ( ) ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
findMinMaxBoundaries ( ) ;
2016-03-25 20:54:59 +00:00
scale_mtof = min_scale_mtof / 0.7 ;
2016-03-01 15:47:10 +00:00
if ( scale_mtof > max_scale_mtof )
scale_mtof = min_scale_mtof ;
2016-03-25 20:54:59 +00:00
scale_ftom = 1 / scale_mtof ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
UpdateShowAllLines ( ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// set the window scale to the maximum size
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : minOutWindowScale ( )
2016-03-01 15:47:10 +00:00
{
scale_mtof = min_scale_mtof ;
2016-03-25 20:54:59 +00:00
scale_ftom = 1 / scale_mtof ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// set the window scale to the minimum size
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : maxOutWindowScale ( )
2016-03-01 15:47:10 +00:00
{
scale_mtof = max_scale_mtof ;
2016-03-25 20:54:59 +00:00
scale_ftom = 1 / scale_mtof ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// Called right after the resolution has changed
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : NewResolution ( )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
double oldmin = min_scale_mtof ;
2016-03-01 15:47:10 +00:00
if ( oldmin = = 0 )
{
return ; // [SP] Not in a game, exit!
}
2019-01-26 14:21:20 +00:00
calcMinMaxMtoF ( ) ;
2016-03-25 20:54:59 +00:00
scale_mtof = scale_mtof * min_scale_mtof / oldmin ;
scale_ftom = 1 / scale_mtof ;
2016-03-01 15:47:10 +00:00
if ( scale_mtof < min_scale_mtof )
2019-01-26 14:21:20 +00:00
minOutWindowScale ( ) ;
2016-03-01 15:47:10 +00:00
else if ( scale_mtof > max_scale_mtof )
2019-01-26 14:21:20 +00:00
maxOutWindowScale ( ) ;
2016-03-01 15:47:10 +00:00
f_w = screen - > GetWidth ( ) ;
2017-03-30 16:51:24 +00:00
f_h = StatusBar - > GetTopOfStatusbar ( ) ;
2019-01-26 14:21:20 +00:00
activateNewScale ( ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// Handle events (user inputs) in automap mode
//
//=============================================================================
2019-01-26 14:21:20 +00:00
bool DAutomap : : Responder ( event_t * ev , bool last )
2016-03-01 15:47:10 +00:00
{
if ( automapactive & & ( ev - > type = = EV_KeyDown | | ev - > type = = EV_KeyUp ) )
{
if ( am_followplayer )
{
// check for am_pan* and ignore in follow mode
const char * defbind = AutomapBindings . GetBind ( ev - > data1 ) ;
if ( ! strnicmp ( defbind , " +am_pan " , 7 ) ) return false ;
}
2019-01-26 14:21:20 +00:00
bool res = C_DoKey ( ev , & AutomapBindings , nullptr ) ;
2016-03-01 15:47:10 +00:00
if ( res & & ev - > type = = EV_KeyUp & & ! last )
{
// If this is a release event we also need to check if it released a button in the main Bindings
// so that that button does not get stuck.
const char * defbind = Bindings . GetBind ( ev - > data1 ) ;
return ( defbind [ 0 ] ! = ' + ' ) ; // Let G_Responder handle button releases
}
return res ;
}
return false ;
}
//=============================================================================
//
// Zooming
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : changeWindowScale ( )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
double mtof_zoommul ;
2016-03-01 15:47:10 +00:00
if ( am_zoomdir > 0 )
{
2016-03-25 20:54:59 +00:00
mtof_zoommul = M_ZOOMIN * am_zoomdir ;
2016-03-01 15:47:10 +00:00
}
else if ( am_zoomdir < 0 )
{
2016-03-25 20:54:59 +00:00
mtof_zoommul = M_ZOOMOUT / - am_zoomdir ;
2016-03-01 15:47:10 +00:00
}
else if ( Button_AM_ZoomIn . bDown )
{
2016-03-25 20:54:59 +00:00
mtof_zoommul = M_ZOOMIN ;
2016-03-01 15:47:10 +00:00
}
else if ( Button_AM_ZoomOut . bDown )
{
2016-03-25 20:54:59 +00:00
mtof_zoommul = M_ZOOMOUT ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-25 20:54:59 +00:00
mtof_zoommul = 1 ;
2016-03-01 15:47:10 +00:00
}
am_zoomdir = 0 ;
// Change the scaling multipliers
2016-03-25 20:54:59 +00:00
scale_mtof = scale_mtof * mtof_zoommul ;
scale_ftom = 1 / scale_mtof ;
2016-03-01 15:47:10 +00:00
if ( scale_mtof < min_scale_mtof )
2019-01-26 14:21:20 +00:00
minOutWindowScale ( ) ;
2016-03-01 15:47:10 +00:00
else if ( scale_mtof > max_scale_mtof )
2019-01-26 14:21:20 +00:00
maxOutWindowScale ( ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : doFollowPlayer ( )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
double sx , sy ;
2017-05-14 11:12:39 +00:00
auto cam = players [ consoleplayer ] . camera ;
if ( cam ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2017-05-14 11:12:39 +00:00
double delta = cam - > player ? cam - > player - > viewz - cam - > Z ( ) : cam - > GetCameraHeight ( ) ;
DVector3 ampos = cam - > GetPortalTransition ( delta ) ;
2016-03-01 15:47:10 +00:00
2017-05-14 11:12:39 +00:00
if ( f_oldloc . x ! = ampos . X | | f_oldloc . y ! = ampos . Y )
2016-03-01 15:47:10 +00:00
{
2017-05-14 11:12:39 +00:00
m_x = ampos . X - m_w / 2 ;
m_y = ampos . Y - m_h / 2 ;
m_x2 = m_x + m_w ;
m_y2 = m_y + m_h ;
// do the parallax parchment scrolling.
sx = ( ampos . X - f_oldloc . x ) ;
sy = ( f_oldloc . y - ampos . Y ) ;
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotate ( & sx , & sy , cam - > Angles . Yaw - 90 ) ;
2017-05-14 11:12:39 +00:00
}
2019-01-26 14:21:20 +00:00
ScrollParchment ( sx , sy ) ;
2016-03-01 15:47:10 +00:00
2017-05-14 11:12:39 +00:00
f_oldloc . x = ampos . X ;
f_oldloc . y = ampos . Y ;
}
2016-03-01 15:47:10 +00:00
}
}
//=============================================================================
//
// Updates on Game Tick
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : Ticker ( )
2016-03-01 15:47:10 +00:00
{
if ( ! automapactive )
return ;
amclock + + ;
if ( am_followplayer )
{
2019-01-26 14:21:20 +00:00
doFollowPlayer ( ) ;
2016-03-01 15:47:10 +00:00
}
else
{
m_paninc . x = m_paninc . y = 0 ;
if ( Button_AM_PanLeft . bDown ) m_paninc . x - = FTOM ( F_PANINC ) ;
if ( Button_AM_PanRight . bDown ) m_paninc . x + = FTOM ( F_PANINC ) ;
if ( Button_AM_PanUp . bDown ) m_paninc . y + = FTOM ( F_PANINC ) ;
if ( Button_AM_PanDown . bDown ) m_paninc . y - = FTOM ( F_PANINC ) ;
}
// Change the zoom if necessary
if ( Button_AM_ZoomIn . bDown | | Button_AM_ZoomOut . bDown | | am_zoomdir ! = 0 )
2019-01-26 14:21:20 +00:00
changeWindowScale ( ) ;
2016-03-01 15:47:10 +00:00
// Change x,y location
//if (m_paninc.x || m_paninc.y)
2019-01-26 14:21:20 +00:00
changeWindowLoc ( ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// Clear automap frame buffer.
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : clearFB ( const AMColor & color )
2016-03-01 15:47:10 +00:00
{
bool drawback = mapback . isValid ( ) & & am_drawmapback ! = 0 ;
if ( am_drawmapback = = 2 )
{
// only draw background when using a mod defined custom color set or Raven colors, if am_drawmapback is 2.
if ( ! am_customcolors | | ! AMMod . defined )
{
drawback & = ( am_colorset = = 3 ) ;
}
}
if ( ! drawback )
{
screen - > Clear ( 0 , 0 , f_w , f_h , color . Index , color . RGB ) ;
}
else
{
2018-12-07 02:01:40 +00:00
FTexture * backtex = TexMan . GetTexture ( mapback ) ;
2019-01-26 14:21:20 +00:00
if ( backtex ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2018-12-06 00:11:04 +00:00
int pwidth = backtex - > GetDisplayWidth ( ) ;
int pheight = backtex - > GetDisplayHeight ( ) ;
2016-03-01 15:47:10 +00:00
int x , y ;
//blit the automap background to the screen.
2016-03-25 20:54:59 +00:00
for ( y = int ( mapystart ) ; y < f_h ; y + = pheight )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
for ( x = int ( mapxstart ) ; x < f_w ; x + = pwidth )
2016-03-01 15:47:10 +00:00
{
screen - > DrawTexture ( backtex , x , y , DTA_ClipBottom , f_h , DTA_TopOffset , 0 , DTA_LeftOffset , 0 , TAG_DONE ) ;
}
}
}
}
}
//=============================================================================
//
// Automap clipping of lines.
//
// Based on Cohen-Sutherland clipping algorithm but with a slightly
// faster reject and precalculated slopes. If the speed is needed,
// use a hash algorithm to handle the common cases.
//
//=============================================================================
2019-01-26 14:21:20 +00:00
bool DAutomap : : clipMline ( mline_t * ml , fline_t * fl )
2016-03-01 15:47:10 +00:00
{
enum {
LEFT = 1 ,
RIGHT = 2 ,
BOTTOM = 4 ,
TOP = 8
} ;
int outcode1 = 0 ;
int outcode2 = 0 ;
int outside ;
fpoint_t tmp = { 0 , 0 } ;
int dx ;
int dy ;
2019-01-26 14:21:20 +00:00
auto DOOUTCODE = [ this ] ( int & oc , double mx , double my )
{
oc = 0 ;
if ( my < 0 ) oc | = TOP ;
else if ( my > = f_h ) oc | = BOTTOM ;
if ( mx < 0 ) oc | = LEFT ;
else if ( mx > = f_w ) oc | = RIGHT ;
} ;
2016-03-01 15:47:10 +00:00
// do trivial rejects and outcodes
if ( ml - > a . y > m_y2 )
outcode1 = TOP ;
else if ( ml - > a . y < m_y )
outcode1 = BOTTOM ;
if ( ml - > b . y > m_y2 )
outcode2 = TOP ;
else if ( ml - > b . y < m_y )
outcode2 = BOTTOM ;
if ( outcode1 & outcode2 )
return false ; // trivially outside
if ( ml - > a . x < m_x )
outcode1 | = LEFT ;
else if ( ml - > a . x > m_x2 )
outcode1 | = RIGHT ;
if ( ml - > b . x < m_x )
outcode2 | = LEFT ;
else if ( ml - > b . x > m_x2 )
outcode2 | = RIGHT ;
if ( outcode1 & outcode2 )
return false ; // trivially outside
// transform to frame-buffer coordinates.
fl - > a . x = CXMTOF ( ml - > a . x ) ;
fl - > a . y = CYMTOF ( ml - > a . y ) ;
fl - > b . x = CXMTOF ( ml - > b . x ) ;
fl - > b . y = CYMTOF ( ml - > b . y ) ;
DOOUTCODE ( outcode1 , fl - > a . x , fl - > a . y ) ;
DOOUTCODE ( outcode2 , fl - > b . x , fl - > b . y ) ;
if ( outcode1 & outcode2 )
return false ;
while ( outcode1 | outcode2 ) {
// may be partially inside box
// find an outside point
if ( outcode1 )
outside = outcode1 ;
else
outside = outcode2 ;
// clip to each side
if ( outside & TOP )
{
dy = fl - > a . y - fl - > b . y ;
dx = fl - > b . x - fl - > a . x ;
tmp . x = fl - > a . x + Scale ( dx , fl - > a . y , dy ) ;
tmp . y = 0 ;
}
else if ( outside & BOTTOM )
{
dy = fl - > a . y - fl - > b . y ;
dx = fl - > b . x - fl - > a . x ;
tmp . x = fl - > a . x + Scale ( dx , fl - > a . y - f_h , dy ) ;
tmp . y = f_h - 1 ;
}
else if ( outside & RIGHT )
{
dy = fl - > b . y - fl - > a . y ;
dx = fl - > b . x - fl - > a . x ;
tmp . y = fl - > a . y + Scale ( dy , f_w - 1 - fl - > a . x , dx ) ;
tmp . x = f_w - 1 ;
}
else if ( outside & LEFT )
{
dy = fl - > b . y - fl - > a . y ;
dx = fl - > b . x - fl - > a . x ;
tmp . y = fl - > a . y + Scale ( dy , - fl - > a . x , dx ) ;
tmp . x = 0 ;
}
if ( outside = = outcode1 )
{
fl - > a = tmp ;
DOOUTCODE ( outcode1 , fl - > a . x , fl - > a . y ) ;
}
else
{
fl - > b = tmp ;
DOOUTCODE ( outcode2 , fl - > b . x , fl - > b . y ) ;
}
if ( outcode1 & outcode2 )
return false ; // trivially outside
}
return true ;
}
//=============================================================================
//
// Clip lines, draw visible parts of lines.
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawMline ( mline_t * ml , const AMColor & color )
2016-03-01 15:47:10 +00:00
{
fline_t fl ;
2019-01-26 14:21:20 +00:00
if ( clipMline ( ml , & fl ) )
2016-03-01 15:47:10 +00:00
{
screen - > DrawLine ( f_x + fl . a . x , f_y + fl . a . y , f_x + fl . b . x , f_y + fl . b . y , color . Index , color . RGB ) ;
}
}
2019-01-26 14:21:20 +00:00
void DAutomap : : drawMline ( mline_t * ml , int colorindex )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
drawMline ( ml , AMColors [ colorindex ] ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// Draws flat (floor/ceiling tile) aligned grid lines.
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawGrid ( int color )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
double x , y ;
double start , end ;
2016-03-01 15:47:10 +00:00
mline_t ml ;
2016-03-25 20:54:59 +00:00
double minlen , extx , exty ;
double minx , miny ;
2019-01-26 14:21:20 +00:00
auto bmaporgx = Level - > blockmap . bmaporgx ;
auto bmaporgy = Level - > blockmap . bmaporgy ;
2016-03-01 15:47:10 +00:00
// [RH] Calculate a minimum for how long the grid lines should be so that
// they cover the screen at any rotation.
2016-03-25 20:54:59 +00:00
minlen = sqrt ( m_w * m_w + m_h * m_h ) ;
2016-03-01 15:47:10 +00:00
extx = ( minlen - m_w ) / 2 ;
exty = ( minlen - m_h ) / 2 ;
minx = m_x ;
miny = m_y ;
// Figure out start of vertical gridlines
start = minx - extx ;
2017-03-17 13:24:21 +00:00
start = ceil ( ( start - bmaporgx ) / FBlockmap : : MAPBLOCKUNITS ) * FBlockmap : : MAPBLOCKUNITS + bmaporgx ;
2016-03-25 20:54:59 +00:00
2016-03-01 15:47:10 +00:00
end = minx + minlen - extx ;
// draw vertical gridlines
2017-03-17 13:24:21 +00:00
for ( x = start ; x < end ; x + = FBlockmap : : MAPBLOCKUNITS )
2016-03-01 15:47:10 +00:00
{
ml . a . x = x ;
ml . b . x = x ;
ml . a . y = miny - exty ;
ml . b . y = ml . a . y + minlen ;
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & ml . a . x , & ml . a . y ) ;
rotatePoint ( & ml . b . x , & ml . b . y ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
drawMline ( & ml , color ) ;
2016-03-01 15:47:10 +00:00
}
// Figure out start of horizontal gridlines
start = miny - exty ;
2017-03-17 13:24:21 +00:00
start = ceil ( ( start - bmaporgy ) / FBlockmap : : MAPBLOCKUNITS ) * FBlockmap : : MAPBLOCKUNITS + bmaporgy ;
2016-03-01 15:47:10 +00:00
end = miny + minlen - exty ;
// draw horizontal gridlines
2017-03-17 13:24:21 +00:00
for ( y = start ; y < end ; y + = FBlockmap : : MAPBLOCKUNITS )
2016-03-01 15:47:10 +00:00
{
ml . a . x = minx - extx ;
ml . b . x = ml . a . x + minlen ;
ml . a . y = y ;
ml . b . y = y ;
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & ml . a . x , & ml . a . y ) ;
rotatePoint ( & ml . b . x , & ml . b . y ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
drawMline ( & ml , color ) ;
2016-03-01 15:47:10 +00:00
}
}
2017-03-12 22:13:07 +00:00
//==========================================================================
//
// This was previously using the variants from the renderers but with
// all globals being factored out this will become dangerouns and unpredictable
// as the original R_FakeFlat heavily depended on global variables from
// the last rendered scene.
//
//==========================================================================
sector_t * AM_FakeFlat ( AActor * viewer , sector_t * sec , sector_t * dest )
{
if ( sec - > GetHeightSec ( ) = = nullptr ) return sec ;
DVector3 pos = viewer - > Pos ( ) ;
if ( viewer - > player )
{
pos . Z = viewer - > player - > viewz ;
}
else
{
pos . Z + = viewer - > GetCameraHeight ( ) ;
}
int in_area ;
if ( viewer - > Sector - > GetHeightSec ( ) = = nullptr )
{
in_area = 0 ;
}
else
{
in_area = pos . Z < = viewer - > Sector - > heightsec - > floorplane . ZatPoint ( pos ) ? - 1 :
2018-05-01 09:29:29 +00:00
( pos . Z > viewer - > Sector - > heightsec - > ceilingplane . ZatPoint ( pos ) & & ! ( viewer - > Sector - > heightsec - > MoreFlags & SECMF_FAKEFLOORONLY ) ) ? 1 : 0 ;
2017-03-12 22:13:07 +00:00
}
2018-05-01 09:29:29 +00:00
int diffTex = ( sec - > heightsec - > MoreFlags & SECMF_CLIPFAKEPLANES ) ;
2017-03-12 22:13:07 +00:00
sector_t * s = sec - > heightsec ;
memcpy ( dest , sec , sizeof ( sector_t ) ) ;
// Replace floor height with control sector's heights.
// The automap is only interested in the floor so let's skip the ceiling.
if ( diffTex )
{
if ( s - > floorplane . CopyPlaneIfValid ( & dest - > floorplane , & sec - > ceilingplane ) )
{
dest - > SetTexture ( sector_t : : floor , s - > GetTexture ( sector_t : : floor ) , false ) ;
2018-05-01 09:29:29 +00:00
dest - > SetPlaneTexZQuick ( sector_t : : floor , s - > GetPlaneTexZ ( sector_t : : floor ) ) ;
2017-03-12 22:13:07 +00:00
}
2018-05-01 09:29:29 +00:00
else if ( s - > MoreFlags & SECMF_FAKEFLOORONLY )
2017-03-12 22:13:07 +00:00
{
if ( in_area = = - 1 )
{
2017-03-15 15:47:42 +00:00
dest - > Colormap = s - > Colormap ;
2018-05-01 09:29:29 +00:00
if ( ! ( s - > MoreFlags & SECMF_NOFAKELIGHT ) )
2017-03-12 22:13:07 +00:00
{
dest - > lightlevel = s - > lightlevel ;
dest - > SetPlaneLight ( sector_t : : floor , s - > GetPlaneLight ( sector_t : : floor ) ) ;
dest - > ChangeFlags ( sector_t : : floor , - 1 , s - > GetFlags ( sector_t : : floor ) ) ;
}
return dest ;
}
return sec ;
}
}
else
{
2018-05-01 09:29:29 +00:00
dest - > SetPlaneTexZQuick ( sector_t : : floor , s - > GetPlaneTexZ ( sector_t : : floor ) ) ;
2017-03-12 22:13:07 +00:00
dest - > floorplane = s - > floorplane ;
}
if ( in_area = = - 1 )
{
2017-03-15 15:47:42 +00:00
dest - > Colormap = s - > Colormap ;
2018-05-01 09:29:29 +00:00
dest - > SetPlaneTexZQuick ( sector_t : : floor , sec - > GetPlaneTexZ ( sector_t : : floor ) ) ;
2017-03-12 22:13:07 +00:00
dest - > floorplane = sec - > floorplane ;
2018-05-01 09:29:29 +00:00
if ( ! ( s - > MoreFlags & SECMF_NOFAKELIGHT ) )
2017-03-12 22:13:07 +00:00
{
dest - > lightlevel = s - > lightlevel ;
}
dest - > SetTexture ( sector_t : : floor , diffTex ? sec - > GetTexture ( sector_t : : floor ) : s - > GetTexture ( sector_t : : floor ) , false ) ;
dest - > planes [ sector_t : : floor ] . xform = s - > planes [ sector_t : : floor ] . xform ;
2018-05-01 09:29:29 +00:00
if ( ! ( s - > MoreFlags & SECMF_NOFAKELIGHT ) )
2017-03-12 22:13:07 +00:00
{
dest - > SetPlaneLight ( sector_t : : floor , s - > GetPlaneLight ( sector_t : : floor ) ) ;
dest - > ChangeFlags ( sector_t : : floor , - 1 , s - > GetFlags ( sector_t : : floor ) ) ;
}
}
else if ( in_area = = 1 )
{
2017-03-15 15:47:42 +00:00
dest - > Colormap = s - > Colormap ;
2018-05-01 09:29:29 +00:00
dest - > SetPlaneTexZQuick ( sector_t : : floor , s - > GetPlaneTexZ ( sector_t : : ceiling ) ) ;
2017-03-12 22:13:07 +00:00
dest - > floorplane = s - > ceilingplane ;
2018-05-01 09:29:29 +00:00
if ( ! ( s - > MoreFlags & SECMF_NOFAKELIGHT ) )
2017-03-12 22:13:07 +00:00
{
dest - > lightlevel = s - > lightlevel ;
}
dest - > SetTexture ( sector_t : : floor , s - > GetTexture ( sector_t : : ceiling ) , false ) ;
if ( s - > GetTexture ( sector_t : : floor ) ! = skyflatnum )
{
dest - > SetTexture ( sector_t : : floor , s - > GetTexture ( sector_t : : floor ) , false ) ;
dest - > planes [ sector_t : : floor ] . xform = s - > planes [ sector_t : : floor ] . xform ;
}
2018-05-01 09:29:29 +00:00
if ( ! ( s - > MoreFlags & SECMF_NOFAKELIGHT ) )
2017-03-12 22:13:07 +00:00
{
dest - > lightlevel = s - > lightlevel ;
dest - > SetPlaneLight ( sector_t : : floor , s - > GetPlaneLight ( sector_t : : floor ) ) ;
dest - > ChangeFlags ( sector_t : : floor , - 1 , s - > GetFlags ( sector_t : : floor ) ) ;
}
}
return dest ;
}
2016-03-01 15:47:10 +00:00
//=============================================================================
//
// AM_drawSubsectors
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawSubsectors ( )
2016-03-01 15:47:10 +00:00
{
2018-11-10 07:04:03 +00:00
std : : vector < uint32_t > indices ;
2016-03-25 20:54:59 +00:00
double scale = scale_mtof ;
DAngle rotation ;
2016-03-01 15:47:10 +00:00
sector_t tempsec ;
2017-03-12 22:13:07 +00:00
int floorlight ;
2016-03-25 20:54:59 +00:00
double scalex , scaley ;
2016-03-01 15:47:10 +00:00
double originx , originy ;
2017-03-15 15:47:42 +00:00
FColormap colormap ;
2017-01-28 19:44:46 +00:00
PalEntry flatcolor ;
2016-03-01 15:47:10 +00:00
mpoint_t originpt ;
2019-01-26 14:21:20 +00:00
auto & subsectors = Level - > subsectors ;
2017-03-16 23:22:52 +00:00
for ( unsigned i = 0 ; i < subsectors . Size ( ) ; + + i )
2016-03-01 15:47:10 +00:00
{
2018-11-10 07:04:03 +00:00
auto sub = & subsectors [ i ] ;
if ( sub - > flags & SSECF_POLYORG )
2016-03-01 15:47:10 +00:00
{
continue ;
}
2018-11-10 07:04:03 +00:00
if ( ( ! ( sub - > flags & SSECMF_DRAWN ) | | ( sub - > flags & SSECF_HOLE ) | | ( sub - > render_sector - > MoreFlags & SECMF_HIDDEN ) ) & & am_cheat = = 0 )
2016-03-01 15:47:10 +00:00
{
continue ;
}
2016-03-13 11:33:58 +00:00
2018-11-10 07:04:03 +00:00
if ( am_portaloverlay & & sub - > render_sector - > PortalGroup ! = MapPortalGroup & & sub - > render_sector - > PortalGroup ! = 0 )
2016-03-13 11:33:58 +00:00
{
continue ;
}
2016-03-01 15:47:10 +00:00
// Fill the points array from the subsector.
2018-11-10 07:04:03 +00:00
points . Resize ( sub - > numlines ) ;
for ( uint32_t j = 0 ; j < sub - > numlines ; + + j )
2016-03-01 15:47:10 +00:00
{
2018-11-10 07:04:03 +00:00
mpoint_t pt = { sub - > firstline [ j ] . v1 - > fX ( ) ,
sub - > firstline [ j ] . v1 - > fY ( ) } ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & pt . x , & pt . y ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
points [ j ] . X = float ( f_x + ( ( pt . x - m_x ) * scale ) ) ;
points [ j ] . Y = float ( f_y + ( f_h - ( pt . y - m_y ) * scale ) ) ;
2016-03-01 15:47:10 +00:00
}
// For lighting and texture determination
2018-11-10 07:04:03 +00:00
sector_t * sec = AM_FakeFlat ( players [ consoleplayer ] . camera , sub - > render_sector , & tempsec ) ;
2017-03-12 22:13:07 +00:00
floorlight = sec - > GetFloorLight ( ) ;
2016-03-01 15:47:10 +00:00
// Find texture origin.
2016-04-23 11:40:02 +00:00
originpt . x = - sec - > GetXOffset ( sector_t : : floor ) ;
originpt . y = sec - > GetYOffset ( sector_t : : floor ) ;
rotation = - sec - > GetAngle ( sector_t : : floor ) ;
2016-03-01 15:47:10 +00:00
// Coloring for the polygon
2017-03-15 15:47:42 +00:00
colormap = sec - > Colormap ;
2016-03-01 15:47:10 +00:00
FTextureID maptex = sec - > GetTexture ( sector_t : : floor ) ;
2017-01-28 19:44:46 +00:00
flatcolor = sec - > SpecialColors [ sector_t : : floor ] ;
2016-03-01 15:47:10 +00:00
2016-04-23 11:40:02 +00:00
scalex = sec - > GetXScale ( sector_t : : floor ) ;
scaley = sec - > GetYScale ( sector_t : : floor ) ;
2016-03-01 15:47:10 +00:00
if ( sec - > e - > XFloor . ffloors . Size ( ) )
{
secplane_t * floorplane = & sec - > floorplane ;
// Look for the highest floor below the camera viewpoint.
// Check the center of the subsector's sector. Do not check each
// subsector separately because that might result in different planes for
// different subsectors of the same sector which is not wanted here.
// (Make the comparison in floating point to avoid overflows and improve performance.)
double secx ;
double secy ;
double seczb , seczt ;
2018-11-10 07:04:03 +00:00
auto & vp = r_viewpoint ;
2018-06-19 09:20:36 +00:00
double cmpz = vp . Pos . Z ;
2016-03-01 15:47:10 +00:00
if ( players [ consoleplayer ] . camera & & sec = = players [ consoleplayer ] . camera - > Sector )
{
// For the actual camera sector use the current viewpoint as reference.
2018-06-19 09:20:36 +00:00
secx = vp . Pos . X ;
secy = vp . Pos . Y ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-26 08:38:58 +00:00
secx = sec - > centerspot . X ;
secy = sec - > centerspot . Y ;
2016-03-01 15:47:10 +00:00
}
seczb = floorplane - > ZatPoint ( secx , secy ) ;
seczt = sec - > ceilingplane . ZatPoint ( secx , secy ) ;
2016-03-30 22:41:21 +00:00
2016-03-01 15:47:10 +00:00
for ( unsigned int i = 0 ; i < sec - > e - > XFloor . ffloors . Size ( ) ; + + i )
{
F3DFloor * rover = sec - > e - > XFloor . ffloors [ i ] ;
if ( ! ( rover - > flags & FF_EXISTS ) ) continue ;
2018-11-10 07:04:03 +00:00
if ( rover - > flags & ( FF_FOG | FF_THISINSIDE ) ) continue ;
2016-03-01 15:47:10 +00:00
if ( ! ( rover - > flags & FF_RENDERPLANES ) ) continue ;
if ( rover - > alpha = = 0 ) continue ;
double roverz = rover - > top . plane - > ZatPoint ( secx , secy ) ;
// Ignore 3D floors that are above or below the sector itself:
// they are hidden. Since 3D floors are sorted top to bottom,
// if we get below the sector floor, we can stop.
if ( roverz > seczt ) continue ;
if ( roverz < seczb ) break ;
if ( roverz < cmpz )
{
maptex = * ( rover - > top . texture ) ;
2017-01-28 19:44:46 +00:00
flatcolor = * ( rover - > top . flatcolor ) ;
2016-03-01 15:47:10 +00:00
floorplane = rover - > top . plane ;
sector_t * model = rover - > top . model ;
int selector = ( rover - > flags & FF_INVERTPLANES ) ? sector_t : : floor : sector_t : : ceiling ;
2016-04-23 11:40:02 +00:00
rotation = - model - > GetAngle ( selector ) ;
scalex = model - > GetXScale ( selector ) ;
scaley = model - > GetYScale ( selector ) ;
originpt . x = - model - > GetXOffset ( selector ) ;
originpt . y = model - > GetYOffset ( selector ) ;
2016-03-01 15:47:10 +00:00
break ;
}
}
lightlist_t * light = P_GetPlaneLight ( sec , floorplane , false ) ;
floorlight = * light - > p_lightlevel ;
colormap = light - > extra_colormap ;
}
if ( maptex = = skyflatnum )
{
continue ;
}
// Apply the floor's rotation to the texture origin.
if ( rotation ! = 0 )
{
2019-01-26 14:21:20 +00:00
rotate ( & originpt . x , & originpt . y , rotation ) ;
2016-03-01 15:47:10 +00:00
}
// Apply the automap's rotation to the texture origin.
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2016-03-25 20:54:59 +00:00
rotation = rotation + 90. - players [ consoleplayer ] . camera - > Angles . Yaw ;
2019-01-26 14:21:20 +00:00
rotatePoint ( & originpt . x , & originpt . y ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
originx = f_x + ( ( originpt . x - m_x ) * scale ) ;
originy = f_y + ( f_h - ( originpt . y - m_y ) * scale ) ;
2016-03-01 15:47:10 +00:00
// If this subsector has not actually been seen yet (because you are cheating
// to see it on the map), tint and desaturate it.
2018-11-10 07:04:03 +00:00
if ( ! ( sub - > flags & SSECMF_DRAWN ) )
2016-03-01 15:47:10 +00:00
{
2017-03-15 15:47:42 +00:00
colormap . LightColor = PalEntry (
( colormap . LightColor . r + 255 ) / 2 ,
( colormap . LightColor . g + 200 ) / 2 ,
( colormap . LightColor . b + 160 ) / 2 ) ;
colormap . Desaturation = 255 - ( 255 - colormap . Desaturation ) / 4 ;
2016-03-01 15:47:10 +00:00
}
2018-03-29 14:21:21 +00:00
// make table based fog visible on the automap as well.
2019-01-26 14:21:20 +00:00
if ( Level - > flags & LEVEL_HASFADETABLE )
2018-03-29 14:21:21 +00:00
{
colormap . FadeColor = PalEntry ( 0 , 128 , 128 , 128 ) ;
}
2016-03-01 15:47:10 +00:00
// Draw the polygon.
2018-12-06 00:11:04 +00:00
if ( maptex . isValid ( ) )
2016-03-01 15:47:10 +00:00
{
2018-11-10 07:04:03 +00:00
// Hole filling "subsectors" are not necessarily convex so they require real triangulation.
// These things are extremely rare so performance is secondary here.
if ( sub - > flags & SSECF_HOLE & & sub - > numlines > 3 )
{
using Point = std : : pair < double , double > ;
std : : vector < std : : vector < Point > > polygon ;
std : : vector < Point > * curPoly ;
polygon . resize ( 1 ) ;
curPoly = & polygon . back ( ) ;
curPoly - > resize ( points . Size ( ) ) ;
for ( unsigned i = 0 ; i < points . Size ( ) ; i + + )
{
( * curPoly ) [ i ] = { points [ i ] . X , points [ i ] . Y } ;
}
indices = mapbox : : earcut ( polygon ) ;
}
else indices . clear ( ) ;
2018-12-07 01:53:18 +00:00
screen - > FillSimplePoly ( TexMan . GetTexture ( maptex , true ) ,
2016-03-01 15:47:10 +00:00
& points [ 0 ] , points . Size ( ) ,
originx , originy ,
2016-03-25 20:54:59 +00:00
scale / scalex ,
scale / scaley ,
rotation ,
2016-03-01 15:47:10 +00:00
colormap ,
2017-01-28 19:44:46 +00:00
flatcolor ,
2016-11-06 03:49:33 +00:00
floorlight ,
2018-11-10 07:04:03 +00:00
f_y + f_h ,
indices . data ( ) , indices . size ( ) ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2018-03-10 15:36:43 +00:00
static int AM_CheckSecret ( line_t * line )
2016-03-01 15:47:10 +00:00
{
if ( AMColors . isValid ( AMColors . SecretSectorColor ) )
{
2019-01-26 14:21:20 +00:00
if ( line - > frontsector ! = nullptr )
2016-03-01 15:47:10 +00:00
{
if ( line - > frontsector - > wasSecret ( ) )
{
2018-03-10 15:36:43 +00:00
if ( am_map_secrets ! = 0 & & ! line - > frontsector - > isSecret ( ) ) return 1 ;
if ( am_map_secrets = = 2 & & ! ( line - > flags & ML_SECRET ) ) return 2 ;
2016-03-01 15:47:10 +00:00
}
}
2019-01-26 14:21:20 +00:00
if ( line - > backsector ! = nullptr )
2016-03-01 15:47:10 +00:00
{
if ( line - > backsector - > wasSecret ( ) )
{
2018-03-10 15:36:43 +00:00
if ( am_map_secrets ! = 0 & & ! line - > backsector - > isSecret ( ) ) return 1 ;
if ( am_map_secrets = = 2 & & ! ( line - > flags & ML_SECRET ) ) return 2 ;
2016-03-01 15:47:10 +00:00
}
}
}
2018-03-10 15:36:43 +00:00
return 0 ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// Polyobject debug stuff
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawSeg ( seg_t * seg , const AMColor & color )
2016-03-01 15:47:10 +00:00
{
mline_t l ;
2016-03-25 20:54:59 +00:00
l . a . x = seg - > v1 - > fX ( ) ;
l . a . y = seg - > v1 - > fY ( ) ;
l . b . x = seg - > v2 - > fX ( ) ;
l . b . y = seg - > v2 - > fY ( ) ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & l . a . x , & l . a . y ) ;
rotatePoint ( & l . b . x , & l . b . y ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
drawMline ( & l , color ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
void DAutomap : : drawPolySeg ( FPolySeg * seg , const AMColor & color )
2016-03-01 15:47:10 +00:00
{
mline_t l ;
2016-03-30 22:41:21 +00:00
l . a . x = seg - > v1 . pos . X ;
l . a . y = seg - > v1 . pos . Y ;
l . b . x = seg - > v2 . pos . X ;
l . b . y = seg - > v2 . pos . Y ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & l . a . x , & l . a . y ) ;
rotatePoint ( & l . b . x , & l . b . y ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
drawMline ( & l , color ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
void DAutomap : : showSS ( )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
if ( am_showsubsector > = 0 & & ( unsigned ) am_showsubsector < Level - > subsectors . Size ( ) )
2016-03-01 15:47:10 +00:00
{
AMColor yellow ;
yellow . FromRGB ( 255 , 255 , 0 ) ;
AMColor red ;
red . FromRGB ( 255 , 0 , 0 ) ;
2019-01-26 14:21:20 +00:00
subsector_t * sub = & Level - > subsectors [ am_showsubsector ] ;
2016-03-01 15:47:10 +00:00
for ( unsigned int i = 0 ; i < sub - > numlines ; i + + )
{
2019-01-26 14:21:20 +00:00
drawSeg ( sub - > firstline + i , yellow ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
for ( auto & poly : Level - > Polyobjects )
2016-03-01 15:47:10 +00:00
{
2018-12-28 09:08:39 +00:00
FPolyNode * pnode = poly . subsectorlinks ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
while ( pnode ! = nullptr )
2016-03-01 15:47:10 +00:00
{
if ( pnode - > subsector = = sub )
{
for ( unsigned j = 0 ; j < pnode - > segs . Size ( ) ; j + + )
{
2019-01-26 14:21:20 +00:00
drawPolySeg ( & pnode - > segs [ j ] , red ) ;
2016-03-01 15:47:10 +00:00
}
}
pnode = pnode - > snext ;
}
}
}
}
//=============================================================================
//
// Determines if a 3D floor boundary should be drawn
//
//=============================================================================
bool AM_Check3DFloors ( line_t * line )
{
TArray < F3DFloor * > & ff_front = line - > frontsector - > e - > XFloor . ffloors ;
TArray < F3DFloor * > & ff_back = line - > backsector - > e - > XFloor . ffloors ;
// No 3D floors so there's no boundary
if ( ff_back . Size ( ) = = 0 & & ff_front . Size ( ) = = 0 ) return false ;
int realfrontcount = 0 ;
int realbackcount = 0 ;
for ( unsigned i = 0 ; i < ff_front . Size ( ) ; i + + )
{
F3DFloor * rover = ff_front [ i ] ;
2018-04-07 21:30:28 +00:00
if ( rover - > flags & FF_THISINSIDE ) continue ;
2016-03-01 15:47:10 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) ) continue ;
if ( rover - > alpha = = 0 ) continue ;
realfrontcount + + ;
}
for ( unsigned i = 0 ; i < ff_back . Size ( ) ; i + + )
{
F3DFloor * rover = ff_back [ i ] ;
2018-04-07 21:30:28 +00:00
if ( rover - > flags & FF_THISINSIDE ) continue ;
2016-03-01 15:47:10 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) ) continue ;
if ( rover - > alpha = = 0 ) continue ;
realbackcount + + ;
}
// if the amount of 3D floors does not match there is a boundary
if ( realfrontcount ! = realbackcount ) return true ;
for ( unsigned i = 0 ; i < ff_front . Size ( ) ; i + + )
{
F3DFloor * rover = ff_front [ i ] ;
2018-04-07 21:30:28 +00:00
if ( rover - > flags & FF_THISINSIDE ) continue ; // only relevant for software rendering.
2016-03-01 15:47:10 +00:00
if ( ! ( rover - > flags & FF_EXISTS ) ) continue ;
if ( rover - > alpha = = 0 ) continue ;
bool found = false ;
for ( unsigned j = 0 ; j < ff_back . Size ( ) ; j + + )
{
F3DFloor * rover2 = ff_back [ j ] ;
2018-04-07 21:30:28 +00:00
if ( rover2 - > flags & FF_THISINSIDE ) continue ; // only relevant for software rendering.
2016-03-01 15:47:10 +00:00
if ( ! ( rover2 - > flags & FF_EXISTS ) ) continue ;
if ( rover2 - > alpha = = 0 ) continue ;
if ( rover - > model = = rover2 - > model & & rover - > flags = = rover2 - > flags )
{
found = true ;
break ;
}
}
// At least one 3D floor in the front sector didn't have a match in the back sector so there is a boundary.
if ( ! found ) return true ;
}
// All 3D floors could be matched so let's not draw a boundary.
return false ;
}
// [TP] Check whether a sector can trigger a special that satisfies the provided function.
// If found, specialptr and argsptr will be filled by the special and the arguments
// If needUseActivated is true, the special must be activated by use.
bool AM_checkSectorActions ( sector_t * sector , bool ( * function ) ( int , int * ) , int * specialptr , int * * argsptr , bool needUseActivated )
{
2017-01-13 12:51:47 +00:00
// This code really stands in the way of a more generic and flexible implementation of sector actions because it makes far too many assumptions
// about their internal workings. Well, it can't be helped. Let's just hope that nobody abuses the special and the health field in a way that breaks this.
for ( AActor * action = sector - > SecActTarget ; action ; action = action - > tracer )
2016-03-01 15:47:10 +00:00
{
2017-01-13 12:51:47 +00:00
if ( ( ( action - > health & ( SECSPAC_Use | SECSPAC_UseWall ) ) | | false = = needUseActivated )
2016-03-01 15:47:10 +00:00
& & ( * function ) ( action - > special , action - > args )
2017-01-13 12:51:47 +00:00
& & ! ( action - > flags & MF_FRIENDLY ) )
2016-03-01 15:47:10 +00:00
{
* specialptr = action - > special ;
* argsptr = action - > args ;
return true ;
}
}
return false ;
}
// [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function.
// It's a boundary if the line can activate the special or the line's bordering sectors can activate it.
// If found, specialptr and argsptr will be filled with special and args if given.
2019-01-26 14:21:20 +00:00
bool AM_checkSpecialBoundary ( line_t & line , bool ( * function ) ( int , int * ) , int * specialptr = nullptr , int * * argsptr = nullptr )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
if ( specialptr = = nullptr )
2016-03-01 15:47:10 +00:00
{
static int sink ;
specialptr = & sink ;
}
2019-01-26 14:21:20 +00:00
if ( argsptr = = nullptr )
2016-03-01 15:47:10 +00:00
{
static int * sink ;
argsptr = & sink ;
}
// Check if the line special qualifies for this
if ( ( line . activation & SPAC_PlayerActivate ) & & ( * function ) ( line . special , line . args ) )
{
* specialptr = line . special ;
* argsptr = line . args ;
return true ;
}
// Check sector actions in the line's front sector -- the action has to be use-activated in order to
// show up if this is a one-sided line, because the player cannot trigger sector actions by crossing
// a one-sided line (since that's impossible, duh).
2019-01-26 14:21:20 +00:00
if ( AM_checkSectorActions ( line . frontsector , function , specialptr , argsptr , line . backsector = = nullptr ) )
2016-03-01 15:47:10 +00:00
return true ;
// If it has a back sector, check sector actions in that.
return ( line . backsector & & AM_checkSectorActions ( line . backsector , function , specialptr , argsptr , false ) ) ;
}
bool AM_isTeleportBoundary ( line_t & line )
{
2017-02-26 14:01:55 +00:00
return AM_checkSpecialBoundary ( line , [ ] ( int special , int * )
{
return ( special = = Teleport | |
special = = Teleport_NoFog | |
special = = Teleport_ZombieChanger | |
special = = Teleport_Line ) ;
} ) ;
2016-03-01 15:47:10 +00:00
}
bool AM_isExitBoundary ( line_t & line )
{
2017-02-26 14:01:55 +00:00
return AM_checkSpecialBoundary ( line , [ ] ( int special , int * )
{
return ( special = = Teleport_NewMap | |
special = = Teleport_EndGame | |
special = = Exit_Normal | |
special = = Exit_Secret ) ;
} ) ;
2016-03-01 15:47:10 +00:00
}
bool AM_isTriggerBoundary ( line_t & line )
{
2017-02-26 14:01:55 +00:00
return am_showtriggerlines = = 1 ? AM_checkSpecialBoundary ( line , [ ] ( int special , int * )
{
FLineSpecial * spec = P_GetLineSpecialInfo ( special ) ;
2019-01-26 14:21:20 +00:00
return spec ! = nullptr
2017-02-26 14:01:55 +00:00
& & spec - > max_args > = 0
& & special ! = Door_Open
& & special ! = Door_Close
& & special ! = Door_CloseWaitOpen
& & special ! = Door_Raise
& & special ! = Door_Animated
& & special ! = Generic_Door ;
} ) : AM_checkSpecialBoundary ( line , [ ] ( int special , int * )
{
FLineSpecial * spec = P_GetLineSpecialInfo ( special ) ;
2019-01-26 14:21:20 +00:00
return spec ! = nullptr
2017-02-26 14:01:55 +00:00
& & spec - > max_args > = 0 ;
} ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
bool AM_isLockBoundary ( line_t & line , int * lockptr = nullptr )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
if ( lockptr = = nullptr )
2016-03-01 15:47:10 +00:00
{
static int sink ;
lockptr = & sink ;
}
if ( line . locknumber )
{
* lockptr = line . locknumber ;
return true ;
}
int special ;
int * args ;
2017-02-26 14:01:55 +00:00
bool result = AM_checkSpecialBoundary ( line , [ ] ( int special , int * args )
{
return special = = Door_LockedRaise
| | special = = ACS_LockedExecute
| | special = = ACS_LockedExecuteDoor
| | ( special = = Door_Animated & & args [ 3 ] ! = 0 )
| | ( special = = Generic_Door & & args [ 4 ] ! = 0 )
| | ( special = = FS_Execute & & args [ 2 ] ! = 0 ) ;
} , & special , & args ) ;
2016-03-01 15:47:10 +00:00
if ( result )
{
switch ( special )
{
case FS_Execute :
* lockptr = args [ 2 ] ;
break ;
case Door_Animated :
case Door_LockedRaise :
* lockptr = args [ 3 ] ;
break ;
default :
* lockptr = args [ 4 ] ;
break ;
}
}
return result ;
}
//=============================================================================
//
// Determines visible lines, draws them.
// This is LineDef based, not LineSeg based.
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawWalls ( bool allmap )
2016-03-01 15:47:10 +00:00
{
static mline_t l ;
int lock , color ;
2019-01-26 14:21:20 +00:00
int numportalgroups = am_portaloverlay ? Level - > Displacements . size : 0 ;
2016-03-13 11:33:58 +00:00
for ( int p = numportalgroups - 1 ; p > = - 1 ; p - - )
2016-03-01 15:47:10 +00:00
{
2016-03-13 11:33:58 +00:00
if ( p = = MapPortalGroup ) continue ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
for ( auto & line : Level - > lines )
2016-03-01 15:47:10 +00:00
{
2016-03-13 11:33:58 +00:00
int pg ;
2017-01-08 13:39:16 +00:00
if ( line . sidedef [ 0 ] - > Flags & WALLF_POLYOBJ )
2016-03-01 15:47:10 +00:00
{
2016-03-13 11:33:58 +00:00
// For polyobjects we must test the surrounding sector to get the proper group.
2017-01-08 13:39:16 +00:00
pg = P_PointInSector ( line . v1 - > fX ( ) + line . Delta ( ) . X / 2 , line . v1 - > fY ( ) + line . Delta ( ) . Y / 2 ) - > PortalGroup ;
2016-03-01 15:47:10 +00:00
}
2016-03-13 11:33:58 +00:00
else
2016-03-01 15:47:10 +00:00
{
2017-01-08 13:39:16 +00:00
pg = line . frontsector - > PortalGroup ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
DVector2 offset ;
2016-03-13 11:33:58 +00:00
bool portalmode = numportalgroups > 0 & & pg ! = MapPortalGroup ;
if ( pg = = p )
{
2019-01-26 14:21:20 +00:00
offset = Level - > Displacements . getOffset ( pg , MapPortalGroup ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-13 11:33:58 +00:00
else if ( p = = - 1 & & ( pg = = MapPortalGroup | | ! am_portaloverlay ) )
{
offset = { 0 , 0 } ;
2016-03-01 15:47:10 +00:00
}
2016-03-13 11:33:58 +00:00
else continue ;
2017-01-08 13:39:16 +00:00
l . a . x = ( line . v1 - > fX ( ) + offset . X ) ;
l . a . y = ( line . v1 - > fY ( ) + offset . Y ) ;
l . b . x = ( line . v2 - > fX ( ) + offset . X ) ;
l . b . y = ( line . v2 - > fY ( ) + offset . Y ) ;
2016-03-13 11:33:58 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & l . a . x , & l . a . y ) ;
rotatePoint ( & l . b . x , & l . b . y ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-13 11:33:58 +00:00
2017-01-08 13:39:16 +00:00
if ( am_cheat ! = 0 | | ( line . flags & ML_MAPPED ) )
2016-03-01 15:47:10 +00:00
{
2017-01-08 13:39:16 +00:00
if ( ( line . flags & ML_DONTDRAW ) & & ( am_cheat = = 0 | | am_cheat > = 4 ) )
2016-03-01 15:47:10 +00:00
{
2016-03-13 11:33:58 +00:00
if ( ! am_showallenabled | | CheckCheatmode ( false ) )
{
continue ;
}
}
2016-03-01 15:47:10 +00:00
2018-05-19 07:49:04 +00:00
if ( line . automapstyle > AMLS_Default & & line . automapstyle < AMLS_COUNT
& & ( am_cheat = = 0 | | am_cheat > = 4 ) )
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AUTOMAP_LINE_COLORS [ line . automapstyle ] ) ;
2018-05-19 07:49:04 +00:00
continue ;
}
2016-03-13 11:33:58 +00:00
if ( portalmode )
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . PortalColor ) ;
2016-03-13 11:33:58 +00:00
}
2018-03-10 15:36:43 +00:00
else if ( AM_CheckSecret ( & line ) = = 1 )
2016-03-13 11:33:58 +00:00
{
// map secret sectors like Boom
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . SecretSectorColor ) ;
2016-03-13 11:33:58 +00:00
}
2018-03-10 15:36:43 +00:00
else if ( AM_CheckSecret ( & line ) = = 2 )
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . UnexploredSecretColor ) ;
2018-03-10 15:36:43 +00:00
}
2017-01-08 13:39:16 +00:00
else if ( line . flags & ML_SECRET )
2016-03-13 11:33:58 +00:00
{ // secret door
2019-01-26 14:21:20 +00:00
if ( am_cheat ! = 0 & & line . backsector ! = nullptr )
drawMline ( & l , AMColors . SecretWallColor ) ;
2016-03-13 11:33:58 +00:00
else
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . WallColor ) ;
2016-03-13 11:33:58 +00:00
}
2017-01-08 13:39:16 +00:00
else if ( AM_isTeleportBoundary ( line ) & & AMColors . isValid ( AMColors . IntraTeleportColor ) )
2016-03-13 11:33:58 +00:00
{ // intra-level teleporters
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . IntraTeleportColor ) ;
2016-03-13 11:33:58 +00:00
}
2017-01-08 13:39:16 +00:00
else if ( AM_isExitBoundary ( line ) & & AMColors . isValid ( AMColors . InterTeleportColor ) )
2016-03-13 11:33:58 +00:00
{ // inter-level/game-ending teleporters
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . InterTeleportColor ) ;
2016-03-13 11:33:58 +00:00
}
2017-01-08 13:39:16 +00:00
else if ( AM_isLockBoundary ( line , & lock ) )
2016-03-13 11:33:58 +00:00
{
if ( AMColors . displayLocks )
{
color = P_GetMapColorForLock ( lock ) ;
2016-03-01 15:47:10 +00:00
2016-03-13 11:33:58 +00:00
AMColor c ;
2016-03-01 15:47:10 +00:00
2016-03-13 11:33:58 +00:00
if ( color > = 0 ) c . FromRGB ( RPART ( color ) , GPART ( color ) , BPART ( color ) ) ;
else c = AMColors [ AMColors . LockedColor ] ;
2019-01-26 14:21:20 +00:00
drawMline ( & l , c ) ;
2016-03-13 11:33:58 +00:00
}
else
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . LockedColor ) ; // locked special
2016-03-13 11:33:58 +00:00
}
2016-03-01 15:47:10 +00:00
}
2016-03-13 11:33:58 +00:00
else if ( am_showtriggerlines
& & AMColors . isValid ( AMColors . SpecialWallColor )
2017-01-08 13:39:16 +00:00
& & AM_isTriggerBoundary ( line ) )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . SpecialWallColor ) ; // wall with special non-door action the player can do
2016-03-13 11:33:58 +00:00
}
2019-01-26 14:21:20 +00:00
else if ( line . backsector = = nullptr )
2016-03-13 11:33:58 +00:00
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . WallColor ) ; // one-sided wall
2016-03-13 11:33:58 +00:00
}
2017-01-08 13:39:16 +00:00
else if ( line . backsector - > floorplane
! = line . frontsector - > floorplane )
2016-03-13 11:33:58 +00:00
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . FDWallColor ) ; // floor level change
2016-03-13 11:33:58 +00:00
}
2017-01-08 13:39:16 +00:00
else if ( line . backsector - > ceilingplane
! = line . frontsector - > ceilingplane )
2016-03-13 11:33:58 +00:00
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . CDWallColor ) ; // ceiling level change
2016-03-13 11:33:58 +00:00
}
2017-01-08 13:39:16 +00:00
else if ( AM_Check3DFloors ( & line ) )
2016-03-13 11:33:58 +00:00
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . EFWallColor ) ; // Extra floor border
2016-03-13 11:33:58 +00:00
}
else if ( am_cheat > 0 & & am_cheat < 4 )
{
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . TSWallColor ) ;
2016-03-01 15:47:10 +00:00
}
}
2018-05-19 06:31:22 +00:00
else if ( allmap | | ( line . flags & ML_REVEALED ) )
2016-03-01 15:47:10 +00:00
{
2017-01-08 13:39:16 +00:00
if ( ( line . flags & ML_DONTDRAW ) & & ( am_cheat = = 0 | | am_cheat > = 4 ) )
2016-03-01 15:47:10 +00:00
{
2016-03-13 11:33:58 +00:00
if ( ! am_showallenabled | | CheckCheatmode ( false ) )
{
continue ;
}
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
drawMline ( & l , AMColors . NotSeenColor ) ;
2016-03-01 15:47:10 +00:00
}
}
2016-03-13 11:33:58 +00:00
}
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
// Rotation in 2D.
// Used to rotate player arrow line character.
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : rotate ( double * xp , double * yp , DAngle a )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
static DAngle angle_saved = 0. ;
2016-03-01 15:47:10 +00:00
static double sinrot = 0 ;
static double cosrot = 1 ;
if ( angle_saved ! = a )
{
angle_saved = a ;
2016-03-30 14:30:22 +00:00
sinrot = sin ( a . Radians ( ) ) ;
cosrot = cos ( a . Radians ( ) ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
double x = * xp ;
double y = * yp ;
2016-03-01 15:47:10 +00:00
double tmpx = ( x * cosrot ) - ( y * sinrot ) ;
y = ( x * sinrot ) + ( y * cosrot ) ;
x = tmpx ;
2016-03-25 20:54:59 +00:00
* xp = x ;
* yp = y ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : rotatePoint ( double * x , double * y )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
double pivotx = m_x + m_w / 2 ;
double pivoty = m_y + m_h / 2 ;
2016-03-01 15:47:10 +00:00
* x - = pivotx ;
* y - = pivoty ;
2019-01-26 14:21:20 +00:00
rotate ( x , y , - players [ consoleplayer ] . camera - > Angles . Yaw + 90. ) ;
2016-03-01 15:47:10 +00:00
* x + = pivotx ;
* y + = pivoty ;
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawLineCharacter ( const mline_t * lineguy , size_t lineguylines , double scale , DAngle angle , const AMColor & color , double x , double y )
2016-03-01 15:47:10 +00:00
{
int i ;
mline_t l ;
for ( i = 0 ; i < lineguylines ; i + + ) {
l . a . x = lineguy [ i ] . a . x ;
l . a . y = lineguy [ i ] . a . y ;
if ( scale ) {
2016-03-25 20:54:59 +00:00
l . a . x * = scale ;
l . a . y * = scale ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
if ( angle ! = 0 )
2019-01-26 14:21:20 +00:00
rotate ( & l . a . x , & l . a . y , angle ) ;
2016-03-01 15:47:10 +00:00
l . a . x + = x ;
l . a . y + = y ;
l . b . x = lineguy [ i ] . b . x ;
l . b . y = lineguy [ i ] . b . y ;
if ( scale ) {
2016-03-25 20:54:59 +00:00
l . b . x * = scale ;
l . b . y * = scale ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
if ( angle ! = 0 )
2019-01-26 14:21:20 +00:00
rotate ( & l . b . x , & l . b . y , angle ) ;
2016-03-01 15:47:10 +00:00
l . b . x + = x ;
l . b . y + = y ;
2019-01-26 14:21:20 +00:00
drawMline ( & l , color ) ;
2016-03-01 15:47:10 +00:00
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawPlayers ( )
2016-03-01 15:47:10 +00:00
{
if ( am_cheat > = 2 & & am_cheat ! = 4 & & am_showthingsprites > 0 )
{
// Player sprites are drawn with the others
return ;
}
mpoint_t pt ;
2016-03-25 20:54:59 +00:00
DAngle angle ;
2016-03-01 15:47:10 +00:00
int i ;
if ( ! multiplayer )
{
mline_t * arrow ;
int numarrowlines ;
2016-03-25 20:54:59 +00:00
double vh = players [ consoleplayer ] . viewheight ;
DVector2 pos = am_portaloverlay ? players [ consoleplayer ] . camera - > GetPortalTransition ( vh ) : players [ consoleplayer ] . camera - > Pos ( ) ;
pt . x = pos . X ;
pt . y = pos . Y ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2016-04-07 08:39:15 +00:00
angle = 90. ;
2019-01-26 14:21:20 +00:00
rotatePoint ( & pt . x , & pt . y ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-03-25 20:54:59 +00:00
angle = players [ consoleplayer ] . camera - > Angles . Yaw ;
2016-03-01 15:47:10 +00:00
}
if ( am_cheat ! = 0 & & CheatMapArrow . Size ( ) > 0 )
{
arrow = & CheatMapArrow [ 0 ] ;
numarrowlines = CheatMapArrow . Size ( ) ;
}
else
{
arrow = & MapArrow [ 0 ] ;
numarrowlines = MapArrow . Size ( ) ;
}
2019-01-26 14:21:20 +00:00
drawLineCharacter ( arrow , numarrowlines , 0 , angle , AMColors [ AMColors . YourColor ] , pt . x , pt . y ) ;
2016-03-01 15:47:10 +00:00
return ;
}
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
player_t * p = & players [ i ] ;
AMColor color ;
2019-01-26 14:21:20 +00:00
if ( ! playeringame [ i ] | | p - > mo = = nullptr )
2016-03-01 15:47:10 +00:00
{
continue ;
}
// We don't always want to show allies on the automap.
if ( dmflags2 & DF2_NO_AUTOMAP_ALLIES & & i ! = consoleplayer )
continue ;
if ( deathmatch & & ! demoplayback & &
! p - > mo - > IsTeammate ( players [ consoleplayer ] . mo ) & &
p ! = players [ consoleplayer ] . camera - > player )
{
continue ;
}
2016-03-21 11:18:46 +00:00
if ( p - > mo - > Alpha < 1. )
2016-03-01 15:47:10 +00:00
{
color = AMColors [ AMColors . AlmostBackgroundColor ] ;
}
else
{
float h , s , v , r , g , b ;
2019-01-26 14:21:20 +00:00
D_GetPlayerColor ( i , & h , & s , & v , nullptr ) ;
2016-03-01 15:47:10 +00:00
HSVtoRGB ( & r , & g , & b , h , s , v ) ;
color . FromRGB ( clamp ( int ( r * 255.f ) , 0 , 255 ) , clamp ( int ( g * 255.f ) , 0 , 255 ) , clamp ( int ( b * 255.f ) , 0 , 255 ) ) ;
}
2019-01-26 14:21:20 +00:00
if ( p - > mo ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
DVector3 pos = p - > mo - > PosRelative ( MapPortalGroup ) ;
pt . x = pos . X ;
pt . y = pos . Y ;
2016-03-13 11:33:58 +00:00
2016-03-25 20:54:59 +00:00
angle = p - > mo - > Angles . Yaw ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & pt . x , & pt . y ) ;
2016-04-07 11:05:29 +00:00
angle - = players [ consoleplayer ] . camera - > Angles . Yaw - 90. ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
drawLineCharacter ( & MapArrow [ 0 ] , MapArrow . Size ( ) , 0 , angle , color , pt . x , pt . y ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawKeys ( )
2016-03-01 15:47:10 +00:00
{
AMColor color ;
mpoint_t p ;
2016-03-25 20:54:59 +00:00
DAngle angle ;
2016-03-01 15:47:10 +00:00
2018-12-04 16:11:36 +00:00
TThinkerIterator < AActor > it ( NAME_Key ) ;
AActor * key ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
while ( ( key = it . Next ( ) ) ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
DVector3 pos = key - > PosRelative ( MapPortalGroup ) ;
p . x = pos . X ;
p . y = pos . Y ;
2016-03-13 11:33:58 +00:00
2016-03-25 20:54:59 +00:00
angle = key - > Angles . Yaw ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & p . x , & p . y ) ;
2016-03-25 20:54:59 +00:00
angle + = - players [ consoleplayer ] . camera - > Angles . Yaw + 90. ;
2016-03-01 15:47:10 +00:00
}
if ( key - > flags & MF_SPECIAL )
{
// Find the key's own color.
// Only works correctly if single-key locks have lower numbers than any-key locks.
// That is the case for all default keys, however.
int c = P_GetMapColorForKey ( key ) ;
if ( c > = 0 ) color . FromRGB ( RPART ( c ) , GPART ( c ) , BPART ( c ) ) ;
else color = AMColors [ AMColors . ThingColor_CountItem ] ;
2019-01-26 14:21:20 +00:00
drawLineCharacter ( & EasyKey [ 0 ] , EasyKey . Size ( ) , 0 , 0. , color , p . x , p . y ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawThings ( )
2016-03-01 15:47:10 +00:00
{
AMColor color ;
AActor * t ;
mpoint_t p ;
2016-03-25 20:54:59 +00:00
DAngle angle ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
for ( auto & sec : Level - > sectors )
2016-03-01 15:47:10 +00:00
{
2017-01-07 18:32:24 +00:00
t = sec . thinglist ;
2016-03-01 15:47:10 +00:00
while ( t )
{
if ( am_cheat > 0 | | ! ( t - > flags6 & MF6_NOTONAUTOMAP ) )
{
2016-03-25 20:54:59 +00:00
DVector3 pos = t - > PosRelative ( MapPortalGroup ) ;
p . x = pos . X ;
p . y = pos . Y ;
2016-03-01 15:47:10 +00:00
if ( am_showthingsprites > 0 & & t - > sprite > 0 )
{
2019-01-26 14:21:20 +00:00
FTexture * texture = nullptr ;
2016-03-01 15:47:10 +00:00
spriteframe_t * frame ;
2016-03-25 20:54:59 +00:00
int rotation = 0 ;
2016-03-01 15:47:10 +00:00
// try all modes backwards until a valid texture has been found.
2019-01-26 14:21:20 +00:00
for ( int show = am_showthingsprites ; show > 0 & & texture = = nullptr ; show - - )
2016-03-01 15:47:10 +00:00
{
const spritedef_t & sprite = sprites [ t - > sprite ] ;
const size_t spriteIndex = sprite . spriteframes + ( show > 1 ? t - > frame : 0 ) ;
frame = & SpriteFrames [ spriteIndex ] ;
2017-12-30 10:08:32 +00:00
DAngle angle = 270. + 22.5 - t - > Angles . Yaw ;
2016-03-25 20:54:59 +00:00
if ( frame - > Texture [ 0 ] ! = frame - > Texture [ 1 ] ) angle + = 180. / 16 ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2016-04-07 11:05:29 +00:00
angle + = players [ consoleplayer ] . camera - > Angles . Yaw - 90. ;
2016-03-01 15:47:10 +00:00
}
2016-03-25 20:54:59 +00:00
rotation = int ( ( angle . Normalized360 ( ) * ( 16. / 360. ) ) . Degrees ) ;
2016-03-01 15:47:10 +00:00
const FTextureID textureID = frame - > Texture [ show > 2 ? rotation : 0 ] ;
2018-12-07 01:53:18 +00:00
texture = TexMan . GetTexture ( textureID , true ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
if ( texture = = nullptr ) goto drawTriangle ; // fall back to standard display if no sprite can be found.
2016-03-01 15:47:10 +00:00
2016-05-18 19:25:58 +00:00
const double spriteXScale = ( t - > Scale . X * ( 10. / 16. ) * scale_mtof ) ;
const double spriteYScale = ( t - > Scale . Y * ( 10. / 16. ) * scale_mtof ) ;
2016-03-01 15:47:10 +00:00
DrawMarker ( texture , p . x , p . y , 0 , ! ! ( frame - > Flip & ( 1 < < rotation ) ) ,
2016-03-21 11:18:46 +00:00
spriteXScale , spriteYScale , t - > Translation , 1. , 0 , LegacyRenderStyles [ STYLE_Normal ] ) ;
2016-03-01 15:47:10 +00:00
}
else
{
drawTriangle :
2016-03-25 20:54:59 +00:00
angle = t - > Angles . Yaw ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & p . x , & p . y ) ;
2016-04-07 08:39:15 +00:00
angle + = - players [ consoleplayer ] . camera - > Angles . Yaw + 90. ;
2016-03-01 15:47:10 +00:00
}
color = AMColors [ AMColors . ThingColor ] ;
// use separate colors for special thing types
if ( t - > flags3 & MF3_ISMONSTER & & ! ( t - > flags & MF_CORPSE ) )
{
if ( t - > flags & MF_FRIENDLY ) color = AMColors [ AMColors . ThingColor_Friend ] ;
else if ( ! ( t - > flags & MF_COUNTKILL ) ) color = AMColors [ AMColors . ThingColor_NocountMonster ] ;
else color = AMColors [ AMColors . ThingColor_Monster ] ;
}
else if ( t - > flags & MF_SPECIAL )
{
// Find the key's own color.
// Only works correctly if single-key locks have lower numbers than any-key locks.
// That is the case for all default keys, however.
2017-02-08 14:47:22 +00:00
if ( t - > IsKindOf ( NAME_Key ) )
2016-03-01 15:47:10 +00:00
{
if ( G_SkillProperty ( SKILLP_EasyKey ) )
{
// Already drawn by AM_drawKeys(), so don't draw again
color . Index = - 1 ;
}
else if ( am_showkeys )
{
2018-12-04 16:00:48 +00:00
int c = P_GetMapColorForKey ( t ) ;
2016-03-01 15:47:10 +00:00
if ( c > = 0 ) color . FromRGB ( RPART ( c ) , GPART ( c ) , BPART ( c ) ) ;
else color = AMColors [ AMColors . ThingColor_CountItem ] ;
2019-01-26 14:21:20 +00:00
drawLineCharacter ( & CheatKey [ 0 ] , CheatKey . Size ( ) , 0 , 0. , color , p . x , p . y ) ;
2016-03-01 15:47:10 +00:00
color . Index = - 1 ;
}
else
{
color = AMColors [ AMColors . ThingColor_Item ] ;
}
}
else if ( t - > flags & MF_COUNTITEM )
color = AMColors [ AMColors . ThingColor_CountItem ] ;
else
color = AMColors [ AMColors . ThingColor_Item ] ;
}
if ( color . Index ! = - 1 )
{
2019-01-26 14:21:20 +00:00
drawLineCharacter ( thintriangle_guy . data ( ) , thintriangle_guy . size ( ) , 16 , angle , color , p . x , p . y ) ;
2016-03-01 15:47:10 +00:00
}
if ( am_cheat = = 3 | | am_cheat = = 6 )
{
static const mline_t box [ 4 ] =
{
2016-03-25 20:54:59 +00:00
{ { - 1 , - 1 } , { 1 , - 1 } } ,
{ { 1 , - 1 } , { 1 , 1 } } ,
{ { 1 , 1 } , { - 1 , 1 } } ,
{ { - 1 , 1 } , { - 1 , - 1 } } ,
2016-03-01 15:47:10 +00:00
} ;
2019-01-26 14:21:20 +00:00
drawLineCharacter ( box , 4 , t - > radius , angle - t - > Angles . Yaw , color , p . x , p . y ) ;
2016-03-01 15:47:10 +00:00
}
}
}
t = t - > snext ;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : DrawMarker ( FTexture * tex , double x , double y , int yadjust ,
2017-03-08 17:50:37 +00:00
INTBOOL flip , double xscale , double yscale , int translation , double alpha , uint32_t fillcolor , FRenderStyle renderstyle )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
if ( tex = = nullptr | | ! tex - > isValid ( ) )
2016-03-01 15:47:10 +00:00
{
return ;
}
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2019-01-26 14:21:20 +00:00
rotatePoint ( & x , & y ) ;
2016-03-01 15:47:10 +00:00
}
screen - > DrawTexture ( tex , CXMTOF ( x ) + f_x , CYMTOF ( y ) + yadjust + f_y ,
2018-12-06 00:11:04 +00:00
DTA_DestWidthF , tex - > GetDisplayWidthDouble ( ) * CleanXfac * xscale ,
DTA_DestHeightF , tex - > GetDisplayHeightDouble ( ) * CleanYfac * yscale ,
2016-03-01 15:47:10 +00:00
DTA_ClipTop , f_y ,
DTA_ClipBottom , f_y + f_h ,
DTA_ClipLeft , f_x ,
DTA_ClipRight , f_x + f_w ,
DTA_FlipX , flip ,
2017-02-04 22:26:28 +00:00
DTA_TranslationIndex , translation ,
2017-02-04 12:11:12 +00:00
DTA_Alpha , alpha ,
2016-03-01 15:47:10 +00:00
DTA_FillColor , fillcolor ,
2018-03-18 12:47:40 +00:00
DTA_RenderStyle , renderstyle . AsDWORD ,
2016-03-01 15:47:10 +00:00
TAG_DONE ) ;
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawMarks ( )
2016-03-01 15:47:10 +00:00
{
for ( int i = 0 ; i < AM_NUMMARKPOINTS ; i + + )
{
if ( markpoints [ i ] . x ! = - 1 )
{
2018-12-07 01:53:18 +00:00
DrawMarker ( TexMan . GetTexture ( marknums [ i ] , true ) , markpoints [ i ] . x , markpoints [ i ] . y , - 3 , 0 ,
2016-03-25 20:54:59 +00:00
1 , 1 , 0 , 1 , 0 , LegacyRenderStyles [ STYLE_Normal ] ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawAuthorMarkers ( )
2016-03-01 15:47:10 +00:00
{
// [RH] Draw any actors derived from AMapMarker on the automap.
// If args[0] is 0, then the actor's sprite is drawn at its own location.
// Otherwise, its sprite is drawn at the location of any actors whose TIDs match args[0].
2019-01-26 14:21:20 +00:00
auto it = Level - > GetThinkerIterator < AActor > ( NAME_MapMarker , STAT_MAPMARKER ) ;
2016-11-29 18:50:34 +00:00
AActor * mark ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
while ( ( mark = it . Next ( ) ) ! = nullptr )
2016-03-01 15:47:10 +00:00
{
if ( mark - > flags2 & MF2_DORMANT )
{
continue ;
}
FTextureID picnum ;
FTexture * tex ;
2017-03-08 17:50:37 +00:00
uint16_t flip = 0 ;
2016-03-01 15:47:10 +00:00
if ( mark - > picnum . isValid ( ) )
{
2018-12-07 01:53:18 +00:00
tex = TexMan . GetTexture ( mark - > picnum , true ) ;
2018-12-06 00:11:04 +00:00
if ( tex - > GetRotations ( ) ! = 0xFFFF )
2016-03-01 15:47:10 +00:00
{
2018-12-06 00:11:04 +00:00
spriteframe_t * sprframe = & SpriteFrames [ tex - > GetRotations ( ) ] ;
2016-03-01 15:47:10 +00:00
picnum = sprframe - > Texture [ 0 ] ;
flip = sprframe - > Flip & 1 ;
2018-12-07 02:01:40 +00:00
tex = TexMan . GetTexture ( picnum ) ;
2016-03-01 15:47:10 +00:00
}
}
else
{
spritedef_t * sprdef = & sprites [ mark - > sprite ] ;
if ( mark - > frame > = sprdef - > numframes )
{
continue ;
}
else
{
spriteframe_t * sprframe = & SpriteFrames [ sprdef - > spriteframes + mark - > frame ] ;
picnum = sprframe - > Texture [ 0 ] ;
flip = sprframe - > Flip & 1 ;
2018-12-07 02:01:40 +00:00
tex = TexMan . GetTexture ( picnum ) ;
2016-03-01 15:47:10 +00:00
}
}
2019-01-26 14:21:20 +00:00
auto it = Level - > GetActorIterator ( mark - > args [ 0 ] ) ;
2016-03-01 15:47:10 +00:00
AActor * marked = mark - > args [ 0 ] = = 0 ? mark : it . Next ( ) ;
2019-01-26 14:21:20 +00:00
while ( marked ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2018-12-20 17:40:19 +00:00
if ( mark - > args [ 1 ] = = 0 | | ( mark - > args [ 1 ] = = 1 & & ( marked - > subsector - > flags & SSECMF_DRAWN ) ) )
2016-03-01 15:47:10 +00:00
{
2016-05-18 19:25:58 +00:00
DrawMarker ( tex , marked - > X ( ) , marked - > Y ( ) , 0 , flip , mark - > Scale . X , mark - > Scale . Y , mark - > Translation ,
2016-03-21 11:18:46 +00:00
mark - > Alpha , mark - > fillcolor , mark - > RenderStyle ) ;
2016-03-01 15:47:10 +00:00
}
2019-01-26 14:21:20 +00:00
marked = mark - > args [ 0 ] ! = 0 ? it . Next ( ) : nullptr ;
2016-03-01 15:47:10 +00:00
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : drawCrosshair ( const AMColor & color )
2016-03-01 15:47:10 +00:00
{
screen - > DrawPixel ( f_w / 2 , ( f_h + 1 ) / 2 , color . Index , color . RGB ) ;
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void DAutomap : : Drawer ( int bottom )
2016-03-01 15:47:10 +00:00
{
if ( ! automapactive )
return ;
2019-01-26 14:21:20 +00:00
bool allmap = ( Level - > flags2 & LEVEL2_ALLMAP ) ! = 0 ;
2017-01-18 21:57:47 +00:00
bool allthings = allmap & & players [ consoleplayer ] . mo - > FindInventory ( NAME_PowerScanner , true ) ! = nullptr ;
2016-03-01 15:47:10 +00:00
2016-03-13 11:33:58 +00:00
if ( am_portaloverlay )
{
sector_t * sec ;
2016-03-25 20:54:59 +00:00
double vh = players [ consoleplayer ] . viewheight ;
2016-03-22 17:06:08 +00:00
players [ consoleplayer ] . camera - > GetPortalTransition ( vh , & sec ) ;
2016-03-13 11:33:58 +00:00
MapPortalGroup = sec - > PortalGroup ;
}
else MapPortalGroup = 0 ;
2016-03-01 15:47:10 +00:00
AM_initColors ( viewactive ) ;
if ( ! viewactive )
{
// [RH] Set f_? here now to handle automap overlaying
// and view size adjustments.
f_x = f_y = 0 ;
f_w = screen - > GetWidth ( ) ;
2017-03-30 16:51:24 +00:00
f_h = bottom ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
clearFB ( AMColors [ AMColors . Background ] ) ;
2016-03-01 15:47:10 +00:00
}
else
{
f_x = viewwindowx ;
f_y = viewwindowy ;
f_w = viewwidth ;
f_h = viewheight ;
}
2019-01-26 14:21:20 +00:00
activateNewScale ( ) ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
if ( am_textured & & ! viewactive )
drawSubsectors ( ) ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
if ( am_showgrid )
drawGrid ( AMColors . GridColor ) ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
drawWalls ( allmap ) ;
drawPlayers ( ) ;
2016-03-01 15:47:10 +00:00
if ( G_SkillProperty ( SKILLP_EasyKey ) )
2019-01-26 14:21:20 +00:00
drawKeys ( ) ;
2016-03-01 15:47:10 +00:00
if ( ( am_cheat > = 2 & & am_cheat ! = 4 ) | | allthings )
2019-01-26 14:21:20 +00:00
drawThings ( ) ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
drawAuthorMarkers ( ) ;
2016-03-01 15:47:10 +00:00
if ( ! viewactive )
2019-01-26 14:21:20 +00:00
drawCrosshair ( AMColors [ AMColors . XHairColor ] ) ;
drawMarks ( ) ;
showSS ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void DAutomap : : Serialize ( FSerializer & arc )
{
// This only stores those variables which do not get set each time the automap is either activated or drawn.
// Especially the screen coordinates can not be brought over because the display settings may have changed.
arc ( " markpointnum " , markpointnum )
. Array ( " markpoints " , & markpoints [ 0 ] . x , AM_NUMMARKPOINTS * 2 ) // write as a double array.
( " scale_mtof " , scale_mtof )
( " scale_ftom " , scale_ftom )
( " bigstate " , bigstate )
( " min_x " , min_x )
( " min_y " , min_y )
( " max_x " , max_x )
( " max_y " , max_y )
( " min_w " , min_w )
( " min_h " , min_h )
( " max_w " , max_w )
( " max_h " , max_h )
( " min_scale_mtof " , min_scale_mtof )
( " max_scale_mtof " , max_scale_mtof )
( " mapback " , mapback ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void DAutomap : : UpdateShowAllLines ( )
{
int val = am_showalllines ;
int flagged = 0 ;
int total = 0 ;
if ( val > 0 & & Level - > lines . Size ( ) > 0 )
{
for ( auto & line : Level - > lines )
{
// disregard intra-sector lines
if ( line . frontsector = = line . backsector ) continue ;
// disregard control sectors for deep water
if ( line . frontsector - > e - > FakeFloor . Sectors . Size ( ) > 0 ) continue ;
// disregard control sectors for 3D-floors
if ( line . frontsector - > e - > XFloor . attached . Size ( ) > 0 ) continue ;
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
total + + ;
if ( line . flags & ML_DONTDRAW ) flagged + + ;
}
am_showallenabled = ( flagged * 100 / total > = val ) ;
}
else if ( val = = 0 )
{
am_showallenabled = true ;
}
else
{
am_showallenabled = false ;
}
}
void DAutomap : : GoBig ( )
{
bigstate = ! bigstate ;
if ( bigstate )
{
saveScaleAndLoc ( ) ;
minOutWindowScale ( ) ;
}
else
restoreScaleAndLoc ( ) ;
}
void DAutomap : : ResetFollowLocation ( )
{
f_oldloc . x = FLT_MAX ;
}
2016-03-01 15:47:10 +00:00
2019-01-26 14:21:20 +00:00
//=============================================================================
//
//
//
//=============================================================================
void AM_Stop ( )
{
automapactive = false ;
viewactive = true ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
2019-01-26 14:21:20 +00:00
void AM_ToggleMap ( )
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
if ( gamestate ! = GS_LEVEL )
return ;
// Don't activate the automap if we're not allowed to use it.
if ( dmflags2 & DF2_NO_AUTOMAP )
return ;
// ... or if there is no automap.
if ( ! currentUILevel | | ! currentUILevel - > automap )
return ;
if ( ! automapactive )
{
// Reset AM buttons
Button_AM_PanLeft . Reset ( ) ;
Button_AM_PanRight . Reset ( ) ;
Button_AM_PanUp . Reset ( ) ;
Button_AM_PanDown . Reset ( ) ;
Button_AM_ZoomIn . Reset ( ) ;
Button_AM_ZoomOut . Reset ( ) ;
currentUILevel - > automap - > startDisplay ( ) ;
automapactive = true ;
viewactive = ( am_overlay ! = 0.f ) ;
}
else
2016-03-01 15:47:10 +00:00
{
2019-01-26 14:21:20 +00:00
if ( am_overlay = = 1 & & viewactive )
{
viewactive = false ;
}
else
{
AM_Stop ( ) ;
}
2016-03-01 15:47:10 +00:00
}
}
2019-01-26 14:21:20 +00:00
//=============================================================================
//
//
//
//=============================================================================
DAutomapBase * AM_Create ( FLevelLocals * Level )
{
auto am = Create < DAutomap > ( ) ;
am - > Level = Level ;
return am ;
}