2016-03-01 15:47:10 +00:00
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
//
// $Log:$
//
// DESCRIPTION: the automap code
//
//-----------------------------------------------------------------------------
# include <stdio.h>
# include "doomdef.h"
# include "templates.h"
# include "g_level.h"
# include "doomdef.h"
# include "st_stuff.h"
# include "p_local.h"
# include "p_lnspec.h"
# include "w_wad.h"
# include "a_sharedglobal.h"
# include "statnums.h"
# include "r_data/r_translate.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 "i_system.h"
# include "c_dispatch.h"
# include "colormatcher.h"
# include "d_netinf.h"
// Needs access to LFB.
# include "v_video.h"
# include "v_palette.h"
# include "v_text.h"
// State.
# include "doomstat.h"
# include "r_state.h"
# include "r_utility.h"
// Data.
# include "gstrings.h"
# include "am_map.h"
# include "po_man.h"
# include "a_keys.h"
# include "r_data/colormaps.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2016-03-01 15:47:10 +00:00
//=============================================================================
//
// CVARs
//
//=============================================================================
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 ( Bool , am_showtriggerlines , false , CVAR_ARCHIVE ) ;
CVAR ( Int , am_showthingsprites , 0 , CVAR_ARCHIVE ) ;
//=============================================================================
//
// 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 ) ;
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 ) ;
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 ;
uint32 RGB ;
void FromCVar ( FColorCVar & cv )
{
Index = cv . GetIndex ( ) ;
RGB = uint32 ( cv ) | MAKEARGB ( 255 , 0 , 0 , 0 ) ;
}
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 " ,
2016-03-13 11:33:58 +00:00
" PortalColor " ,
2016-03-01 15:47:10 +00:00
" AlmostBackgroundColor " ,
NULL
} ;
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 ,
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 ] ) ;
}
DWORD ba = * ( values [ 0 ] ) ;
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 ( ) ;
}
} ;
//=============================================================================
//
// 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 ,
& 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 ,
& 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
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
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
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 ;
}
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 ;
for ( i = 0 ; ColorNames [ i ] ! = NULL ; i + + )
{
if ( nextKey . CompareNoCase ( ColorNames [ i ] ) = = 0 )
{
sc . MustGetToken ( TK_StringConst ) ;
FString color = sc . String ;
FString colorName = V_GetColorStringByName ( color ) ;
if ( ! colorName . IsEmpty ( ) ) color = colorName ;
int colorval = V_GetColorFromString ( NULL , color ) ;
cset . c [ i ] . FromRGB ( RPART ( colorval ) , GPART ( colorval ) , BPART ( colorval ) ) ;
colorset = true ;
break ;
}
}
if ( ColorNames [ i ] = = NULL )
{
sc . ScriptError ( " Unknown key '%s' " , nextKey . GetChars ( ) ) ;
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
// scale on entry
2016-03-25 20:54:59 +00:00
# define INITSCALEMTOF .2
2016-03-01 15:47:10 +00:00
// used by MTOF to scale from map-to-frame-buffer coords
2016-03-25 20:54:59 +00:00
static double scale_mtof = INITSCALEMTOF ;
2016-03-01 15:47:10 +00:00
// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
2016-03-25 20:54:59 +00:00
static double scale_ftom ;
2016-03-01 15:47:10 +00:00
// translates between frame-buffer and map distances
2016-03-25 20:54:59 +00:00
inline double FTOM ( double x )
2016-03-01 15:47:10 +00:00
{
return x * scale_ftom ;
}
2016-03-25 20:54:59 +00:00
inline double MTOF ( double x )
2016-03-01 15:47:10 +00:00
{
2016-03-25 20:54:59 +00:00
return x * scale_mtof ;
2016-03-01 15:47:10 +00:00
}
static int bigstate = 0 ;
static bool textured = 1 ; // internal toggle for texture mode
2016-03-13 11:33:58 +00:00
static int MapPortalGroup ;
2016-03-01 15:47:10 +00:00
CUSTOM_CVAR ( Bool , am_textured , false , CVAR_ARCHIVE )
{
textured | = self ;
}
CVAR ( Int , am_showsubsector , - 1 , 0 ) ;
// 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 ;
CUSTOM_CVAR ( Int , am_showalllines , - 1 , 0 ) // This is a cheat so don't save it.
{
int flagged = 0 ;
int total = 0 ;
2017-01-08 13:39:16 +00:00
if ( self > 0 & & level . lines . Size ( ) > 0 )
2016-03-01 15:47:10 +00:00
{
2017-01-08 13:39:16 +00:00
for ( auto & line : level . lines )
2016-03-01 15:47:10 +00:00
{
// disregard intra-sector lines
2017-01-08 13:39:16 +00:00
if ( line . frontsector = = line . backsector ) continue ;
2016-03-01 15:47:10 +00:00
// disregard control sectors for deep water
2017-01-08 13:39:16 +00:00
if ( line . frontsector - > e - > FakeFloor . Sectors . Size ( ) > 0 ) continue ;
2016-03-01 15:47:10 +00:00
// disregard control sectors for 3D-floors
2017-01-08 13:39:16 +00:00
if ( line . frontsector - > e - > XFloor . attached . Size ( ) > 0 ) continue ;
2016-03-01 15:47:10 +00:00
total + + ;
2017-01-08 13:39:16 +00:00
if ( line . flags & ML_DONTDRAW ) flagged + + ;
2016-03-01 15:47:10 +00:00
}
am_showallenabled = ( flagged * 100 / total > = self ) ;
}
else if ( self = = 0 )
{
am_showallenabled = true ;
}
else
{
am_showallenabled = false ;
}
}
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 ;
}
}
# define AM_NUMMARKPOINTS 10
2016-03-25 17:19:54 +00:00
// player radius for automap checking
2016-03-25 20:54:59 +00:00
# define PLAYERRADIUS 16.
2016-03-01 15:47:10 +00:00
// how much the automap moves window per tic in frame-buffer coordinates
// moves 140 pixels at 320x200 in 1 second
# define F_PANINC (140 / TICRATE)
// how much zoom-in per tic
// goes to 2x in 1 second
2016-03-25 20:54:59 +00:00
# define M_ZOOMIN (1.02)
2016-03-01 15:47:10 +00:00
// how much zoom-out per tic
// pulls out to 0.5x in 1 second
2016-03-25 20:54:59 +00:00
# define M_ZOOMOUT (1 / 1.02)
2016-03-01 15:47:10 +00:00
// translates between frame-buffer and map coordinates
2016-03-25 20:54:59 +00:00
# define CXMTOF(x) int(MTOF((x)-m_x) /* - f_x*/ )
# define CYMTOF(y) int(f_h - MTOF((y)-m_y) /* + f_y*/ )
2016-03-01 15:47:10 +00:00
struct fpoint_t
{
int x , y ;
} ;
struct fline_t
{
fpoint_t a , b ;
} ;
struct mpoint_t
{
2016-03-25 20:54:59 +00:00
double x , y ;
2016-03-01 15:47:10 +00:00
} ;
struct mline_t
{
mpoint_t a , b ;
} ;
struct islope_t
{
2016-03-25 20:54:59 +00:00
double slp , islp ;
2016-03-01 15:47:10 +00:00
} ;
//=============================================================================
//
// 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 ;
2016-03-25 20:54:59 +00:00
# define L(a,b,c,d) { {(a), (b)}, {(c), (d)} }
2016-03-01 15:47:10 +00:00
static mline_t triangle_guy [ ] = {
L ( - .867 , - .5 , .867 , - .5 ) ,
L ( .867 , - .5 , 0 , 1 ) ,
L ( 0 , 1 , - .867 , - .5 )
} ;
# define NUMTRIANGLEGUYLINES (sizeof(triangle_guy) / sizeof(mline_t))
static mline_t thintriangle_guy [ ] = {
L ( - .5 , - .7 , 1 , 0 ) ,
L ( 1 , 0 , - .5 , .7 ) ,
L ( - .5 , .7 , - .5 , - .7 )
} ;
# define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy) / sizeof(mline_t))
static mline_t square_guy [ ] = {
L ( 0 , 1 , 1 , 0 ) ,
L ( 1 , 0 , 0 , - 1 ) ,
L ( 0 , - 1 , - 1 , 0 ) ,
L ( - 1 , 0 , 0 , 1 )
} ;
# define NUMSQUAREGUYLINES (sizeof(square_guy) / sizeof(mline_t))
//=============================================================================
//
//
//
//=============================================================================
static int grid = 0 ;
bool automapactive = false ;
// location of window on screen
static int f_x ;
static int f_y ;
// size of window on screen
static int f_w ;
static int f_h ;
static int f_p ; // [RH] # of bytes from start of a line to start of next
static int amclock ;
static mpoint_t m_paninc ; // how far the window pans each tic (map coords)
2016-03-25 20:54:59 +00:00
static double mtof_zoommul ; // how far the window zooms in each tic (map coords)
static double am_zoomdir ;
2016-03-01 15:47:10 +00:00
2016-03-25 20:54:59 +00:00
static double m_x , m_y ; // LL x,y where the window is on the map (map coords)
static double m_x2 , m_y2 ; // UR x,y where the window is on the map (map coords)
2016-03-01 15:47:10 +00:00
//
// width/height of window on map (map coords)
//
2016-03-25 20:54:59 +00:00
static double m_w ;
static double m_h ;
2016-03-01 15:47:10 +00:00
// based on level size
2016-03-25 20:54:59 +00:00
static double min_x , min_y , max_x , max_y ;
2016-03-01 15:47:10 +00:00
2016-03-25 20:54:59 +00:00
static double max_w ; // max_x-min_x,
static double max_h ; // max_y-min_y
2016-03-01 15:47:10 +00:00
// based on player size
2016-03-25 20:54:59 +00:00
static double min_w ;
static double min_h ;
2016-03-01 15:47:10 +00:00
2016-03-25 20:54:59 +00:00
static double min_scale_mtof ; // used to tell when to stop zooming out
static double max_scale_mtof ; // used to tell when to stop zooming in
2016-03-01 15:47:10 +00:00
// old stuff for recovery later
2016-03-25 20:54:59 +00:00
static double old_m_w , old_m_h ;
static double old_m_x , old_m_y ;
2016-03-01 15:47:10 +00:00
// old location used by the Follower routine
static mpoint_t f_oldloc ;
static FTextureID marknums [ 10 ] ; // numbers used for marking by the automap
static mpoint_t markpoints [ AM_NUMMARKPOINTS ] ; // where the points are
static int markpointnum = 0 ; // next point to be assigned
static FTextureID mapback ; // the automap background
2016-03-25 20:54:59 +00:00
static double mapystart = 0 ; // y-value for the start of the map bitmap...used in the parallax stuff.
static double mapxstart = 0 ; //x-value for the bitmap.
2016-03-01 15:47:10 +00:00
static bool stopped = true ;
static void AM_calcMinMaxMtoF ( ) ;
2016-03-25 20:54:59 +00:00
static void DrawMarker ( FTexture * tex , double x , double y , int yadjust ,
INTBOOL flip , double xscale , double yscale , int translation , double alpha , DWORD fillcolor , FRenderStyle renderstyle ) ;
2016-03-01 15:47:10 +00:00
2016-03-25 20:54:59 +00:00
void AM_rotatePoint ( double * x , double * y ) ;
void AM_rotate ( double * x , double * y , DAngle an ) ;
2016-03-01 15:47:10 +00:00
void AM_doFollowPlayer ( ) ;
//=============================================================================
//
// map functions
//
//=============================================================================
2016-03-25 20:54:59 +00:00
2016-03-01 15:47:10 +00:00
bool AM_addMark ( ) ;
bool AM_clearMarks ( ) ;
void AM_saveScaleAndLoc ( ) ;
void AM_restoreScaleAndLoc ( ) ;
void AM_minOutWindowScale ( ) ;
CVAR ( Bool , am_followplayer , true , CVAR_ARCHIVE )
2016-03-13 11:33:58 +00:00
CVAR ( Bool , am_portaloverlay , true , CVAR_ARCHIVE )
2016-03-01 15:47:10 +00:00
CCMD ( am_togglefollow )
{
am_followplayer = ! am_followplayer ;
2016-03-25 23:34:56 +00:00
f_oldloc . x = FLT_MAX ;
2016-03-01 15:47:10 +00:00
Printf ( " %s \n " , GStrings ( am_followplayer ? " AMSTR_FOLLOWON " : " AMSTR_FOLLOWOFF " ) ) ;
}
CCMD ( am_togglegrid )
{
grid = ! grid ;
Printf ( " %s \n " , GStrings ( grid ? " AMSTR_GRIDON " : " AMSTR_GRIDOFF " ) ) ;
}
CCMD ( am_toggletexture )
{
if ( am_textured & & hasglnodes )
{
textured = ! textured ;
Printf ( " %s \n " , GStrings ( textured ? " AMSTR_TEXON " : " AMSTR_TEXOFF " ) ) ;
}
}
CCMD ( am_setmark )
{
if ( AM_addMark ( ) )
{
Printf ( " %s %d \n " , GStrings ( " AMSTR_MARKEDSPOT " ) , markpointnum ) ;
}
}
CCMD ( am_clearmarks )
{
if ( AM_clearMarks ( ) )
{
Printf ( " %s \n " , GStrings ( " AMSTR_MARKSCLEARED " ) ) ;
}
}
CCMD ( am_gobig )
{
bigstate = ! bigstate ;
if ( bigstate )
{
AM_saveScaleAndLoc ( ) ;
AM_minOutWindowScale ( ) ;
}
else
AM_restoreScaleAndLoc ( ) ;
}
2016-03-25 20:54:59 +00:00
//=============================================================================
//
// vector graphics
//
//=============================================================================
2016-03-01 15:47:10 +00:00
void AM_ParseArrow ( TArray < mline_t > & Arrow , const char * lumpname )
{
2016-03-25 20:54:59 +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 ) ;
}
}
}
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 < 10 ; i + + )
{
mysnprintf ( namebuf , countof ( namebuf ) , " AMMNUM%d " , i ) ;
marknums [ i ] = TexMan . CheckForTexture ( namebuf , FTexture : : TEX_MiscPatch ) ;
}
markpointnum = 0 ;
mapback . SetInvalid ( ) ;
}
//=============================================================================
//
// called by the coordinate drawer
//
//=============================================================================
2016-03-24 00:46:11 +00:00
DVector2 AM_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
}
//=============================================================================
//
//
//
//=============================================================================
void AM_activateNewScale ( )
{
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 ;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_saveScaleAndLoc ( )
{
old_m_x = m_x ;
old_m_y = m_y ;
old_m_w = m_w ;
old_m_h = m_h ;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_restoreScaleAndLoc ( )
{
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
//
//=============================================================================
bool AM_addMark ( )
{
if ( marknums [ 0 ] . isValid ( ) )
{
markpoints [ markpointnum ] . x = m_x + m_w / 2 ;
markpoints [ markpointnum ] . y = m_y + m_h / 2 ;
markpointnum = ( markpointnum + 1 ) % AM_NUMMARKPOINTS ;
return true ;
}
return false ;
}
//=============================================================================
//
// Determines bounding box of all vertices,
// sets global variables controlling zoom range.
//
//=============================================================================
static void AM_findMinMaxBoundaries ( )
{
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 ;
2017-01-08 23:46:16 +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 ;
AM_calcMinMaxMtoF ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
static void AM_calcMinMaxMtoF ( )
{
2016-03-25 20:54:59 +00:00
double a = SCREENWIDTH / max_w ;
2017-01-20 09:51:21 +00:00
double b = gST_Y / 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
}
//=============================================================================
//
//
//
//=============================================================================
2016-03-25 20:54:59 +00:00
static void AM_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 ;
}
else
{
#if 0
2016-03-25 20:54:59 +00:00
double rmin_x , rmin_y , rmax_x , rmax_y ;
double xs [ 5 ] , ys [ 5 ] ;
2016-03-01 15:47:10 +00:00
int i ;
xs [ 0 ] = min_x ; ys [ 0 ] = min_y ;
xs [ 1 ] = max_x ; ys [ 1 ] = min_y ;
xs [ 2 ] = max_x ; ys [ 2 ] = max_y ;
xs [ 3 ] = min_x ; ys [ 3 ] = max_y ;
xs [ 4 ] = m_x + m_w / 2 ; ys [ 4 ] = m_y + m_h / 2 ;
2016-03-25 23:34:56 +00:00
rmin_x = rmin_y = FLT_MAX ;
2016-03-01 15:47:10 +00:00
rmax_x = rmax_y = FIXED_MIN ;
for ( i = 0 ; i < 5 ; + + i )
{
xs [ i ] - = pivotx ;
ys [ i ] - = pivoty ;
2016-03-25 20:54:59 +00:00
AM_rotate ( & xs [ i ] , & ys [ i ] , 90. - players [ consoleplayer ] . camera - > Angles . Yaw ) ;
2016-03-01 15:47:10 +00:00
if ( i = = 5 )
break ;
// xs[i] += pivotx;
// ys[i] += pivoty;
if ( xs [ i ] < rmin_x ) rmin_x = xs [ i ] ;
if ( xs [ i ] > rmax_x ) rmax_x = xs [ i ] ;
if ( ys [ i ] < rmin_y ) rmin_y = ys [ i ] ;
if ( ys [ i ] > rmax_y ) rmax_y = ys [ i ] ;
}
if ( rmax_x < 0 )
xs [ 4 ] = - rmax_x ;
else if ( rmin_x > 0 )
xs [ 4 ] = - rmin_x ;
// if (ys[4] > rmax_y)
// ys[4] = rmax_y;
// else if (ys[4] < rmin_y)
// ys[4] = rmin_y;
2016-03-25 20:54:59 +00:00
AM_rotate ( & xs [ 4 ] , & ys [ 4 ] , 270. - players [ consoleplayer ] . camera - > Angles . Yaw ) ;
2016-03-01 15:47:10 +00:00
m_x = xs [ 4 ] + pivotx - m_w / 2 ;
m_y = ys [ 4 ] + pivoty - m_h / 2 ;
# endif
}
m_x2 = m_x + m_w ;
m_y2 = m_y + m_h ;
}
//=============================================================================
//
//
//
//=============================================================================
2016-03-25 20:54:59 +00:00
static void AM_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 ( ) )
{
FTexture * backtex = TexMan [ mapback ] ;
if ( backtex ! = NULL )
{
2016-03-25 20:54:59 +00:00
int pwidth = backtex - > GetWidth ( ) ;
int pheight = backtex - > GetHeight ( ) ;
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 ;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_changeWindowLoc ( )
{
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 ) )
{
2016-04-07 11:05:29 +00:00
AM_rotate ( & incx , & incy , players [ consoleplayer ] . camera - > Angles . Yaw - 90. ) ;
2016-03-01 15:47:10 +00:00
}
m_x + = incx ;
m_y + = incy ;
AM_ClipRotatedExtents ( oldmx + m_w / 2 , oldmy + m_h / 2 ) ;
AM_ScrollParchment ( m_x ! = oldmx ? oincx : 0 , m_y ! = oldmy ? - oincy : 0 ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_initVariables ( )
{
int pnum ;
automapactive = true ;
// 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 ( ) ;
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 ;
2016-03-01 15:47:10 +00:00
AM_changeWindowLoc ( ) ;
// for saving & restoring
old_m_x = m_x ;
old_m_y = m_y ;
old_m_w = m_w ;
old_m_h = m_h ;
}
//=============================================================================
//
//
//
//=============================================================================
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 ;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool AM_clearMarks ( )
{
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
//
//=============================================================================
void AM_LevelInit ( )
{
if ( level . info - > MapBackground . Len ( ) = = 0 )
{
mapback = TexMan . CheckForTexture ( " AUTOPAGE " , FTexture : : TEX_MiscPatch ) ;
}
else
{
mapback = TexMan . CheckForTexture ( level . info - > MapBackground , FTexture : : TEX_MiscPatch ) ;
}
AM_clearMarks ( ) ;
AM_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
am_showalllines . Callback ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_Stop ( )
{
automapactive = false ;
stopped = true ;
V_SetBorderNeedRefresh ( ) ;
viewactive = true ;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_Start ( )
{
if ( ! stopped ) AM_Stop ( ) ;
stopped = false ;
AM_initVariables ( ) ;
}
//=============================================================================
//
// set the window scale to the maximum size
//
//=============================================================================
void AM_minOutWindowScale ( )
{
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
//
//=============================================================================
void AM_maxOutWindowScale ( )
{
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
//
//=============================================================================
void AM_NewResolution ( )
{
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!
}
AM_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 )
AM_minOutWindowScale ( ) ;
else if ( scale_mtof > max_scale_mtof )
AM_maxOutWindowScale ( ) ;
f_w = screen - > GetWidth ( ) ;
2017-01-20 09:51:21 +00:00
f_h = gST_Y ;
2016-03-01 15:47:10 +00:00
AM_activateNewScale ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
CCMD ( togglemap )
{
if ( gameaction = = ga_nothing )
{
gameaction = ga_togglemap ;
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_ToggleMap ( )
{
if ( gamestate ! = GS_LEVEL )
return ;
// Don't activate the automap if we're not allowed to use it.
if ( dmflags2 & DF2_NO_AUTOMAP )
return ;
ST_SetNeedRefresh ( ) ;
if ( ! automapactive )
{
AM_Start ( ) ;
viewactive = ( am_overlay ! = 0.f ) ;
}
else
{
if ( am_overlay = = 1 & & viewactive )
{
viewactive = false ;
ST_SetNeedRefresh ( ) ;
}
else
{
AM_Stop ( ) ;
}
}
}
//=============================================================================
//
// Handle events (user inputs) in automap mode
//
//=============================================================================
bool AM_Responder ( event_t * ev , bool last )
{
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 ;
}
bool res = C_DoKey ( ev , & AutomapBindings , NULL ) ;
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
//
//=============================================================================
void AM_changeWindowScale ( )
{
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 )
AM_minOutWindowScale ( ) ;
else if ( scale_mtof > max_scale_mtof )
AM_maxOutWindowScale ( ) ;
}
CCMD ( am_zoom )
{
if ( argv . argc ( ) > = 2 )
{
2016-03-25 20:54:59 +00:00
am_zoomdir = atof ( argv [ 1 ] ) ;
2016-03-01 15:47:10 +00:00
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_doFollowPlayer ( )
{
2016-03-25 20:54:59 +00:00
double sx , sy ;
2016-03-01 15:47:10 +00:00
if ( players [ consoleplayer ] . camera ! = NULL & &
2016-03-25 20:54:59 +00:00
( f_oldloc . x ! = players [ consoleplayer ] . camera - > X ( ) | |
f_oldloc . y ! = players [ consoleplayer ] . camera - > Y ( ) ) )
2016-03-01 15:47:10 +00:00
{
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 ;
// do the parallax parchment scrolling.
2016-03-25 20:54:59 +00:00
sx = ( players [ consoleplayer ] . camera - > X ( ) - f_oldloc . x ) ;
sy = ( f_oldloc . y - players [ consoleplayer ] . camera - > Y ( ) ) ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
2016-04-07 11:05:29 +00:00
AM_rotate ( & sx , & sy , players [ consoleplayer ] . camera - > Angles . Yaw - 90 ) ;
2016-03-01 15:47:10 +00:00
}
AM_ScrollParchment ( sx , sy ) ;
2016-03-25 20:54:59 +00:00
f_oldloc . x = players [ consoleplayer ] . camera - > X ( ) ;
f_oldloc . y = players [ consoleplayer ] . camera - > Y ( ) ;
2016-03-01 15:47:10 +00:00
}
}
//=============================================================================
//
// Updates on Game Tick
//
//=============================================================================
void AM_Ticker ( )
{
if ( ! automapactive )
return ;
amclock + + ;
if ( am_followplayer )
{
AM_doFollowPlayer ( ) ;
}
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 )
AM_changeWindowScale ( ) ;
// Change x,y location
//if (m_paninc.x || m_paninc.y)
AM_changeWindowLoc ( ) ;
}
//=============================================================================
//
// Clear automap frame buffer.
//
//=============================================================================
void AM_clearFB ( const AMColor & color )
{
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
{
FTexture * backtex = TexMan [ mapback ] ;
if ( backtex ! = NULL )
{
int pwidth = backtex - > GetWidth ( ) ;
int pheight = backtex - > GetHeight ( ) ;
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.
//
//=============================================================================
bool AM_clipMline ( mline_t * ml , fline_t * fl )
{
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 ;
# define DOOUTCODE(oc, mx, 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 ;
// 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 ;
}
# undef DOOUTCODE
//=============================================================================
//
// Clip lines, draw visible parts of lines.
//
//=============================================================================
void AM_drawMline ( mline_t * ml , const AMColor & color )
{
fline_t fl ;
if ( AM_clipMline ( ml , & fl ) )
{
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 ) ;
}
}
inline void AM_drawMline ( mline_t * ml , int colorindex )
{
AM_drawMline ( ml , AMColors [ colorindex ] ) ;
}
//=============================================================================
//
// Draws flat (floor/ceiling tile) aligned grid lines.
//
//=============================================================================
void AM_drawGrid ( int color )
{
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 ;
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 ;
2016-03-31 07:23:14 +00:00
start = ceil ( ( start - bmaporgx ) / MAPBLOCKUNITS ) * 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
2016-03-25 20:54:59 +00:00
for ( x = start ; x < end ; x + = 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 ) )
{
AM_rotatePoint ( & ml . a . x , & ml . a . y ) ;
AM_rotatePoint ( & ml . b . x , & ml . b . y ) ;
}
AM_drawMline ( & ml , color ) ;
}
// Figure out start of horizontal gridlines
start = miny - exty ;
2016-03-31 07:23:14 +00:00
start = ceil ( ( start - bmaporgy ) / MAPBLOCKUNITS ) * MAPBLOCKUNITS + bmaporgy ;
2016-03-01 15:47:10 +00:00
end = miny + minlen - exty ;
// draw horizontal gridlines
2016-03-25 20:54:59 +00:00
for ( y = start ; y < end ; y + = 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 ) )
{
AM_rotatePoint ( & ml . a . x , & ml . a . y ) ;
AM_rotatePoint ( & ml . b . x , & ml . b . y ) ;
}
AM_drawMline ( & ml , color ) ;
}
}
//=============================================================================
//
// AM_drawSubsectors
//
//=============================================================================
void AM_drawSubsectors ( )
{
static TArray < FVector2 > points ;
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 ;
int floorlight , ceilinglight ;
2016-03-25 20:54:59 +00:00
double scalex , scaley ;
2016-03-01 15:47:10 +00:00
double originx , originy ;
FDynamicColormap * colormap ;
2017-01-28 19:44:46 +00:00
PalEntry flatcolor ;
2016-03-01 15:47:10 +00:00
mpoint_t originpt ;
2016-08-06 17:20:41 +00:00
screen - > StartSimplePolys ( ) ;
2016-03-01 15:47:10 +00:00
for ( int i = 0 ; i < numsubsectors ; + + i )
{
if ( subsectors [ i ] . flags & SSECF_POLYORG )
{
continue ;
}
if ( ( ! ( subsectors [ i ] . flags & SSECF_DRAWN ) | | ( subsectors [ i ] . render_sector - > MoreFlags & SECF_HIDDEN ) ) & & am_cheat = = 0 )
{
continue ;
}
2016-03-13 11:33:58 +00:00
if ( am_portaloverlay & & subsectors [ i ] . render_sector - > PortalGroup ! = MapPortalGroup & & subsectors [ i ] . render_sector - > PortalGroup ! = 0 )
{
continue ;
}
2016-03-01 15:47:10 +00:00
// Fill the points array from the subsector.
points . Resize ( subsectors [ i ] . numlines ) ;
for ( DWORD j = 0 ; j < subsectors [ i ] . numlines ; + + j )
{
2016-03-25 20:54:59 +00:00
mpoint_t pt = { subsectors [ i ] . firstline [ j ] . v1 - > fX ( ) ,
subsectors [ i ] . firstline [ j ] . v1 - > fY ( ) } ;
2016-03-01 15:47:10 +00:00
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
AM_rotatePoint ( & pt . x , & pt . y ) ;
}
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
2016-03-30 22:41:21 +00:00
sector_t * sec = Renderer - > FakeFlat ( subsectors [ i ] . render_sector , & tempsec , & floorlight , & ceilinglight , false ) ;
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
colormap = sec - > ColorMap ;
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 ;
2016-04-01 10:22:16 +00:00
double cmpz = ViewPos . 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.
2016-04-01 10:22:16 +00:00
secx = ViewPos . X ;
secy = ViewPos . 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 ;
if ( rover - > flags & FF_FOG ) continue ;
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 )
{
AM_rotate ( & originpt . x , & originpt . y , rotation ) ;
}
// 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 ;
2016-03-01 15:47:10 +00:00
AM_rotatePoint ( & originpt . x , & originpt . y ) ;
}
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.
if ( ! ( subsectors [ i ] . flags & SSECF_DRAWN ) )
{
colormap = GetSpecialLights (
MAKERGB (
( colormap - > Color . r + 255 ) / 2 ,
( colormap - > Color . g + 200 ) / 2 ,
( colormap - > Color . b + 160 ) / 2 ) ,
colormap - > Fade ,
255 - ( 255 - colormap - > Desaturate ) / 4 ) ;
2016-03-30 22:41:21 +00:00
floorlight = ( floorlight + 200 * 15 ) / 16 ;
2016-03-01 15:47:10 +00:00
}
// Draw the polygon.
FTexture * pic = TexMan ( maptex ) ;
if ( pic ! = NULL & & pic - > UseType ! = FTexture : : TEX_Null )
{
screen - > FillSimplePoly ( TexMan ( maptex ) ,
& 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 ,
f_y + f_h
2016-03-01 15:47:10 +00:00
) ;
}
}
2016-08-06 17:20:41 +00:00
screen - > FinishSimplePolys ( ) ;
2016-03-01 15:47:10 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
static bool AM_CheckSecret ( line_t * line )
{
if ( AMColors . isValid ( AMColors . SecretSectorColor ) )
{
if ( line - > frontsector ! = NULL )
{
if ( line - > frontsector - > wasSecret ( ) )
{
if ( am_map_secrets ! = 0 & & ! line - > frontsector - > isSecret ( ) ) return true ;
if ( am_map_secrets = = 2 & & ! ( line - > flags & ML_SECRET ) ) return true ;
}
}
if ( line - > backsector ! = NULL )
{
if ( line - > backsector - > wasSecret ( ) )
{
if ( am_map_secrets ! = 0 & & ! line - > backsector - > isSecret ( ) ) return true ;
if ( am_map_secrets = = 2 & & ! ( line - > flags & ML_SECRET ) ) return true ;
}
}
}
return false ;
}
//=============================================================================
//
// Polyobject debug stuff
//
//=============================================================================
void AM_drawSeg ( seg_t * seg , const AMColor & color )
{
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 ) )
{
AM_rotatePoint ( & l . a . x , & l . a . y ) ;
AM_rotatePoint ( & l . b . x , & l . b . y ) ;
}
AM_drawMline ( & l , color ) ;
}
void AM_drawPolySeg ( FPolySeg * seg , const AMColor & color )
{
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 ) )
{
AM_rotatePoint ( & l . a . x , & l . a . y ) ;
AM_rotatePoint ( & l . b . x , & l . b . y ) ;
}
AM_drawMline ( & l , color ) ;
}
void AM_showSS ( )
{
if ( am_showsubsector > = 0 & & am_showsubsector < numsubsectors )
{
AMColor yellow ;
yellow . FromRGB ( 255 , 255 , 0 ) ;
AMColor red ;
red . FromRGB ( 255 , 0 , 0 ) ;
subsector_t * sub = & subsectors [ am_showsubsector ] ;
for ( unsigned int i = 0 ; i < sub - > numlines ; i + + )
{
AM_drawSeg ( sub - > firstline + i , yellow ) ;
}
PO_LinkToSubsectors ( ) ;
for ( int i = 0 ; i < po_NumPolyobjs ; i + + )
{
FPolyObj * po = & polyobjs [ i ] ;
FPolyNode * pnode = po - > subsectorlinks ;
while ( pnode ! = NULL )
{
if ( pnode - > subsector = = sub )
{
for ( unsigned j = 0 ; j < pnode - > segs . Size ( ) ; j + + )
{
AM_drawPolySeg ( & pnode - > segs [ j ] , red ) ;
}
}
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 ] ;
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 ] ;
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 ] ;
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 ] ;
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.
bool AM_checkSpecialBoundary ( line_t & line , bool ( * function ) ( int , int * ) , int * specialptr = NULL , int * * argsptr = NULL )
{
if ( specialptr = = NULL )
{
static int sink ;
specialptr = & sink ;
}
if ( argsptr = = NULL )
{
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).
if ( AM_checkSectorActions ( line . frontsector , function , specialptr , argsptr , line . backsector = = NULL ) )
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_isTeleportSpecial ( int special , int * )
{
return ( special = = Teleport | |
special = = Teleport_NoFog | |
special = = Teleport_ZombieChanger | |
special = = Teleport_Line ) ;
}
bool AM_isTeleportBoundary ( line_t & line )
{
return AM_checkSpecialBoundary ( line , & AM_isTeleportSpecial ) ;
}
bool AM_isExitSpecial ( int special , int * )
{
return ( special = = Teleport_NewMap | |
special = = Teleport_EndGame | |
special = = Exit_Normal | |
special = = Exit_Secret ) ;
}
bool AM_isExitBoundary ( line_t & line )
{
return AM_checkSpecialBoundary ( line , & AM_isExitSpecial ) ;
}
bool AM_isTriggerSpecial ( int special , int * )
{
FLineSpecial * spec = P_GetLineSpecialInfo ( special ) ;
return spec ! = NULL
& & spec - > max_args > = 0
& & special ! = Door_Open
& & special ! = Door_Close
& & special ! = Door_CloseWaitOpen
& & special ! = Door_Raise
& & special ! = Door_Animated
& & special ! = Generic_Door ;
}
bool AM_isTriggerBoundary ( line_t & line )
{
return AM_checkSpecialBoundary ( line , & AM_isTriggerSpecial ) ;
}
bool AM_isLockSpecial ( 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 ) ;
}
bool AM_isLockBoundary ( line_t & line , int * lockptr = NULL )
{
if ( lockptr = = NULL )
{
static int sink ;
lockptr = & sink ;
}
if ( line . locknumber )
{
* lockptr = line . locknumber ;
return true ;
}
int special ;
int * args ;
bool result = AM_checkSpecialBoundary ( line , & AM_isLockSpecial , & special , & args ) ;
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.
//
//=============================================================================
void AM_drawWalls ( bool allmap )
{
static mline_t l ;
int lock , color ;
2016-03-13 11:33:58 +00:00
int numportalgroups = am_portaloverlay ? Displacements . size : 0 ;
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
2017-01-08 13:39:16 +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 )
{
2016-03-25 20:54:59 +00:00
offset = 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 ) )
{
AM_rotatePoint ( & l . a . x , & l . a . y ) ;
AM_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
2016-03-13 11:33:58 +00:00
if ( portalmode )
{
AM_drawMline ( & l , AMColors . PortalColor ) ;
}
2017-01-08 13:39:16 +00:00
else if ( AM_CheckSecret ( & line ) )
2016-03-13 11:33:58 +00:00
{
// map secret sectors like Boom
AM_drawMline ( & l , AMColors . SecretSectorColor ) ;
}
2017-01-08 13:39:16 +00:00
else if ( line . flags & ML_SECRET )
2016-03-13 11:33:58 +00:00
{ // secret door
2017-01-08 13:39:16 +00:00
if ( am_cheat ! = 0 & & line . backsector ! = NULL )
2016-03-13 11:33:58 +00:00
AM_drawMline ( & l , AMColors . SecretWallColor ) ;
else
AM_drawMline ( & l , AMColors . WallColor ) ;
}
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
AM_drawMline ( & l , AMColors . IntraTeleportColor ) ;
}
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
AM_drawMline ( & l , AMColors . InterTeleportColor ) ;
}
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 ] ;
AM_drawMline ( & l , c ) ;
}
else
{
AM_drawMline ( & l , AMColors . LockedColor ) ; // locked special
}
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
{
2016-03-13 11:33:58 +00:00
AM_drawMline ( & l , AMColors . SpecialWallColor ) ; // wall with special non-door action the player can do
}
2017-01-08 13:39:16 +00:00
else if ( line . backsector = = NULL )
2016-03-13 11:33:58 +00:00
{
AM_drawMline ( & l , AMColors . WallColor ) ; // one-sided wall
}
2017-01-08 13:39:16 +00:00
else if ( line . backsector - > floorplane
! = line . frontsector - > floorplane )
2016-03-13 11:33:58 +00:00
{
AM_drawMline ( & l , AMColors . FDWallColor ) ; // floor level change
}
2017-01-08 13:39:16 +00:00
else if ( line . backsector - > ceilingplane
! = line . frontsector - > ceilingplane )
2016-03-13 11:33:58 +00:00
{
AM_drawMline ( & l , AMColors . CDWallColor ) ; // ceiling level change
}
2017-01-08 13:39:16 +00:00
else if ( AM_Check3DFloors ( & line ) )
2016-03-13 11:33:58 +00:00
{
AM_drawMline ( & l , AMColors . EFWallColor ) ; // Extra floor border
}
else if ( am_cheat > 0 & & am_cheat < 4 )
{
AM_drawMline ( & l , AMColors . TSWallColor ) ;
2016-03-01 15:47:10 +00:00
}
}
2016-03-13 11:33:58 +00:00
else if ( allmap )
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
}
2016-03-13 11:33:58 +00:00
AM_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.
//
//=============================================================================
2016-03-25 20:54:59 +00:00
void AM_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
}
//=============================================================================
//
//
//
//=============================================================================
2016-03-25 20:54:59 +00:00
void AM_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 ;
2016-04-07 08:39:15 +00:00
AM_rotate ( x , y , - players [ consoleplayer ] . camera - > Angles . Yaw + 90. ) ;
2016-03-01 15:47:10 +00:00
* x + = pivotx ;
* y + = pivoty ;
}
//=============================================================================
//
//
//
//=============================================================================
void
AM_drawLineCharacter
( const mline_t * lineguy ,
int lineguylines ,
2016-03-25 20:54:59 +00:00
double scale ,
DAngle angle ,
2016-03-01 15:47:10 +00:00
const AMColor & color ,
2016-03-25 20:54:59 +00:00
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 )
2016-03-01 15:47:10 +00:00
AM_rotate ( & l . a . x , & l . a . y , angle ) ;
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 )
2016-03-01 15:47:10 +00:00
AM_rotate ( & l . b . x , & l . b . y , angle ) ;
l . b . x + = x ;
l . b . y + = y ;
AM_drawMline ( & l , color ) ;
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_drawPlayers ( )
{
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. ;
2016-03-01 15:47:10 +00:00
AM_rotatePoint ( & pt . x , & pt . y ) ;
}
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 ( ) ;
}
AM_drawLineCharacter ( arrow , numarrowlines , 0 , angle , AMColors [ AMColors . YourColor ] , pt . x , pt . y ) ;
return ;
}
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
player_t * p = & players [ i ] ;
AMColor color ;
if ( ! playeringame [ i ] | | p - > mo = = NULL )
{
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 ;
D_GetPlayerColor ( i , & h , & s , & v , NULL ) ;
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 ) ) ;
}
if ( p - > mo ! = NULL )
{
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 ) )
{
AM_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
}
AM_drawLineCharacter ( & MapArrow [ 0 ] , MapArrow . Size ( ) , 0 , angle , color , pt . x , pt . y ) ;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_drawKeys ( )
{
AMColor color ;
mpoint_t p ;
2016-03-25 20:54:59 +00:00
DAngle angle ;
2016-03-01 15:47:10 +00:00
2017-01-18 14:17:12 +00:00
TThinkerIterator < AInventory > it ( NAME_Key ) ;
AInventory * key ;
2016-03-01 15:47:10 +00:00
while ( ( key = it . Next ( ) ) ! = NULL )
{
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 ) )
{
AM_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 P_GetMapColorForKey ( AInventory * key ) ;
int c = P_GetMapColorForKey ( key ) ;
if ( c > = 0 ) color . FromRGB ( RPART ( c ) , GPART ( c ) , BPART ( c ) ) ;
else color = AMColors [ AMColors . ThingColor_CountItem ] ;
2016-03-25 20:54:59 +00:00
AM_drawLineCharacter ( & EasyKey [ 0 ] , EasyKey . Size ( ) , 0 , 0. , color , p . x , p . y ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_drawThings ( )
{
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
2017-01-07 18:32:24 +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 )
{
FTexture * texture = NULL ;
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.
for ( int show = am_showthingsprites ; show > 0 & & texture = = NULL ; show - - )
{
const spritedef_t & sprite = sprites [ t - > sprite ] ;
const size_t spriteIndex = sprite . spriteframes + ( show > 1 ? t - > frame : 0 ) ;
frame = & SpriteFrames [ spriteIndex ] ;
2016-04-07 11:05:29 +00:00
DAngle angle = 270. - 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 ] ;
texture = TexMan ( textureID ) ;
}
if ( texture = = NULL ) goto drawTriangle ; // fall back to standard display if no sprite can be found.
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 ) )
{
AM_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-01-18 14:17:12 +00:00
if ( t - > IsKindOf ( PClass : : FindActor ( 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 )
{
int P_GetMapColorForKey ( AInventory * key ) ;
2017-01-18 14:17:12 +00:00
int c = P_GetMapColorForKey ( static_cast < AInventory * > ( 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 ] ;
2016-03-25 20:54:59 +00:00
AM_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 )
{
2016-03-25 20:54:59 +00:00
AM_drawLineCharacter ( thintriangle_guy , NUMTHINTRIANGLEGUYLINES , 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
} ;
2016-03-25 20:54:59 +00:00
AM_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 ;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
2016-03-25 20:54:59 +00:00
static void DrawMarker ( FTexture * tex , double x , double y , int yadjust ,
INTBOOL flip , double xscale , double yscale , int translation , double alpha , DWORD fillcolor , FRenderStyle renderstyle )
2016-03-01 15:47:10 +00:00
{
if ( tex = = NULL | | tex - > UseType = = FTexture : : TEX_Null )
{
return ;
}
if ( am_rotate = = 1 | | ( am_rotate = = 2 & & viewactive ) )
{
AM_rotatePoint ( & x , & y ) ;
}
screen - > DrawTexture ( tex , CXMTOF ( x ) + f_x , CYMTOF ( y ) + yadjust + f_y ,
2016-05-18 19:25:58 +00:00
DTA_DestWidthF , tex - > GetScaledWidthDouble ( ) * CleanXfac * xscale ,
DTA_DestHeightF , tex - > GetScaledHeightDouble ( ) * 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 ,
DTA_Translation , TranslationToTable ( translation ) ,
2016-03-21 11:18:46 +00:00
DTA_AlphaF , alpha ,
2016-03-01 15:47:10 +00:00
DTA_FillColor , fillcolor ,
DTA_RenderStyle , DWORD ( renderstyle ) ,
TAG_DONE ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_drawMarks ( )
{
for ( int i = 0 ; i < AM_NUMMARKPOINTS ; i + + )
{
if ( markpoints [ i ] . x ! = - 1 )
{
DrawMarker ( TexMan ( marknums [ i ] ) , 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
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_drawAuthorMarkers ( )
{
// [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].
2016-11-29 18:50:34 +00:00
TThinkerIterator < AActor > it ( " MapMarker " , STAT_MAPMARKER ) ;
AActor * mark ;
2016-03-01 15:47:10 +00:00
while ( ( mark = it . Next ( ) ) ! = NULL )
{
if ( mark - > flags2 & MF2_DORMANT )
{
continue ;
}
FTextureID picnum ;
FTexture * tex ;
WORD flip = 0 ;
if ( mark - > picnum . isValid ( ) )
{
tex = TexMan ( mark - > picnum ) ;
if ( tex - > Rotations ! = 0xFFFF )
{
spriteframe_t * sprframe = & SpriteFrames [ tex - > Rotations ] ;
picnum = sprframe - > Texture [ 0 ] ;
flip = sprframe - > Flip & 1 ;
tex = TexMan [ picnum ] ;
}
}
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 ;
tex = TexMan [ picnum ] ;
}
}
FActorIterator it ( mark - > args [ 0 ] ) ;
AActor * marked = mark - > args [ 0 ] = = 0 ? mark : it . Next ( ) ;
while ( marked ! = NULL )
{
// Use more correct info if we have GL nodes available
if ( mark - > args [ 1 ] = = 0 | |
( mark - > args [ 1 ] = = 1 & & ( hasglnodes ?
marked - > subsector - > flags & SSECF_DRAWN :
marked - > Sector - > MoreFlags & SECF_DRAWN ) ) )
{
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
}
marked = mark - > args [ 0 ] ! = 0 ? it . Next ( ) : NULL ;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void AM_drawCrosshair ( const AMColor & color )
{
screen - > DrawPixel ( f_w / 2 , ( f_h + 1 ) / 2 , color . Index , color . RGB ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void AM_Drawer ( )
{
if ( ! automapactive )
return ;
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-01-20 09:51:21 +00:00
f_h = gST_Y ;
2016-03-01 15:47:10 +00:00
f_p = screen - > GetPitch ( ) ;
AM_clearFB ( AMColors [ AMColors . Background ] ) ;
}
else
{
f_x = viewwindowx ;
f_y = viewwindowy ;
f_w = viewwidth ;
f_h = viewheight ;
f_p = screen - > GetPitch ( ) ;
}
AM_activateNewScale ( ) ;
if ( am_textured & & hasglnodes & & textured & & ! viewactive )
AM_drawSubsectors ( ) ;
if ( grid )
AM_drawGrid ( AMColors . GridColor ) ;
AM_drawWalls ( allmap ) ;
AM_drawPlayers ( ) ;
if ( G_SkillProperty ( SKILLP_EasyKey ) )
AM_drawKeys ( ) ;
if ( ( am_cheat > = 2 & & am_cheat ! = 4 ) | | allthings )
AM_drawThings ( ) ;
AM_drawAuthorMarkers ( ) ;
if ( ! viewactive )
AM_drawCrosshair ( AMColors [ AMColors . XHairColor ] ) ;
AM_drawMarks ( ) ;
AM_showSS ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
2016-09-20 07:11:13 +00:00
void AM_SerializeMarkers ( FSerializer & arc )
2016-03-01 15:47:10 +00:00
{
2016-09-20 07:11:13 +00:00
if ( arc . BeginObject ( " automarkers " ) )
2016-03-01 15:47:10 +00:00
{
2016-09-20 07:11:13 +00:00
arc ( " markpointnum " , markpointnum )
. Array ( " markpoints " , & markpoints [ 0 ] . x , AM_NUMMARKPOINTS * 2 ) // write as a double array.
( " scale_mtof " , scale_mtof )
( " scale_ftom " , scale_ftom )
. EndObject ( ) ;
2016-03-01 15:47:10 +00:00
}
}