2018-12-28 08:17:10 +00:00
//-----------------------------------------------------------------------------
//
// Copyright 1993-1996 id Software
// Copyright 1994-1996 Raven Software
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2018 Christoph Oelckers
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
// DESCRIPTION:
//
//-----------------------------------------------------------------------------
# include <math.h>
# ifdef _MSC_VER
# include <malloc.h> // for alloca()
# endif
# include "templates.h"
# include "d_player.h"
# include "m_argv.h"
# include "g_game.h"
# include "w_wad.h"
# include "p_local.h"
# include "p_effect.h"
# include "p_terrain.h"
# include "nodebuild.h"
# include "p_lnspec.h"
# include "c_console.h"
# include "p_acs.h"
# include "announcer.h"
# include "wi_stuff.h"
# include "doomerrors.h"
# include "gi.h"
# include "p_conversation.h"
# include "a_keys.h"
# include "s_sndseq.h"
# include "sbar.h"
# include "p_setup.h"
# include "r_data/r_interpolate.h"
# include "r_sky.h"
# include "cmdlib.h"
# include "md5.h"
# include "po_man.h"
# include "r_renderer.h"
# include "p_blockmap.h"
# include "r_utility.h"
# include "p_spec.h"
# include "g_levellocals.h"
# include "c_dispatch.h"
# include "a_dynlight.h"
# include "events.h"
# include "p_destructible.h"
# include "types.h"
# include "i_time.h"
# include "scripting/vm/vm.h"
2019-01-05 09:04:27 +00:00
# include "a_specialspot.h"
2018-12-28 08:17:10 +00:00
# include "maploader/maploader.h"
2019-01-06 09:24:27 +00:00
# include "p_acs.h"
2019-01-26 14:21:20 +00:00
# include "am_map.h"
2019-01-31 18:38:04 +00:00
# include "i_system.h"
2019-01-31 23:30:21 +00:00
# include "v_video.h"
2019-01-06 09:24:27 +00:00
# include "fragglescript/t_script.h"
2018-12-28 08:17:10 +00:00
extern AActor * SpawnMapThing ( int index , FMapThing * mthing , int position ) ;
extern unsigned int R_OldBlend ;
static void P_Shutdown ( ) ;
//===========================================================================
//
// P_PrecacheLevel
//
// Preloads all relevant graphics for the Level->
//
//===========================================================================
void hw_PrecacheTexture ( uint8_t * texhitlist , TMap < PClassActor * , bool > & actorhitlist ) ;
static void AddToList ( uint8_t * hitlist , FTextureID texid , int bitmask )
{
if ( hitlist [ texid . GetIndex ( ) ] & bitmask ) return ; // already done, no need to process everything again.
hitlist [ texid . GetIndex ( ) ] | = ( uint8_t ) bitmask ;
for ( auto anim : TexMan . mAnimations )
{
if ( texid = = anim - > BasePic | | ( ! anim - > bDiscrete & & anim - > BasePic < texid & & texid < anim - > BasePic + anim - > NumFrames ) )
{
for ( int i = anim - > BasePic . GetIndex ( ) ; i < anim - > BasePic . GetIndex ( ) + anim - > NumFrames ; i + + )
{
hitlist [ i ] | = ( uint8_t ) bitmask ;
}
}
}
auto switchdef = TexMan . FindSwitch ( texid ) ;
if ( switchdef )
{
for ( int i = 0 ; i < switchdef - > NumFrames ; i + + )
{
hitlist [ switchdef - > frames [ i ] . Texture . GetIndex ( ) ] | = ( uint8_t ) bitmask ;
}
for ( int i = 0 ; i < switchdef - > PairDef - > NumFrames ; i + + )
{
2018-12-29 13:01:07 +00:00
hitlist [ switchdef - > PairDef - > frames [ i ] . Texture . GetIndex ( ) ] | = ( uint8_t ) bitmask ;
2018-12-28 08:17:10 +00:00
}
}
auto adoor = TexMan . FindAnimatedDoor ( texid ) ;
if ( adoor )
{
for ( int i = 0 ; i < adoor - > NumTextureFrames ; i + + )
{
hitlist [ adoor - > TextureFrames [ i ] . GetIndex ( ) ] | = ( uint8_t ) bitmask ;
}
}
}
static void PrecacheLevel ( FLevelLocals * Level )
{
if ( demoplayback )
return ;
int i ;
TMap < PClassActor * , bool > actorhitlist ;
int cnt = TexMan . NumTextures ( ) ;
TArray < uint8_t > hitlist ( cnt , true ) ;
memset ( hitlist . Data ( ) , 0 , cnt ) ;
AActor * actor ;
2019-01-27 23:55:21 +00:00
auto iterator = Level - > GetThinkerIterator < AActor > ( ) ;
2018-12-28 08:17:10 +00:00
while ( ( actor = iterator . Next ( ) ) )
{
actorhitlist [ actor - > GetClass ( ) ] = true ;
}
for ( auto n : gameinfo . PrecachedClasses )
{
PClassActor * cls = PClass : : FindActor ( n ) ;
if ( cls ! = nullptr ) actorhitlist [ cls ] = true ;
}
for ( unsigned i = 0 ; i < Level - > info - > PrecacheClasses . Size ( ) ; i + + )
{
// Level->info can only store names, no class pointers.
PClassActor * cls = PClass : : FindActor ( Level - > info - > PrecacheClasses [ i ] ) ;
if ( cls ! = nullptr ) actorhitlist [ cls ] = true ;
}
for ( i = Level - > sectors . Size ( ) - 1 ; i > = 0 ; i - - )
{
AddToList ( hitlist . Data ( ) , Level - > sectors [ i ] . GetTexture ( sector_t : : floor ) , FTextureManager : : HIT_Flat ) ;
AddToList ( hitlist . Data ( ) , Level - > sectors [ i ] . GetTexture ( sector_t : : ceiling ) , FTextureManager : : HIT_Flat ) ;
}
for ( i = Level - > sides . Size ( ) - 1 ; i > = 0 ; i - - )
{
AddToList ( hitlist . Data ( ) , Level - > sides [ i ] . GetTexture ( side_t : : top ) , FTextureManager : : HIT_Wall ) ;
AddToList ( hitlist . Data ( ) , Level - > sides [ i ] . GetTexture ( side_t : : mid ) , FTextureManager : : HIT_Wall ) ;
AddToList ( hitlist . Data ( ) , Level - > sides [ i ] . GetTexture ( side_t : : bottom ) , FTextureManager : : HIT_Wall ) ;
}
2019-01-29 03:44:44 +00:00
if ( Level - > skytexture1 . isValid ( ) )
2018-12-28 08:17:10 +00:00
{
2019-01-29 03:44:44 +00:00
AddToList ( hitlist . Data ( ) , Level - > skytexture1 , FTextureManager : : HIT_Sky ) ;
2018-12-28 08:17:10 +00:00
}
2019-01-29 03:44:44 +00:00
if ( Level - > skytexture2 . isValid ( ) )
2018-12-28 08:17:10 +00:00
{
2019-01-29 03:44:44 +00:00
AddToList ( hitlist . Data ( ) , Level - > skytexture2 , FTextureManager : : HIT_Sky ) ;
2018-12-28 08:17:10 +00:00
}
for ( auto n : gameinfo . PrecachedTextures )
{
FTextureID tex = TexMan . CheckForTexture ( n , ETextureType : : Wall , FTextureManager : : TEXMAN_Overridable | FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ReturnFirst ) ;
if ( tex . Exists ( ) ) AddToList ( hitlist . Data ( ) , tex , FTextureManager : : HIT_Wall ) ;
}
for ( unsigned i = 0 ; i < Level - > info - > PrecacheTextures . Size ( ) ; i + + )
{
FTextureID tex = TexMan . CheckForTexture ( Level - > info - > PrecacheTextures [ i ] , ETextureType : : Wall , FTextureManager : : TEXMAN_Overridable | FTextureManager : : TEXMAN_TryAny | FTextureManager : : TEXMAN_ReturnFirst ) ;
if ( tex . Exists ( ) ) AddToList ( hitlist . Data ( ) , tex , FTextureManager : : HIT_Wall ) ;
}
// This is just a temporary solution, until the hardware renderer's texture manager is in a better state.
if ( ! V_IsHardwareRenderer ( ) )
SWRenderer - > Precache ( hitlist . Data ( ) , actorhitlist ) ;
else
hw_PrecacheTexture ( hitlist . Data ( ) , actorhitlist ) ;
}
2018-12-31 11:42:03 +00:00
//============================================================================
//
// clears all portal data for a new level start
//
//============================================================================
void FLevelLocals : : ClearPortals ( )
{
Displacements . Create ( 1 ) ;
linePortals . Clear ( ) ;
linkedPortals . Clear ( ) ;
sectorPortals . Resize ( 2 ) ;
PortalBlockmap . Clear ( ) ;
// The first entry must always be the default skybox. This is what every sector gets by default.
memset ( & sectorPortals [ 0 ] , 0 , sizeof ( sectorPortals [ 0 ] ) ) ;
sectorPortals [ 0 ] . mType = PORTS_SKYVIEWPOINT ;
sectorPortals [ 0 ] . mFlags = PORTSF_SKYFLATONLY ;
// The second entry will be the default sky. This is for forcing a regular sky through the skybox picker
memset ( & sectorPortals [ 1 ] , 0 , sizeof ( sectorPortals [ 0 ] ) ) ;
sectorPortals [ 1 ] . mType = PORTS_SKYVIEWPOINT ;
sectorPortals [ 1 ] . mFlags = PORTSF_SKYFLATONLY ;
// also clear the render data
for ( auto & sub : subsectors )
{
for ( int j = 0 ; j < 2 ; j + + )
{
if ( sub . portalcoverage [ j ] . subsectors ! = nullptr )
{
delete [ ] sub . portalcoverage [ j ] . subsectors ;
sub . portalcoverage [ j ] . subsectors = nullptr ;
}
}
}
for ( unsigned i = 0 ; i < portalGroups . Size ( ) ; i + + )
{
delete portalGroups [ i ] ;
}
portalGroups . Clear ( ) ;
linePortalSpans . Clear ( ) ;
}
//==========================================================================
//
//
//
//==========================================================================
void FLevelLocals : : ClearLevelData ( )
{
2019-02-04 15:27:57 +00:00
interpolator . ClearInterpolations ( ) ; // [RH] Nothing to interpolate on a fresh level.
2019-01-30 18:09:21 +00:00
Thinkers . DestroyAllThinkers ( ) ;
2019-01-26 14:21:20 +00:00
ClearAllSubsectorLinks ( ) ; // can't be done as part of the polyobj deletion process.
2018-12-31 11:42:03 +00:00
total_monsters = total_items = total_secrets =
killed_monsters = found_items = found_secrets =
wminfo . maxfrags = 0 ;
2019-01-29 23:37:29 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
UDMFKeys [ i ] . Clear ( ) ;
}
2019-01-09 01:03:26 +00:00
2019-01-28 22:53:40 +00:00
SN_StopAllSequences ( this ) ;
2019-01-09 01:03:26 +00:00
FStrifeDialogueNode * node ;
while ( StrifeDialogues . Pop ( node ) )
{
delete node ;
}
DialogueRoots . Clear ( ) ;
ClassRoots . Clear ( ) ;
2018-12-31 11:42:03 +00:00
// delete allocated data in the level arrays.
if ( sectors . Size ( ) > 0 )
{
delete [ ] sectors [ 0 ] . e ;
}
for ( auto & sub : subsectors )
{
if ( sub . BSP ! = nullptr ) delete sub . BSP ;
}
ClearPortals ( ) ;
2019-01-24 00:40:09 +00:00
tagManager . Clear ( ) ;
2019-01-24 18:28:40 +00:00
ClearTIDHashes ( ) ;
2019-02-04 15:27:57 +00:00
if ( SpotState ) SpotState - > Destroy ( ) ;
2019-01-05 09:04:27 +00:00
SpotState = nullptr ;
2019-01-06 09:24:27 +00:00
ACSThinker = nullptr ;
FraggleScriptThinker = nullptr ;
2019-01-05 09:53:06 +00:00
CorpseQueue . Clear ( ) ;
2018-12-31 11:42:03 +00:00
canvasTextureInfo . EmptyList ( ) ;
sections . Clear ( ) ;
segs . Clear ( ) ;
sectors . Clear ( ) ;
linebuffer . Clear ( ) ;
subsectorbuffer . Clear ( ) ;
lines . Clear ( ) ;
sides . Clear ( ) ;
segbuffer . Clear ( ) ;
loadsectors . Clear ( ) ;
loadlines . Clear ( ) ;
loadsides . Clear ( ) ;
vertexes . Clear ( ) ;
nodes . Clear ( ) ;
gamenodes . Reset ( ) ;
subsectors . Clear ( ) ;
gamesubsectors . Reset ( ) ;
rejectmatrix . Clear ( ) ;
Zones . Clear ( ) ;
blockmap . Clear ( ) ;
Polyobjects . Clear ( ) ;
for ( auto & pb : PolyBlockMap )
{
polyblock_t * link = pb ;
while ( link ! = nullptr )
{
polyblock_t * next = link - > next ;
delete link ;
link = next ;
}
}
PolyBlockMap . Reset ( ) ;
deathmatchstarts . Clear ( ) ;
AllPlayerStarts . Clear ( ) ;
memset ( playerstarts , 0 , sizeof ( playerstarts ) ) ;
Scrolls . Clear ( ) ;
2019-01-27 00:49:20 +00:00
if ( automap ) automap - > Destroy ( ) ;
2019-01-31 16:43:12 +00:00
Behaviors . UnloadModules ( ) ;
2019-02-02 16:29:13 +00:00
localEventManager - > Shutdown ( ) ;
2018-12-31 11:42:03 +00:00
}
2018-12-28 08:17:10 +00:00
//==========================================================================
//
//
//
//==========================================================================
void P_FreeLevelData ( )
{
R_FreePastViewers ( ) ;
2019-02-01 23:24:43 +00:00
for ( auto Level : AllLevels ( ) )
{
Level - > ClearLevelData ( ) ;
}
// primaryLevel->FreeSecondaryLevels();
2018-12-28 08:17:10 +00:00
}
//===========================================================================
//
// P_SetupLevel
//
// [RH] position indicates the start spot to spawn at
//
//===========================================================================
2019-01-26 14:21:20 +00:00
void P_SetupLevel ( FLevelLocals * Level , int position , bool newGame )
2018-12-28 08:17:10 +00:00
{
int i ;
2019-01-26 14:21:20 +00:00
Level - > ShaderStartTime = I_msTimeFS ( ) ; // indicate to the shader system that the level just started
2018-12-28 08:17:10 +00:00
// This is motivated as follows:
2019-01-26 14:21:20 +00:00
Level - > maptype = MAPTYPE_UNKNOWN ;
2018-12-28 08:17:10 +00:00
wminfo . partime = 180 ;
if ( ! savegamerestore )
{
2019-01-26 14:21:20 +00:00
Level - > SetMusicVolume ( Level - > MusicVolume ) ;
2018-12-28 08:17:10 +00:00
for ( i = 0 ; i < MAXPLAYERS ; + + i )
{
2019-01-30 00:15:32 +00:00
Level - > Players [ i ] - > killcount = Level - > Players [ i ] - > secretcount
= Level - > Players [ i ] - > itemcount = 0 ;
2018-12-28 08:17:10 +00:00
}
}
for ( i = 0 ; i < MAXPLAYERS ; + + i )
{
2019-01-30 00:15:32 +00:00
Level - > Players [ i ] - > mo = nullptr ;
2018-12-28 08:17:10 +00:00
}
// [RH] Clear any scripted translation colors the previous level may have set.
for ( i = 0 ; i < int ( translationtables [ TRANSLATION_LevelScripted ] . Size ( ) ) ; + + i )
{
FRemapTable * table = translationtables [ TRANSLATION_LevelScripted ] [ i ] ;
if ( table ! = nullptr )
{
delete table ;
translationtables [ TRANSLATION_LevelScripted ] [ i ] = nullptr ;
}
}
translationtables [ TRANSLATION_LevelScripted ] . Clear ( ) ;
// Initial height of PointOfView will be set by player think.
2019-02-01 16:02:10 +00:00
auto p = Level - > GetConsolePlayer ( ) ;
if ( p ) p - > viewz = NO_VALUE ;
2018-12-28 08:17:10 +00:00
// Make sure all sounds are stopped before Z_FreeTags.
S_Start ( ) ;
// [RH] clear out the mid-screen message
C_MidPrint ( nullptr , nullptr ) ;
// Free all level data from the previous map
P_FreeLevelData ( ) ;
2019-01-26 14:21:20 +00:00
MapData * map = P_OpenMapData ( Level - > MapName , true ) ;
2018-12-28 08:17:10 +00:00
if ( map = = nullptr )
{
2019-01-26 14:21:20 +00:00
I_Error ( " Unable to open map '%s' \n " , Level - > MapName . GetChars ( ) ) ;
2018-12-28 08:17:10 +00:00
}
// [ZZ] init per-map static handlers. we need to call this before everything is set up because otherwise scripts don't receive PlayerEntered event
// (which happens at god-knows-what stage in this function, but definitely not the last part, because otherwise it'd work to put E_InitStaticHandlers before the player spawning)
2019-02-06 14:33:19 +00:00
Level - > localEventManager - > InitStaticHandlers ( Level , true ) ;
2018-12-28 08:17:10 +00:00
// generate a checksum for the level, to be included and checked with savegames.
2019-01-26 14:21:20 +00:00
map - > GetChecksum ( Level - > md5 ) ;
2018-12-28 08:17:10 +00:00
// find map num
2019-01-26 14:21:20 +00:00
Level - > lumpnum = map - > lumpnum ;
2018-12-28 08:17:10 +00:00
if ( newGame )
{
2019-02-02 15:43:11 +00:00
Level - > localEventManager - > NewGame ( ) ;
2018-12-28 08:17:10 +00:00
}
2019-01-26 14:21:20 +00:00
MapLoader loader ( Level ) ;
loader . LoadLevel ( map , Level - > MapName . GetChars ( ) , position ) ;
2018-12-28 08:17:10 +00:00
delete map ;
// if deathmatch, randomly spawn the active players
if ( deathmatch )
{
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
2019-01-30 00:15:32 +00:00
if ( Level - > PlayerInGame ( i ) )
2018-12-28 08:17:10 +00:00
{
2019-01-30 00:15:32 +00:00
Level - > Players [ i ] - > mo = nullptr ;
2019-01-28 01:44:05 +00:00
Level - > DeathMatchSpawnPlayer ( i ) ;
2018-12-28 08:17:10 +00:00
}
}
}
// the same, but for random single/coop player starts
2019-01-26 14:21:20 +00:00
else if ( Level - > flags2 & LEVEL2_RANDOMPLAYERSTARTS )
2018-12-28 08:17:10 +00:00
{
for ( i = 0 ; i < MAXPLAYERS ; + + i )
{
2019-01-30 00:15:32 +00:00
if ( Level - > PlayerInGame ( i ) )
2018-12-28 08:17:10 +00:00
{
2019-01-30 00:15:32 +00:00
Level - > Players [ i ] - > mo = nullptr ;
2019-01-28 01:44:05 +00:00
FPlayerStart * mthing = Level - > PickPlayerStart ( i ) ;
2019-01-28 02:02:25 +00:00
Level - > SpawnPlayer ( mthing , i , ( Level - > flags2 & LEVEL2_PRERAISEWEAPON ) ? SPF_WEAPONFULLYUP : 0 ) ;
2018-12-28 08:17:10 +00:00
}
}
}
// [SP] move unfriendly players around
// horribly hacky - yes, this needs rewritten.
2019-01-26 14:21:20 +00:00
if ( Level - > deathmatchstarts . Size ( ) > 0 )
2018-12-28 08:17:10 +00:00
{
for ( i = 0 ; i < MAXPLAYERS ; + + i )
{
2019-01-30 00:15:32 +00:00
auto p = Level - > Players [ i ] ;
if ( Level - > PlayerInGame ( i ) & & p - > mo ! = nullptr )
2018-12-28 08:17:10 +00:00
{
2019-01-30 00:15:32 +00:00
if ( ! ( p - > mo - > flags & MF_FRIENDLY ) )
2018-12-28 08:17:10 +00:00
{
2019-01-30 00:15:32 +00:00
AActor * oldSpawn = p - > mo ;
2019-01-28 01:44:05 +00:00
Level - > DeathMatchSpawnPlayer ( i ) ;
2018-12-28 08:17:10 +00:00
oldSpawn - > Destroy ( ) ;
}
}
}
}
// Don't count monsters in end-of-level sectors if option is on
if ( dmflags2 & DF2_NOCOUNTENDMONST )
{
2019-01-27 23:55:21 +00:00
auto it = Level - > GetThinkerIterator < AActor > ( ) ;
2018-12-28 08:17:10 +00:00
AActor * mo ;
while ( ( mo = it . Next ( ) ) )
{
if ( mo - > flags & MF_COUNTKILL )
{
if ( mo - > Sector - > damageamount > 0 & & ( mo - > Sector - > Flags & ( SECF_ENDGODMODE | SECF_ENDLEVEL ) ) = = ( SECF_ENDGODMODE | SECF_ENDLEVEL ) )
{
mo - > ClearCounters ( ) ;
}
}
}
}
2019-01-27 23:55:21 +00:00
T_PreprocessScripts ( Level ) ; // preprocess FraggleScript scripts
2018-12-28 08:17:10 +00:00
// build subsector connect matrix
// UNUSED P_ConnectSubsectors ();
R_OldBlend = 0xffffffff ;
// [RH] Remove all particles
2019-01-29 00:09:02 +00:00
P_ClearParticles ( Level ) ;
2018-12-28 08:17:10 +00:00
// preload graphics and sounds
if ( precache )
{
2019-01-27 23:55:21 +00:00
PrecacheLevel ( Level ) ;
S_PrecacheLevel ( Level ) ;
2018-12-28 08:17:10 +00:00
}
if ( deathmatch )
{
AnnounceGameStart ( ) ;
}
// This check was previously done at run time each time the heightsec was checked.
// However, since 3D floors are static data, we can easily precalculate this and store it in the sector's flags for quick access.
2019-01-26 14:21:20 +00:00
for ( auto & s : Level - > sectors )
2018-12-28 08:17:10 +00:00
{
if ( s . heightsec ! = nullptr )
{
// If any of these 3D floors render their planes, ignore heightsec.
for ( auto & ff : s . e - > XFloor . ffloors )
{
if ( ( ff - > flags & ( FF_EXISTS | FF_RENDERPLANES ) ) = = ( FF_EXISTS | FF_RENDERPLANES ) )
{
s . MoreFlags | = SECMF_IGNOREHEIGHTSEC ; // mark the heightsec inactive.
}
}
}
}
// Create a backup of the map data so the savegame code can toss out all fields that haven't changed in order to reduce processing time and file size.
// Note that we want binary identity here, so assignment is not sufficient because it won't initialize any padding bytes.
// Note that none of these structures may contain non POD fields anyway.
2019-01-26 14:21:20 +00:00
Level - > loadsectors . Resize ( Level - > sectors . Size ( ) ) ;
memcpy ( & Level - > loadsectors [ 0 ] , & Level - > sectors [ 0 ] , Level - > sectors . Size ( ) * sizeof ( Level - > sectors [ 0 ] ) ) ;
Level - > loadlines . Resize ( Level - > lines . Size ( ) ) ;
memcpy ( & Level - > loadlines [ 0 ] , & Level - > lines [ 0 ] , Level - > lines . Size ( ) * sizeof ( Level - > lines [ 0 ] ) ) ;
Level - > loadsides . Resize ( Level - > sides . Size ( ) ) ;
memcpy ( & Level - > loadsides [ 0 ] , & Level - > sides [ 0 ] , Level - > sides . Size ( ) * sizeof ( Level - > sides [ 0 ] ) ) ;
Level - > automap = AM_Create ( Level ) ;
Level - > automap - > LevelInit ( ) ;
2019-01-29 18:28:22 +00:00
Level - > SetCompatLineOnSide ( true ) ;
2019-01-27 18:16:14 +00:00
// [RH] Start lightning, if MAPINFO tells us to
if ( Level - > flags & LEVEL_STARTLIGHTNING )
{
Level - > StartLightning ( ) ;
}
2018-12-28 08:17:10 +00:00
}
//
// P_Init
//
void P_Init ( )
{
atterm ( P_Shutdown ) ;
P_InitEffects ( ) ; // [RH]
P_InitTerrainTypes ( ) ;
P_InitKeyMessages ( ) ;
R_InitSprites ( ) ;
}
static void P_Shutdown ( )
2019-01-30 01:15:48 +00:00
{
2019-02-01 23:24:43 +00:00
for ( auto Level : AllLevels ( ) )
{
Level - > Thinkers . DestroyThinkersInList ( STAT_STATIC ) ;
}
2018-12-28 08:17:10 +00:00
P_FreeLevelData ( ) ;
// [ZZ] delete global event handlers
2019-02-02 15:43:11 +00:00
staticEventManager . Shutdown ( ) ; // clear out the handlers before starting the engine shutdown
2018-12-28 08:17:10 +00:00
ST_Clear ( ) ;
for ( auto & p : players )
{
if ( p . psprites ! = nullptr ) p . psprites - > Destroy ( ) ;
}
}
//==========================================================================
//
// dumpgeometry
//
//==========================================================================
CCMD ( dumpgeometry )
{
2019-01-28 01:41:29 +00:00
for ( auto Level : AllLevels ( ) )
2018-12-28 08:17:10 +00:00
{
2019-01-28 01:41:29 +00:00
Printf ( " Geometry for %s \n " , Level - > MapName . GetChars ( ) ) ;
for ( auto & sector : Level - > sectors )
2018-12-28 08:17:10 +00:00
{
2019-01-28 01:41:29 +00:00
Printf ( PRINT_LOG , " Sector %d \n " , sector . sectornum ) ;
for ( int j = 0 ; j < sector . subsectorcount ; j + + )
2018-12-28 08:17:10 +00:00
{
2019-01-28 01:41:29 +00:00
subsector_t * sub = sector . subsectors [ j ] ;
Printf ( PRINT_LOG , " Subsector %d - real sector = %d - %s \n " , int ( sub - > Index ( ) ) , sub - > sector - > sectornum , sub - > hacked & 1 ? " hacked " : " " ) ;
for ( uint32_t k = 0 ; k < sub - > numlines ; k + + )
2018-12-28 08:17:10 +00:00
{
2019-01-28 01:41:29 +00:00
seg_t * seg = sub - > firstline + k ;
if ( seg - > linedef )
{
Printf ( PRINT_LOG , " (%4.4f, %4.4f), (%4.4f, %4.4f) - seg %d, linedef %d, side %d " ,
2019-01-28 22:53:40 +00:00
seg - > v1 - > fX ( ) , seg - > v1 - > fY ( ) , seg - > v2 - > fX ( ) , seg - > v2 - > fY ( ) ,
seg - > Index ( ) , seg - > linedef - > Index ( ) , seg - > sidedef ! = seg - > linedef - > sidedef [ 0 ] ) ;
2019-01-28 01:41:29 +00:00
}
else
{
Printf ( PRINT_LOG , " (%4.4f, %4.4f), (%4.4f, %4.4f) - seg %d, miniseg " ,
2019-01-28 22:53:40 +00:00
seg - > v1 - > fX ( ) , seg - > v1 - > fY ( ) , seg - > v2 - > fX ( ) , seg - > v2 - > fY ( ) , seg - > Index ( ) ) ;
2019-01-28 01:41:29 +00:00
}
if ( seg - > PartnerSeg )
{
subsector_t * sub2 = seg - > PartnerSeg - > Subsector ;
Printf ( PRINT_LOG , " , back sector = %d, real back sector = %d " , sub2 - > render_sector - > sectornum , seg - > PartnerSeg - > frontsector - > sectornum ) ;
}
else if ( seg - > backsector )
{
Printf ( PRINT_LOG , " , back sector = %d (no partnerseg) " , seg - > backsector - > sectornum ) ;
}
Printf ( PRINT_LOG , " \n " ) ;
2018-12-28 08:17:10 +00:00
}
}
}
}
}
2018-12-28 14:51:32 +00:00
//==========================================================================
//
//
//
//==========================================================================
CCMD ( listmapsections )
{
2019-01-28 01:41:29 +00:00
for ( auto Level : AllLevels ( ) )
2018-12-28 14:51:32 +00:00
{
2019-01-28 01:41:29 +00:00
Printf ( " Map sections for %s: \n " , Level - > MapName . GetChars ( ) ) ;
for ( int i = 0 ; i < 100 ; i + + )
2018-12-28 14:51:32 +00:00
{
2019-01-28 01:41:29 +00:00
for ( auto & sub : Level - > subsectors )
2018-12-28 14:51:32 +00:00
{
2019-01-28 01:41:29 +00:00
if ( sub . mapsection = = i )
{
Printf ( " Mapsection %d, sector %d, line %d \n " , i , sub . render_sector - > Index ( ) , sub . firstline - > linedef - > Index ( ) ) ;
break ;
}
2018-12-28 14:51:32 +00:00
}
}
}
}
2019-01-25 00:26:16 +00:00
//==========================================================================
//
//
//
//==========================================================================
CUSTOM_CVAR ( Bool , forcewater , false , CVAR_ARCHIVE | CVAR_SERVERINFO )
{
2019-01-28 01:41:29 +00:00
if ( gamestate = = GS_LEVEL ) for ( auto Level : AllLevels ( ) )
2019-01-25 00:26:16 +00:00
{
for ( auto & sec : Level - > sectors )
{
sector_t * hsec = sec . GetHeightSec ( ) ;
if ( hsec & & ! ( hsec - > MoreFlags & SECMF_UNDERWATER ) )
{
if ( self )
{
hsec - > MoreFlags | = SECMF_FORCEDUNDERWATER ;
}
else
{
hsec - > MoreFlags & = ~ SECMF_FORCEDUNDERWATER ;
}
}
}
}
}