2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
2021-05-07 15:45:56 +00:00
// Copyright (C) 1999-2021 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_setup.c
/// \brief Do all the WAD I/O, get map description, set up initial state and misc. LUTs
# include "doomdef.h"
# include "d_main.h"
# include "byteptr.h"
# include "g_game.h"
# include "p_local.h"
# include "p_setup.h"
# include "p_spec.h"
# include "p_saveg.h"
# include "i_sound.h" // for I_PlayCD()..
# include "i_video.h" // for I_FinishUpdate()..
# include "r_sky.h"
# include "i_system.h"
# include "r_data.h"
2020-03-09 13:54:56 +00:00
# include "r_things.h" // for R_AddSpriteDefs
2020-01-07 15:35:10 +00:00
# include "r_textures.h"
2019-10-28 18:28:42 +00:00
# include "r_patch.h"
2020-01-06 21:22:23 +00:00
# include "r_picformats.h"
2014-03-15 16:59:03 +00:00
# include "r_sky.h"
# include "r_draw.h"
# include "s_sound.h"
# include "st_stuff.h"
# include "w_wad.h"
# include "z_zone.h"
# include "r_splats.h"
# include "hu_stuff.h"
# include "console.h"
# include "m_misc.h"
# include "m_fixed.h"
# include "m_random.h"
# include "dehacked.h" // for map headers
# include "r_main.h"
# include "m_cond.h" // for emblems
# include "m_argv.h"
# include "p_polyobj.h"
# include "v_video.h"
2017-05-08 16:28:48 +00:00
# include "filesrch.h" // refreshdirmenu
2018-06-14 19:17:31 +00:00
# include "lua_hud.h" // level title
# include "f_finale.h" // wipes
2014-03-15 16:59:03 +00:00
# include "md5.h" // map MD5
2020-11-17 12:14:45 +00:00
// for MapLoad hook
2014-03-15 16:59:03 +00:00
# include "lua_script.h"
# include "lua_hook.h"
2017-09-29 22:25:34 +00:00
# ifdef _WIN32
2014-03-15 16:59:03 +00:00
# include <malloc.h>
# include <math.h>
# endif
# ifdef HWRENDER
# include "hardware/hw_main.h"
# include "hardware/hw_light.h"
2019-09-03 21:27:22 +00:00
# include "hardware/hw_model.h"
2014-03-15 16:59:03 +00:00
# endif
2015-04-19 21:54:20 +00:00
# include "p_slopes.h"
2019-12-30 10:33:22 +00:00
# include "fastcmp.h" // textmap parsing
2020-04-12 09:56:36 +00:00
# include "taglist.h"
2014-03-15 16:59:03 +00:00
//
// Map MD5, calculated on level load.
// Sent to clients in PT_SERVERINFO.
//
unsigned char mapmd5 [ 16 ] ;
//
// MAP related Lookup tables.
// Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
//
2020-03-15 15:23:15 +00:00
boolean udmf ;
2014-03-15 16:59:03 +00:00
size_t numvertexes , numsegs , numsectors , numsubsectors , numnodes , numlines , numsides , nummapthings ;
vertex_t * vertexes ;
seg_t * segs ;
sector_t * sectors ;
subsector_t * subsectors ;
node_t * nodes ;
line_t * lines ;
side_t * sides ;
mapthing_t * mapthings ;
2019-12-23 11:30:01 +00:00
sector_t * spawnsectors ;
line_t * spawnlines ;
side_t * spawnsides ;
2014-03-15 16:59:03 +00:00
INT32 numstarposts ;
2019-07-31 22:17:17 +00:00
UINT16 bossdisabled ;
2019-11-08 15:47:12 +00:00
boolean stoppedclock ;
2014-03-15 16:59:03 +00:00
boolean levelloading ;
2018-06-14 21:23:20 +00:00
UINT8 levelfadecol ;
2014-03-15 16:59:03 +00:00
// BLOCKMAP
// Created from axis aligned bounding box
// of the map, a rectangular array of
// blocks of size ...
// Used to speed up collision detection
// by spatial subdivision in 2D.
//
// Blockmap size.
INT32 bmapwidth , bmapheight ; // size in mapblocks
INT32 * blockmap ; // INT32 for large maps
// offsets in blockmap are from here
INT32 * blockmaplump ; // Big blockmap
// origin of block map
fixed_t bmaporgx , bmaporgy ;
// for thing chains
mobj_t * * blocklinks ;
// REJECT
// For fast sight rejection.
// Speeds up enemy AI by skipping detailed LineOf Sight calculation.
// Without special effect, this could be used as a PVS lookup as well.
//
UINT8 * rejectmatrix ;
// Maintain single and multi player starting spots.
INT32 numdmstarts , numcoopstarts , numredctfstarts , numbluectfstarts ;
mapthing_t * deathmatchstarts [ MAX_DM_STARTS ] ;
mapthing_t * playerstarts [ MAXPLAYERS ] ;
mapthing_t * bluectfstarts [ MAXPLAYERS ] ;
mapthing_t * redctfstarts [ MAXPLAYERS ] ;
2020-05-12 21:50:30 +00:00
// Maintain waypoints
mobj_t * waypoints [ NUMWAYPOINTSEQUENCES ] [ WAYPOINTSEQUENCESIZE ] ;
UINT16 numwaypoints [ NUMWAYPOINTSEQUENCES ] ;
void P_AddWaypoint ( UINT8 sequence , UINT8 id , mobj_t * waypoint )
{
waypoints [ sequence ] [ id ] = waypoint ;
if ( id > = numwaypoints [ sequence ] )
numwaypoints [ sequence ] = id + 1 ;
}
static void P_ResetWaypoints ( void )
{
UINT16 sequence , id ;
for ( sequence = 0 ; sequence < NUMWAYPOINTSEQUENCES ; sequence + + )
{
for ( id = 0 ; id < numwaypoints [ sequence ] ; id + + )
waypoints [ sequence ] [ id ] = NULL ;
numwaypoints [ sequence ] = 0 ;
}
}
mobj_t * P_GetFirstWaypoint ( UINT8 sequence )
{
return waypoints [ sequence ] [ 0 ] ;
}
mobj_t * P_GetLastWaypoint ( UINT8 sequence )
{
return waypoints [ sequence ] [ numwaypoints [ sequence ] - 1 ] ;
}
mobj_t * P_GetPreviousWaypoint ( mobj_t * current , boolean wrap )
{
UINT8 sequence = current - > threshold ;
UINT8 id = current - > health ;
if ( id = = 0 )
{
if ( ! wrap )
return NULL ;
id = numwaypoints [ sequence ] - 1 ;
}
else
id - - ;
return waypoints [ sequence ] [ id ] ;
}
mobj_t * P_GetNextWaypoint ( mobj_t * current , boolean wrap )
{
UINT8 sequence = current - > threshold ;
UINT8 id = current - > health ;
if ( id = = numwaypoints [ sequence ] - 1 )
{
if ( ! wrap )
return NULL ;
id = 0 ;
}
else
id + + ;
return waypoints [ sequence ] [ id ] ;
}
mobj_t * P_GetClosestWaypoint ( UINT8 sequence , mobj_t * mo )
{
UINT8 wp ;
mobj_t * mo2 , * result = NULL ;
fixed_t bestdist = 0 ;
fixed_t curdist ;
for ( wp = 0 ; wp < numwaypoints [ sequence ] ; wp + + )
{
mo2 = waypoints [ sequence ] [ wp ] ;
if ( ! mo2 )
continue ;
curdist = P_AproxDistance ( P_AproxDistance ( mo - > x - mo2 - > x , mo - > y - mo2 - > y ) , mo - > z - mo2 - > z ) ;
if ( result & & curdist > bestdist )
continue ;
result = mo2 ;
bestdist = curdist ;
}
return result ;
}
2020-05-16 08:24:06 +00:00
// Return true if all waypoints are in the same location
boolean P_IsDegeneratedWaypointSequence ( UINT8 sequence )
{
mobj_t * first , * waypoint ;
UINT8 wp ;
if ( numwaypoints [ sequence ] < = 1 )
return true ;
first = waypoints [ sequence ] [ 0 ] ;
for ( wp = 1 ; wp < numwaypoints [ sequence ] ; wp + + )
{
waypoint = waypoints [ sequence ] [ wp ] ;
if ( ! waypoint )
continue ;
if ( waypoint - > x ! = first - > x )
return false ;
if ( waypoint - > y ! = first - > y )
return false ;
if ( waypoint - > z ! = first - > z )
return false ;
}
return true ;
}
2014-03-15 16:59:03 +00:00
/** Logs an error about a map being corrupt, then terminate.
* This allows reporting highly technical errors for usefulness , without
* confusing a novice map designer who simply needs to run ZenNode .
*
* If logging is disabled in this compile , or the log file is not opened , the
* full technical details are printed in the I_Error ( ) message .
*
* \ param msg The message to log . This message can safely result from a call
* to va ( ) , since that function is not used here .
* \ todo Fix the I_Error ( ) message . On some implementations the logfile may
* not be called log . txt .
* \ sa CON_LogMessage , I_Error
*/
FUNCNORETURN static ATTRNORETURN void CorruptMapError ( const char * msg )
{
// don't use va() because the calling function probably uses it
char mapnum [ 10 ] ;
sprintf ( mapnum , " %hd " , gamemap ) ;
CON_LogMessage ( " Map " ) ;
CON_LogMessage ( mapnum ) ;
CON_LogMessage ( " is corrupt: " ) ;
CON_LogMessage ( msg ) ;
CON_LogMessage ( " \n " ) ;
I_Error ( " Invalid or corrupt map. \n Look in log file or text console for technical details. " ) ;
}
2017-01-01 16:24:47 +00:00
/** Sets a header's flickies to be equivalent to the original Freed Animals
*
* \ param i The header to set flickies for
*/
void P_SetDemoFlickies ( INT16 i )
{
mapheaderinfo [ i ] - > numFlickies = 5 ;
mapheaderinfo [ i ] - > flickies = Z_Realloc ( mapheaderinfo [ i ] - > flickies , 5 * sizeof ( mobjtype_t ) , PU_STATIC , NULL ) ;
mapheaderinfo [ i ] - > flickies [ 0 ] = MT_FLICKY_02 /*MT_BUNNY*/ ;
mapheaderinfo [ i ] - > flickies [ 1 ] = MT_FLICKY_01 /*MT_BIRD*/ ;
mapheaderinfo [ i ] - > flickies [ 2 ] = MT_FLICKY_12 /*MT_MOUSE*/ ;
mapheaderinfo [ i ] - > flickies [ 3 ] = MT_FLICKY_11 /*MT_COW*/ ;
mapheaderinfo [ i ] - > flickies [ 4 ] = MT_FLICKY_03 /*MT_CHICKEN*/ ;
}
/** Clears a header's flickies
*
* \ param i The header to clear flickies for
*/
void P_DeleteFlickies ( INT16 i )
{
if ( mapheaderinfo [ i ] - > flickies )
Z_Free ( mapheaderinfo [ i ] - > flickies ) ;
mapheaderinfo [ i ] - > flickies = NULL ;
mapheaderinfo [ i ] - > numFlickies = 0 ;
}
2014-03-15 16:59:03 +00:00
# define NUMLAPS_DEFAULT 4
/** Clears the data from a single map header.
*
* \ param i Map number to clear header for .
2014-08-27 03:56:30 +00:00
* \ sa P_ClearMapHeaderInfo
2014-03-15 16:59:03 +00:00
*/
static void P_ClearSingleMapHeaderInfo ( INT16 i )
{
const INT16 num = ( INT16 ) ( i - 1 ) ;
mapheaderinfo [ num ] - > lvlttl [ 0 ] = ' \0 ' ;
2017-01-26 19:14:52 +00:00
mapheaderinfo [ num ] - > selectheading [ 0 ] = ' \0 ' ;
2014-03-15 16:59:03 +00:00
mapheaderinfo [ num ] - > subttl [ 0 ] = ' \0 ' ;
2019-12-18 03:28:58 +00:00
mapheaderinfo [ num ] - > ltzzpatch [ 0 ] = ' \0 ' ;
mapheaderinfo [ num ] - > ltzztext [ 0 ] = ' \0 ' ;
mapheaderinfo [ num ] - > ltactdiamond [ 0 ] = ' \0 ' ;
2014-03-15 16:59:03 +00:00
mapheaderinfo [ num ] - > actnum = 0 ;
mapheaderinfo [ num ] - > typeoflevel = 0 ;
mapheaderinfo [ num ] - > nextlevel = ( INT16 ) ( i + 1 ) ;
Introducing Marathon Run. (I was going to call it Marathon Mode, but NiGHTS Mode being right next to it on the menu looked terrible.)
Basically a dedicated Record Attack-like experience for speedrunning the game as a continuous chunk rather than ILs. Has several quality of life features.
Benefits include:
* An unambiguous real-time bar across the bottom of the screen, always displaying the current time, ticking up until you reach the ending.
* Disable the console (pausing is still allowed, but the timer will still increment).
* Automatically skip intermissions as if you're holding down the spin button.
* Show centiseconds on HUD automatically, like record attack.
* "Live Event Backups" - a category of run fit for major events like GDQ, where recovery from crashes or chokes makes for better entertainment. Essentially a modified SP savefile, down to using the same basic functions, but has its own filename and tweaked internal layout.
* "spmarathon_start" MainCfg block parameter and "marathonnext" mapheader parameter, allowing for a customised flow (makes this fit for purpose for an eventual SUGOI port).
* Disabling inter-level custom cutscenes by default with a menu option to toggle this (won't show up if the mod doesn't *have* any custom cutscenes), although either way ending cutscenes (vanilla or custom) remain intact since is time is called before them.
* Won't show up if you have a mod that consists of only one level (determined by spmarathon_start's nextlevel; this won't trip if you manually set its marathonnext).
* Unconditional gratitude on the evaluation screen, instead of a negging "Try again..." if you didn't get all the emeralds (which you may not have been aiming for).
* Gorgeous new menu (no new assets required, unless you wanna give it a header later).
Changes which were required for the above but affect other areas of the game include:
* "useBlackRock" MainCFG block parameter, which can be used to disable the presence of the Black Rock or Egg Rock in both the Evaluation screen and the Marathon Run menu (for total conversions with different stories).
* Disabling Continues in NiGHTS mode, to match the most common singleplayer experience post 2.2.4's release (is reverted if useContinues is set to true).
* Hiding the exitmove "powerup" outside of multiplayer. (Okay, this isn't really related, I just saw this bug in action a lot while doing test runs and got annoyed enough to fix it here.)
* The ability to use V_DrawPromptBack (in hardcode only at the moment, but) to draw in terms of pixels rather than rows of text, by providing negative instead of positive inputs).
* A refactoring of redundant game saves smattered across the ending, credits, and evaluation - in addition to saving the game slightly earlier.
* Minor m_menu.c touchups and refactorings here and there.
Built using feedback from the official server's #speedruns channel, among other places.
2020-05-14 22:10:00 +00:00
mapheaderinfo [ num ] - > marathonnext = 0 ;
2019-06-23 22:51:42 +00:00
mapheaderinfo [ num ] - > startrings = 0 ;
2020-05-03 15:56:49 +00:00
mapheaderinfo [ num ] - > sstimer = 90 ;
mapheaderinfo [ num ] - > ssspheres = 1 ;
2020-05-03 16:33:18 +00:00
mapheaderinfo [ num ] - > gravity = FRACUNIT / 2 ;
2020-01-08 22:41:38 +00:00
mapheaderinfo [ num ] - > keywords [ 0 ] = ' \0 ' ;
2016-02-26 07:31:48 +00:00
snprintf ( mapheaderinfo [ num ] - > musname , 7 , " %sM " , G_BuildMapName ( i ) ) ;
2016-01-08 03:48:20 +00:00
mapheaderinfo [ num ] - > musname [ 6 ] = 0 ;
mapheaderinfo [ num ] - > mustrack = 0 ;
2018-09-18 14:22:17 +00:00
mapheaderinfo [ num ] - > muspos = 0 ;
2019-03-15 05:00:50 +00:00
mapheaderinfo [ num ] - > musinterfadeout = 0 ;
2020-07-18 20:36:41 +00:00
mapheaderinfo [ num ] - > musintername [ 0 ] = 0 ;
mapheaderinfo [ num ] - > muspostbossname [ 0 ] = 0 ;
2019-08-04 11:03:57 +00:00
mapheaderinfo [ num ] - > muspostbosstrack = 0 ;
mapheaderinfo [ num ] - > muspostbosspos = 0 ;
mapheaderinfo [ num ] - > muspostbossfadein = 0 ;
2019-08-05 00:02:38 +00:00
mapheaderinfo [ num ] - > musforcereset = - 1 ;
2014-03-15 16:59:03 +00:00
mapheaderinfo [ num ] - > forcecharacter [ 0 ] = ' \0 ' ;
mapheaderinfo [ num ] - > weather = 0 ;
mapheaderinfo [ num ] - > skynum = 1 ;
mapheaderinfo [ num ] - > skybox_scalex = 16 ;
mapheaderinfo [ num ] - > skybox_scaley = 16 ;
mapheaderinfo [ num ] - > skybox_scalez = 16 ;
mapheaderinfo [ num ] - > interscreen [ 0 ] = ' # ' ;
mapheaderinfo [ num ] - > runsoc [ 0 ] = ' # ' ;
mapheaderinfo [ num ] - > scriptname [ 0 ] = ' # ' ;
mapheaderinfo [ num ] - > precutscenenum = 0 ;
mapheaderinfo [ num ] - > cutscenenum = 0 ;
mapheaderinfo [ num ] - > countdown = 0 ;
mapheaderinfo [ num ] - > palette = UINT16_MAX ;
mapheaderinfo [ num ] - > numlaps = NUMLAPS_DEFAULT ;
mapheaderinfo [ num ] - > unlockrequired = - 1 ;
mapheaderinfo [ num ] - > levelselect = 0 ;
mapheaderinfo [ num ] - > bonustype = 0 ;
2018-08-13 18:16:33 +00:00
mapheaderinfo [ num ] - > maxbonuslives = - 1 ;
2014-03-15 16:59:03 +00:00
mapheaderinfo [ num ] - > levelflags = 0 ;
mapheaderinfo [ num ] - > menuflags = 0 ;
2017-01-01 16:24:47 +00:00
# if 1 // equivalent to "FlickyList = DEMO"
P_SetDemoFlickies ( num ) ;
# else // equivalent to "FlickyList = NONE"
P_DeleteFlickies ( num ) ;
# endif
2014-03-15 16:59:03 +00:00
P_DeleteGrades ( num ) ;
2014-08-04 03:49:33 +00:00
mapheaderinfo [ num ] - > customopts = NULL ;
mapheaderinfo [ num ] - > numCustomOptions = 0 ;
2014-03-15 16:59:03 +00:00
}
/** Allocates a new map-header structure.
*
* \ param i Index of header to allocate .
*/
void P_AllocMapHeader ( INT16 i )
{
if ( ! mapheaderinfo [ i ] )
{
mapheaderinfo [ i ] = Z_Malloc ( sizeof ( mapheader_t ) , PU_STATIC , NULL ) ;
2016-12-29 17:02:05 +00:00
mapheaderinfo [ i ] - > flickies = NULL ;
2014-03-15 16:59:03 +00:00
mapheaderinfo [ i ] - > grades = NULL ;
}
P_ClearSingleMapHeaderInfo ( i + 1 ) ;
}
/** NiGHTS Grades are a special structure,
* we initialize them here .
*
* \ param i Index of header to allocate grades for
* \ param mare The mare we ' re adding grades for
* \ param grades the string from DeHackEd , we work with it ourselves
*/
void P_AddGradesForMare ( INT16 i , UINT8 mare , char * gtext )
{
INT32 g ;
char * spos = gtext ;
CONS_Debug ( DBG_SETUP , " Map %d Mare %d: " , i + 1 , ( UINT16 ) mare + 1 ) ;
if ( mapheaderinfo [ i ] - > numGradedMares < mare + 1 )
{
mapheaderinfo [ i ] - > numGradedMares = mare + 1 ;
mapheaderinfo [ i ] - > grades = Z_Realloc ( mapheaderinfo [ i ] - > grades , sizeof ( nightsgrades_t ) * mapheaderinfo [ i ] - > numGradedMares , PU_STATIC , NULL ) ;
}
for ( g = 0 ; g < 6 ; + + g )
{
// Allow "partial" grading systems
if ( spos ! = NULL )
{
mapheaderinfo [ i ] - > grades [ mare ] . grade [ g ] = atoi ( spos ) ;
CONS_Debug ( DBG_SETUP , " %u " , atoi ( spos ) ) ;
// Grab next comma
spos = strchr ( spos , ' , ' ) ;
if ( spos )
+ + spos ;
}
else
{
// Grade not reachable
mapheaderinfo [ i ] - > grades [ mare ] . grade [ g ] = UINT32_MAX ;
}
}
CONS_Debug ( DBG_SETUP , " \n " ) ;
}
/** And this removes the grades safely.
*
* \ param i The header to remove grades from
*/
void P_DeleteGrades ( INT16 i )
{
if ( mapheaderinfo [ i ] - > grades )
Z_Free ( mapheaderinfo [ i ] - > grades ) ;
mapheaderinfo [ i ] - > grades = NULL ;
mapheaderinfo [ i ] - > numGradedMares = 0 ;
}
/** And this fetches the grades
*
* \ param pscore The player ' s score .
* \ param map The game map .
* \ param mare The mare to test .
*/
UINT8 P_GetGrade ( UINT32 pscore , INT16 map , UINT8 mare )
{
INT32 i ;
// Determining the grade
if ( mapheaderinfo [ map - 1 ] & & mapheaderinfo [ map - 1 ] - > grades & & mapheaderinfo [ map - 1 ] - > numGradedMares > = mare + 1 )
{
INT32 pgrade = 0 ;
for ( i = 0 ; i < 6 ; + + i )
{
if ( pscore > = mapheaderinfo [ map - 1 ] - > grades [ mare ] . grade [ i ] )
+ + pgrade ;
}
return ( UINT8 ) pgrade ;
}
return 0 ;
}
UINT8 P_HasGrades ( INT16 map , UINT8 mare )
{
// Determining the grade
// Mare 0 is treated as overall and is true if ANY grades exist
if ( mapheaderinfo [ map - 1 ] & & mapheaderinfo [ map - 1 ] - > grades
& & ( mare = = 0 | | mapheaderinfo [ map - 1 ] - > numGradedMares > = mare ) )
return true ;
return false ;
}
UINT32 P_GetScoreForGrade ( INT16 map , UINT8 mare , UINT8 grade )
{
// Get the score for the grade... if it exists
if ( grade = = GRADE_F | | grade > GRADE_S | | ! P_HasGrades ( map , mare ) ) return 0 ;
return mapheaderinfo [ map - 1 ] - > grades [ mare ] . grade [ grade - 1 ] ;
}
//
// levelflats
//
# define MAXLEVELFLATS 256
size_t numlevelflats ;
levelflat_t * levelflats ;
2019-12-23 15:36:26 +00:00
levelflat_t * foundflats ;
2014-03-15 16:59:03 +00:00
//SoM: Other files want this info.
size_t P_PrecacheLevelFlats ( void )
{
lumpnum_t lump ;
2019-08-18 17:16:48 +00:00
size_t i ;
2014-03-15 16:59:03 +00:00
//SoM: 4/18/2000: New flat code to make use of levelflats.
2019-08-18 17:16:48 +00:00
flatmemory = 0 ;
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < numlevelflats ; i + + )
{
2019-10-21 03:21:22 +00:00
if ( levelflats [ i ] . type = = LEVELFLAT_FLAT )
{
lump = levelflats [ i ] . u . flat . lumpnum ;
if ( devparm )
flatmemory + = W_LumpLength ( lump ) ;
R_GetFlat ( lump ) ;
}
2014-03-15 16:59:03 +00:00
}
return flatmemory ;
}
2019-10-21 03:21:22 +00:00
/*
levelflat refers to an array of level flats ,
or NULL if we want to allocate it now .
*/
static INT32
2020-01-22 00:47:47 +00:00
Ploadflat ( levelflat_t * levelflat , const char * flatname , boolean resize )
2014-03-15 16:59:03 +00:00
{
2019-12-04 18:41:29 +00:00
# ifndef NO_PNG_LUMPS
2019-10-21 03:21:22 +00:00
UINT8 buffer [ 8 ] ;
2019-12-04 18:41:29 +00:00
# endif
2014-03-15 16:59:03 +00:00
2019-10-21 03:21:22 +00:00
lumpnum_t flatnum ;
int texturenum ;
2020-08-16 00:52:01 +00:00
UINT8 * flatpatch ;
2020-01-06 21:22:23 +00:00
size_t lumplength ;
2014-03-15 16:59:03 +00:00
2019-10-21 03:21:22 +00:00
size_t i ;
2019-05-21 18:24:26 +00:00
2020-01-22 00:47:47 +00:00
// Scan through the already found flats, return if it matches.
for ( i = 0 ; i < numlevelflats ; i + + )
2019-10-21 03:21:22 +00:00
{
2020-01-22 00:47:47 +00:00
if ( strnicmp ( levelflat [ i ] . name , flatname , 8 ) = = 0 )
return i ;
2019-10-21 03:21:22 +00:00
}
2014-03-15 16:59:03 +00:00
2020-01-22 00:47:47 +00:00
if ( resize )
2019-10-21 03:21:22 +00:00
{
// allocate new flat memory
levelflats = Z_Realloc ( levelflats , ( numlevelflats + 1 ) * sizeof ( * levelflats ) , PU_LEVEL , NULL ) ;
levelflat = levelflats + numlevelflats ;
2014-03-15 16:59:03 +00:00
}
2020-01-22 00:47:47 +00:00
else
{
if ( numlevelflats > = MAXLEVELFLATS )
I_Error ( " Too many flats in level \n " ) ;
levelflat + = numlevelflats ;
}
2014-03-15 16:59:03 +00:00
2019-10-21 03:21:22 +00:00
// Store the name.
strlcpy ( levelflat - > name , flatname , sizeof ( levelflat - > name ) ) ;
strupr ( levelflat - > name ) ;
/* If we can't find a flat, try looking for a texture! */
2020-06-27 21:30:41 +00:00
if ( ( flatnum = R_GetFlatNumForName ( levelflat - > name ) ) = = LUMPERROR )
2019-10-21 03:21:22 +00:00
{
2020-06-27 21:30:41 +00:00
if ( ( texturenum = R_CheckTextureNumForName ( levelflat - > name ) ) = = - 1 )
2019-10-21 03:21:22 +00:00
{
2019-11-09 03:08:22 +00:00
// check for REDWALL
if ( ( texturenum = R_CheckTextureNumForName ( " REDWALL " ) ) ! = - 1 )
goto texturefound ;
// check for REDFLR
else if ( ( flatnum = R_GetFlatNumForName ( " REDFLR " ) ) ! = LUMPERROR )
goto flatfound ;
// nevermind
2019-10-21 03:21:22 +00:00
levelflat - > type = LEVELFLAT_NONE ;
}
else
{
2019-11-09 03:08:22 +00:00
texturefound :
2019-10-21 03:21:22 +00:00
levelflat - > type = LEVELFLAT_TEXTURE ;
levelflat - > u . texture . num = texturenum ;
levelflat - > u . texture . lastnum = texturenum ;
/* start out unanimated */
levelflat - > u . texture . basenum = - 1 ;
}
}
else
{
2019-11-09 03:08:22 +00:00
flatfound :
2019-10-21 03:21:22 +00:00
/* This could be a flat, patch, or PNG. */
2020-01-07 16:27:59 +00:00
flatpatch = W_CacheLumpNum ( flatnum , PU_CACHE ) ;
2020-01-06 21:22:23 +00:00
lumplength = W_LumpLength ( flatnum ) ;
2020-08-16 00:52:01 +00:00
if ( Picture_CheckIfDoomPatch ( ( softwarepatch_t * ) flatpatch , lumplength ) )
2019-10-21 03:21:22 +00:00
levelflat - > type = LEVELFLAT_PATCH ;
else
{
# ifndef NO_PNG_LUMPS
/*
Only need eight bytes for PNG headers .
FIXME : Put this elsewhere .
*/
W_ReadLumpHeader ( flatnum , buffer , 8 , 0 ) ;
2020-01-06 23:16:48 +00:00
if ( Picture_IsLumpPNG ( buffer , lumplength ) )
2019-10-21 03:21:22 +00:00
levelflat - > type = LEVELFLAT_PNG ;
else
# endif /*NO_PNG_LUMPS*/
levelflat - > type = LEVELFLAT_FLAT ; /* phew */
}
2020-01-07 17:07:14 +00:00
if ( flatpatch )
Z_Free ( flatpatch ) ;
2019-10-21 03:21:22 +00:00
levelflat - > u . flat . lumpnum = flatnum ;
levelflat - > u . flat . baselumpnum = LUMPERROR ;
}
2020-01-21 23:11:16 +00:00
# ifndef ZDEBUG
CONS_Debug ( DBG_SETUP , " flat #%03d: %s \n " , atoi ( sizeu1 ( numlevelflats ) ) , levelflat - > name ) ;
# endif
2019-10-21 03:21:22 +00:00
return ( numlevelflats + + ) ;
}
// Auxiliary function. Find a flat in the active wad files,
// allocate an id for it, and set the levelflat (to speedup search)
INT32 P_AddLevelFlat ( const char * flatname , levelflat_t * levelflat )
{
2020-01-22 00:47:47 +00:00
return Ploadflat ( levelflat , flatname , false ) ;
2014-03-15 16:59:03 +00:00
}
2016-12-08 21:45:25 +00:00
// help function for Lua and $$$.sav reading
// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
// no longer a static func in lua_maplib.c because p_saveg.c also needs it
//
INT32 P_AddLevelFlatRuntime ( const char * flatname )
{
2020-01-22 00:47:47 +00:00
return Ploadflat ( levelflats , flatname , true ) ;
2016-12-08 21:45:25 +00:00
}
// help function for $$$.sav checking
// this simply returns the flat # for the name given
//
INT32 P_CheckLevelFlat ( const char * flatname )
{
size_t i ;
levelflat_t * levelflat = levelflats ;
//
// scan through the already found flats
//
for ( i = 0 ; i < numlevelflats ; i + + , levelflat + + )
if ( strnicmp ( levelflat - > name , flatname , 8 ) = = 0 )
break ;
if ( i = = numlevelflats )
return 0 ; // ??? flat was not found, this should not happen!
// level flat id
return ( INT32 ) i ;
}
2014-03-15 16:59:03 +00:00
//
// P_ReloadRings
2019-12-24 09:50:49 +00:00
// Used by NiGHTS, clears all ring/sphere/hoop/etc items and respawns them
2014-03-15 16:59:03 +00:00
//
void P_ReloadRings ( void )
{
mobj_t * mo ;
thinker_t * th ;
size_t i , numHoops = 0 ;
// Okay, if you have more than 4000 hoops in your map,
// you're insane.
mapthing_t * hoopsToRespawn [ 4096 ] ;
mapthing_t * mt = mapthings ;
2018-06-03 21:41:54 +00:00
// scan the thinkers to find rings/spheres/hoops to unset
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
continue ;
2014-03-15 16:59:03 +00:00
mo = ( mobj_t * ) th ;
if ( mo - > type = = MT_HOOPCENTER )
{
// Hoops give me a headache
if ( mo - > threshold = = 4242 ) // Dead hoop
{
hoopsToRespawn [ numHoops + + ] = mo - > spawnpoint ;
P_RemoveMobj ( mo ) ;
}
continue ;
}
2018-06-05 16:22:28 +00:00
if ( ! ( mo - > type = = MT_RING | | mo - > type = = MT_COIN
| | mo - > type = = MT_BLUESPHERE | | mo - > type = = MT_BOMBSPHERE
2018-06-03 21:41:54 +00:00
| | mo - > type = = MT_NIGHTSCHIP | | mo - > type = = MT_NIGHTSSTAR ) )
2014-03-15 16:59:03 +00:00
continue ;
// Don't auto-disintegrate things being pulled to us
if ( mo - > flags2 & MF2_NIGHTSPULL )
continue ;
P_RemoveMobj ( mo ) ;
}
// Reiterate through mapthings
for ( i = 0 ; i < nummapthings ; i + + , mt + + )
{
// Notice an omission? We handle hoops differently.
2018-06-08 16:16:20 +00:00
if ( mt - > type = = mobjinfo [ MT_RING ] . doomednum | | mt - > type = = mobjinfo [ MT_COIN ] . doomednum
2019-12-24 09:50:49 +00:00
| | mt - > type = = mobjinfo [ MT_REDTEAMRING ] . doomednum | | mt - > type = = mobjinfo [ MT_BLUETEAMRING ] . doomednum
| | mt - > type = = mobjinfo [ MT_BLUESPHERE ] . doomednum | | mt - > type = = mobjinfo [ MT_BOMBSPHERE ] . doomednum )
2014-03-15 16:59:03 +00:00
{
mt - > mobj = NULL ;
2019-12-24 11:52:43 +00:00
P_SetBonusTime ( P_SpawnMapThing ( mt ) ) ;
2019-12-24 09:50:49 +00:00
}
2021-12-20 20:14:39 +00:00
else if ( mt - > type > = 600 & & mt - > type < = 611 ) // Item patterns
2019-12-24 09:50:49 +00:00
{
mt - > mobj = NULL ;
P_SpawnItemPattern ( mt , true ) ;
2014-03-15 16:59:03 +00:00
}
}
for ( i = 0 ; i < numHoops ; i + + )
{
2019-12-24 09:50:49 +00:00
P_SpawnHoop ( hoopsToRespawn [ i ] ) ;
2018-06-03 21:41:54 +00:00
}
}
void P_SwitchSpheresBonusMode ( boolean bonustime )
{
mobj_t * mo ;
thinker_t * th ;
// scan the thinkers to find spheres to switch
2019-04-20 21:29:20 +00:00
for ( th = thlist [ THINK_MOBJ ] . next ; th ! = & thlist [ THINK_MOBJ ] ; th = th - > next )
2018-06-03 21:41:54 +00:00
{
2019-07-12 23:42:03 +00:00
if ( th - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
continue ;
2018-06-03 21:41:54 +00:00
mo = ( mobj_t * ) th ;
2018-08-10 04:20:30 +00:00
if ( mo - > type ! = MT_BLUESPHERE & & mo - > type ! = MT_NIGHTSCHIP
& & mo - > type ! = MT_FLINGBLUESPHERE & & mo - > type ! = MT_FLINGNIGHTSCHIP )
2018-06-03 21:41:54 +00:00
continue ;
if ( ! mo - > health )
continue ;
P_SetMobjState ( mo , ( ( bonustime ) ? mo - > info - > raisestate : mo - > info - > spawnstate ) ) ;
2014-03-15 16:59:03 +00:00
}
}
# ifdef SCANTHINGS
void P_ScanThings ( INT16 mapnum , INT16 wadnum , INT16 lumpnum )
{
size_t i , n ;
UINT8 * data , * datastart ;
UINT16 type , maprings ;
INT16 tol ;
UINT32 flags ;
tol = mapheaderinfo [ mapnum - 1 ] - > typeoflevel ;
if ( ! ( tol & TOL_SP ) )
return ;
flags = mapheaderinfo [ mapnum - 1 ] - > levelflags ;
n = W_LumpLengthPwad ( wadnum , lumpnum ) / ( 5 * sizeof ( INT16 ) ) ;
//CONS_Printf("%u map things found!\n", n);
maprings = 0 ;
data = datastart = W_CacheLumpNumPwad ( wadnum , lumpnum , PU_STATIC ) ;
for ( i = 0 ; i < n ; i + + )
{
data + = 3 * sizeof ( INT16 ) ; // skip x y position, angle
type = READUINT16 ( data ) & 4095 ;
data + = sizeof ( INT16 ) ; // skip options
switch ( type )
{
case 300 : // MT_RING
case 1800 : // MT_COIN
case 308 : // red team ring
case 309 : // blue team ring
maprings + + ;
break ;
case 400 : // MT_SUPERRINGBOX
case 414 : // red ring box
case 415 : // blue ring box
case 603 : // 10 diagonal rings
maprings + = 10 ;
break ;
case 600 : // 5 vertical rings
case 601 : // 5 vertical rings
case 602 : // 5 diagonal rings
maprings + = 5 ;
break ;
case 604 : // 8 circle rings
case 609 : // 16 circle rings & wings
maprings + = 8 ;
break ;
case 605 : // 16 circle rings
maprings + = 16 ;
break ;
case 608 : // 8 circle rings & wings
maprings + = 4 ;
break ;
}
}
Z_Free ( datastart ) ;
if ( maprings )
CONS_Printf ( " %s has %u rings \n " , G_BuildMapName ( mapnum ) , maprings ) ;
}
# endif
2019-12-15 08:49:54 +00:00
static void P_SpawnEmeraldHunt ( void )
2019-12-10 13:21:08 +00:00
{
2020-04-22 21:17:18 +00:00
INT32 emer [ 3 ] , num [ MAXHUNTEMERALDS ] , i , randomkey ;
2020-04-22 16:58:40 +00:00
fixed_t x , y , z ;
2019-12-10 13:21:08 +00:00
2020-04-22 21:17:18 +00:00
for ( i = 0 ; i < numhuntemeralds ; i + + )
2020-04-22 20:46:12 +00:00
num [ i ] = i ;
2019-12-10 13:21:08 +00:00
2020-04-22 21:17:18 +00:00
for ( i = 0 ; i < 3 ; i + + )
2019-12-10 13:21:08 +00:00
{
2020-04-22 20:46:12 +00:00
// generate random index, shuffle afterwards
randomkey = P_RandomKey ( numhuntemeralds - - ) ;
emer [ i ] = num [ randomkey ] ;
num [ randomkey ] = num [ numhuntemeralds ] ;
num [ numhuntemeralds ] = emer [ i ] ;
// spawn emerald
x = huntemeralds [ emer [ i ] ] - > x < < FRACBITS ;
y = huntemeralds [ emer [ i ] ] - > y < < FRACBITS ;
z = P_GetMapThingSpawnHeight ( MT_EMERHUNT , huntemeralds [ emer [ i ] ] , x , y ) ;
2020-04-22 16:58:40 +00:00
P_SetMobjStateNF ( P_SpawnMobj ( x , y , z , MT_EMERHUNT ) ,
2020-04-22 20:46:12 +00:00
mobjinfo [ MT_EMERHUNT ] . spawnstate + i ) ;
2019-12-10 13:21:08 +00:00
}
}
2019-12-28 10:30:39 +00:00
static void P_SpawnMapThings ( boolean spawnemblems )
2017-05-16 19:10:02 +00:00
{
2017-05-18 19:13:18 +00:00
size_t i ;
2017-05-16 19:10:02 +00:00
mapthing_t * mt ;
2019-12-22 22:02:47 +00:00
// Spawn axis points first so they are at the front of the list for fast searching.
2019-12-09 12:26:31 +00:00
for ( i = 0 , mt = mapthings ; i < nummapthings ; i + + , mt + + )
2014-03-15 16:59:03 +00:00
{
2019-12-09 12:26:31 +00:00
switch ( mt - > type )
{
case 1700 : // MT_AXIS
case 1701 : // MT_AXISTRANSFER
case 1702 : // MT_AXISTRANSFERLINE
mt - > mobj = NULL ;
P_SpawnMapThing ( mt ) ;
break ;
default :
break ;
}
}
2015-05-16 05:02:01 +00:00
2019-12-09 12:26:31 +00:00
numhuntemeralds = 0 ;
2014-03-15 16:59:03 +00:00
2019-12-09 12:26:31 +00:00
for ( i = 0 , mt = mapthings ; i < nummapthings ; i + + , mt + + )
{
2014-03-15 16:59:03 +00:00
if ( mt - > type = = 1700 // MT_AXIS
| | mt - > type = = 1701 // MT_AXISTRANSFER
| | mt - > type = = 1702 ) // MT_AXISTRANSFERLINE
continue ; // These were already spawned
2019-12-28 10:30:39 +00:00
if ( ! spawnemblems & & mt - > type = = mobjinfo [ MT_EMBLEM ] . doomednum )
2019-02-03 13:32:07 +00:00
continue ;
2014-03-15 16:59:03 +00:00
mt - > mobj = NULL ;
2019-12-24 09:50:49 +00:00
2021-12-20 20:14:39 +00:00
if ( mt - > type > = 600 & & mt - > type < = 611 ) // item patterns
2019-12-24 09:50:49 +00:00
P_SpawnItemPattern ( mt , false ) ;
2021-12-19 09:16:03 +00:00
else if ( mt - > type = = 1713 ) // hoops
2019-12-24 09:50:49 +00:00
P_SpawnHoop ( mt ) ;
else // Everything else
P_SpawnMapThing ( mt ) ;
2014-03-15 16:59:03 +00:00
}
// random emeralds for hunt
if ( numhuntemeralds )
2019-12-15 08:49:54 +00:00
P_SpawnEmeraldHunt ( ) ;
2014-03-15 16:59:03 +00:00
}
// Experimental groovy write function!
2020-11-02 03:31:10 +00:00
void P_WriteThings ( void )
2014-03-15 16:59:03 +00:00
{
size_t i , length ;
mapthing_t * mt ;
UINT8 * savebuffer , * savebuf_p ;
INT16 temp ;
savebuf_p = savebuffer = ( UINT8 * ) malloc ( nummapthings * sizeof ( mapthing_t ) ) ;
if ( ! savebuf_p )
{
CONS_Alert ( CONS_ERROR , M_GetText ( " No more free memory for thing writing! \n " ) ) ;
return ;
}
mt = mapthings ;
for ( i = 0 ; i < nummapthings ; i + + , mt + + )
{
WRITEINT16 ( savebuf_p , mt - > x ) ;
WRITEINT16 ( savebuf_p , mt - > y ) ;
WRITEINT16 ( savebuf_p , mt - > angle ) ;
temp = ( INT16 ) ( mt - > type + ( ( INT16 ) mt - > extrainfo < < 12 ) ) ;
WRITEINT16 ( savebuf_p , temp ) ;
WRITEUINT16 ( savebuf_p , mt - > options ) ;
}
length = savebuf_p - savebuffer ;
FIL_WriteFile ( va ( " newthings%d.lmp " , gamemap ) , savebuffer , length ) ;
free ( savebuffer ) ;
savebuf_p = NULL ;
CONS_Printf ( M_GetText ( " newthings%d.lmp saved. \n " ) , gamemap ) ;
}
2019-12-28 15:40:35 +00:00
//
// MAP LOADING FUNCTIONS
//
static void P_LoadVertices ( UINT8 * data )
2017-05-16 19:10:02 +00:00
{
2019-12-28 15:58:48 +00:00
mapvertex_t * mv = ( mapvertex_t * ) data ;
vertex_t * v = vertexes ;
2019-12-12 09:35:38 +00:00
size_t i ;
2017-05-16 19:10:02 +00:00
2019-12-28 15:40:35 +00:00
// Copy and convert vertex coordinates, internal representation as fixed.
2019-12-28 15:58:48 +00:00
for ( i = 0 ; i < numvertexes ; i + + , v + + , mv + + )
2017-05-16 19:10:02 +00:00
{
2019-12-28 15:58:48 +00:00
v - > x = SHORT ( mv - > x ) < < FRACBITS ;
v - > y = SHORT ( mv - > y ) < < FRACBITS ;
2020-01-04 23:34:16 +00:00
v - > floorzset = v - > ceilingzset = false ;
v - > floorz = v - > ceilingz = 0 ;
2019-12-12 09:35:38 +00:00
}
}
2019-12-28 16:29:58 +00:00
static void P_InitializeSector ( sector_t * ss )
{
memset ( & ss - > soundorg , 0 , sizeof ( ss - > soundorg ) ) ;
ss - > validcount = 0 ;
ss - > thinglist = NULL ;
ss - > floordata = NULL ;
ss - > ceilingdata = NULL ;
ss - > lightingdata = NULL ;
ss - > fadecolormapdata = NULL ;
ss - > heightsec = - 1 ;
ss - > camsec = - 1 ;
ss - > floorlightsec = ss - > ceilinglightsec = - 1 ;
2020-04-17 21:54:37 +00:00
ss - > crumblestate = CRUMBLE_NONE ;
2019-12-28 16:29:58 +00:00
ss - > touching_thinglist = NULL ;
ss - > linecount = 0 ;
ss - > lines = NULL ;
ss - > ffloors = NULL ;
ss - > attached = NULL ;
ss - > attachedsolid = NULL ;
ss - > numattached = 0 ;
ss - > maxattached = 1 ;
ss - > lightlist = NULL ;
ss - > numlights = 0 ;
ss - > moved = true ;
ss - > extra_colormap = NULL ;
ss - > gravity = NULL ;
ss - > verticalflip = false ;
ss - > flags = SF_FLIPSPECIAL_FLOOR ;
ss - > cullheight = NULL ;
ss - > floorspeed = ss - > ceilspeed = 0 ;
ss - > preciplist = NULL ;
ss - > touching_preciplist = NULL ;
ss - > f_slope = NULL ;
ss - > c_slope = NULL ;
ss - > hasslope = false ;
ss - > spawn_lightlevel = ss - > lightlevel ;
ss - > spawn_extra_colormap = NULL ;
}
2019-12-28 15:40:35 +00:00
static void P_LoadSectors ( UINT8 * data )
2019-12-12 09:35:38 +00:00
{
2019-12-28 15:40:35 +00:00
mapsector_t * ms = ( mapsector_t * ) data ;
sector_t * ss = sectors ;
2019-12-12 09:35:38 +00:00
size_t i ;
2019-12-28 15:40:35 +00:00
// For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss.
for ( i = 0 ; i < numsectors ; i + + , ss + + , ms + + )
2019-12-12 09:35:38 +00:00
{
2019-12-28 15:40:35 +00:00
ss - > floorheight = SHORT ( ms - > floorheight ) < < FRACBITS ;
ss - > ceilingheight = SHORT ( ms - > ceilingheight ) < < FRACBITS ;
2017-05-16 19:10:02 +00:00
2019-12-28 15:40:35 +00:00
ss - > floorpic = P_AddLevelFlat ( ms - > floorpic , foundflats ) ;
ss - > ceilingpic = P_AddLevelFlat ( ms - > ceilingpic , foundflats ) ;
ss - > lightlevel = SHORT ( ms - > lightlevel ) ;
ss - > special = SHORT ( ms - > special ) ;
2020-04-17 20:29:26 +00:00
Tag_FSet ( & ss - > tags , SHORT ( ms - > tag ) ) ;
2019-12-28 15:40:35 +00:00
2019-12-30 20:23:00 +00:00
ss - > floor_xoffs = ss - > floor_yoffs = 0 ;
ss - > ceiling_xoffs = ss - > ceiling_yoffs = 0 ;
ss - > floorpic_angle = ss - > ceilingpic_angle = 0 ;
2021-09-19 06:58:21 +00:00
ss - > floorlightlevel = ss - > ceilinglightlevel = 0 ;
ss - > floorlightabsolute = ss - > ceilinglightabsolute = false ;
2020-03-20 11:19:02 +00:00
ss - > colormap_protected = false ;
2019-12-28 16:29:58 +00:00
P_InitializeSector ( ss ) ;
2019-12-28 15:40:35 +00:00
}
}
2019-12-28 16:21:31 +00:00
static void P_InitializeLinedef ( line_t * ld )
2019-12-28 15:40:35 +00:00
{
2019-12-28 16:21:31 +00:00
vertex_t * v1 = ld - > v1 ;
vertex_t * v2 = ld - > v2 ;
UINT8 j ;
ld - > dx = v2 - > x - v1 - > x ;
ld - > dy = v2 - > y - v1 - > y ;
ld - > bbox [ BOXLEFT ] = min ( v1 - > x , v2 - > x ) ;
ld - > bbox [ BOXRIGHT ] = max ( v1 - > x , v2 - > x ) ;
ld - > bbox [ BOXBOTTOM ] = min ( v1 - > y , v2 - > y ) ;
ld - > bbox [ BOXTOP ] = max ( v1 - > y , v2 - > y ) ;
if ( ! ld - > dx )
ld - > slopetype = ST_VERTICAL ;
else if ( ! ld - > dy )
ld - > slopetype = ST_HORIZONTAL ;
else if ( ( ld - > dy > 0 ) = = ( ld - > dx > 0 ) )
ld - > slopetype = ST_POSITIVE ;
else
ld - > slopetype = ST_NEGATIVE ;
2019-12-28 15:40:35 +00:00
2019-12-28 16:21:31 +00:00
ld - > frontsector = ld - > backsector = NULL ;
2019-12-28 15:40:35 +00:00
2019-12-28 16:21:31 +00:00
ld - > validcount = 0 ;
ld - > polyobj = NULL ;
2019-12-12 09:35:38 +00:00
2019-12-28 16:21:31 +00:00
ld - > text = NULL ;
ld - > callcount = 0 ;
2019-12-12 09:35:38 +00:00
2019-12-28 16:21:31 +00:00
// cph 2006/09/30 - fix sidedef errors right away.
// cph 2002/07/20 - these errors are fatal if not fixed, so apply them
for ( j = 0 ; j < 2 ; j + + )
if ( ld - > sidenum [ j ] ! = 0xffff & & ld - > sidenum [ j ] > = ( UINT16 ) numsides )
2017-05-16 19:10:02 +00:00
{
2019-12-28 16:21:31 +00:00
ld - > sidenum [ j ] = 0xffff ;
2019-12-28 16:37:32 +00:00
CONS_Debug ( DBG_SETUP , " P_InitializeLinedef: Linedef %s has out-of-range sidedef number \n " , sizeu1 ( ( size_t ) ( ld - lines ) ) ) ;
2017-05-16 19:10:02 +00:00
}
2019-12-28 16:21:31 +00:00
// killough 11/98: fix common wad errors (missing sidedefs):
if ( ld - > sidenum [ 0 ] = = 0xffff )
{
ld - > sidenum [ 0 ] = 0 ; // Substitute dummy sidedef for missing right side
// cph - print a warning about the bug
2019-12-28 16:37:32 +00:00
CONS_Debug ( DBG_SETUP , " P_InitializeLinedef: Linedef %s missing first sidedef \n " , sizeu1 ( ( size_t ) ( ld - lines ) ) ) ;
2019-12-28 16:21:31 +00:00
}
2017-05-16 19:10:02 +00:00
2019-12-28 16:21:31 +00:00
if ( ( ld - > sidenum [ 1 ] = = 0xffff ) & & ( ld - > flags & ML_TWOSIDED ) )
{
ld - > flags & = ~ ML_TWOSIDED ; // Clear 2s flag for missing left side
// cph - print a warning about the bug
2019-12-28 16:37:32 +00:00
CONS_Debug ( DBG_SETUP , " P_InitializeLinedef: Linedef %s has two-sided flag set, but no second sidedef \n " , sizeu1 ( ( size_t ) ( ld - lines ) ) ) ;
2019-12-28 16:21:31 +00:00
}
2017-05-16 19:10:02 +00:00
2019-12-29 08:39:50 +00:00
if ( ld - > sidenum [ 0 ] ! = 0xffff )
{
2019-12-28 16:21:31 +00:00
sides [ ld - > sidenum [ 0 ] ] . special = ld - > special ;
2019-12-29 08:39:50 +00:00
sides [ ld - > sidenum [ 0 ] ] . line = ld ;
}
if ( ld - > sidenum [ 1 ] ! = 0xffff )
{
2019-12-28 16:21:31 +00:00
sides [ ld - > sidenum [ 1 ] ] . special = ld - > special ;
2019-12-29 08:39:50 +00:00
sides [ ld - > sidenum [ 1 ] ] . line = ld ;
}
2019-12-28 16:21:31 +00:00
}
2017-05-16 19:10:02 +00:00
2020-01-01 13:27:01 +00:00
static void P_SetLinedefV1 ( size_t i , UINT16 vertex_num )
{
if ( vertex_num > = numvertexes )
{
CONS_Debug ( DBG_SETUP , " P_SetLinedefV1: linedef %s has out-of-range v1 num %u \n " , sizeu1 ( i ) , vertex_num ) ;
vertex_num = 0 ;
}
lines [ i ] . v1 = & vertexes [ vertex_num ] ;
}
static void P_SetLinedefV2 ( size_t i , UINT16 vertex_num )
{
if ( vertex_num > = numvertexes )
{
CONS_Debug ( DBG_SETUP , " P_SetLinedefV2: linedef %s has out-of-range v2 num %u \n " , sizeu1 ( i ) , vertex_num ) ;
vertex_num = 0 ;
}
lines [ i ] . v2 = & vertexes [ vertex_num ] ;
}
2019-12-28 16:21:31 +00:00
static void P_LoadLinedefs ( UINT8 * data )
{
maplinedef_t * mld = ( maplinedef_t * ) data ;
line_t * ld = lines ;
size_t i ;
2017-05-16 19:10:02 +00:00
2019-12-28 16:21:31 +00:00
for ( i = 0 ; i < numlines ; i + + , mld + + , ld + + )
{
ld - > flags = SHORT ( mld - > flags ) ;
ld - > special = SHORT ( mld - > special ) ;
2020-04-17 20:29:26 +00:00
Tag_FSet ( & ld - > tags , SHORT ( mld - > tag ) ) ;
2020-01-02 11:23:14 +00:00
memset ( ld - > args , 0 , NUMLINEARGS * sizeof ( * ld - > args ) ) ;
2020-01-12 23:59:35 +00:00
memset ( ld - > stringargs , 0x00 , NUMLINESTRINGARGS * sizeof ( * ld - > stringargs ) ) ;
2020-02-10 19:26:29 +00:00
ld - > alpha = FRACUNIT ;
2020-05-03 18:41:37 +00:00
ld - > executordelay = 0 ;
2020-01-01 13:27:01 +00:00
P_SetLinedefV1 ( i , SHORT ( mld - > v1 ) ) ;
P_SetLinedefV2 ( i , SHORT ( mld - > v2 ) ) ;
2017-05-16 19:10:02 +00:00
2019-12-28 16:21:31 +00:00
ld - > sidenum [ 0 ] = SHORT ( mld - > sidenum [ 0 ] ) ;
ld - > sidenum [ 1 ] = SHORT ( mld - > sidenum [ 1 ] ) ;
2014-03-15 16:59:03 +00:00
2019-12-28 16:21:31 +00:00
P_InitializeLinedef ( ld ) ;
2017-05-18 19:13:18 +00:00
}
}
2014-03-15 16:59:03 +00:00
2020-01-01 13:27:01 +00:00
static void P_SetSidedefSector ( size_t i , UINT16 sector_num )
{
// cph 2006/09/30 - catch out-of-range sector numbers; use sector 0 instead
if ( sector_num > = numsectors )
{
CONS_Debug ( DBG_SETUP , " P_SetSidedefSector: sidedef %s has out-of-range sector num %u \n " , sizeu1 ( i ) , sector_num ) ;
sector_num = 0 ;
}
sides [ i ] . sector = & sectors [ sector_num ] ;
}
2020-01-01 14:10:41 +00:00
static void P_InitializeSidedef ( side_t * sd )
{
if ( ! sd - > line )
{
2020-01-01 14:11:39 +00:00
CONS_Debug ( DBG_SETUP , " P_LoadSidedefs: Sidedef %s is not used by any linedef \n " , sizeu1 ( ( size_t ) ( sd - sides ) ) ) ;
2020-01-01 14:10:41 +00:00
sd - > line = & lines [ 0 ] ;
sd - > special = sd - > line - > special ;
}
sd - > text = NULL ;
sd - > colormap_data = NULL ;
}
2019-12-28 15:40:35 +00:00
static void P_LoadSidedefs ( UINT8 * data )
2014-03-15 16:59:03 +00:00
{
2019-12-28 15:58:48 +00:00
mapsidedef_t * msd = ( mapsidedef_t * ) data ;
side_t * sd = sides ;
size_t i ;
2014-03-15 16:59:03 +00:00
2019-12-28 15:58:48 +00:00
for ( i = 0 ; i < numsides ; i + + , sd + + , msd + + )
2014-03-15 16:59:03 +00:00
{
2020-01-01 13:13:24 +00:00
INT16 textureoffset = SHORT ( msd - > textureoffset ) ;
boolean isfrontside ;
2020-01-01 14:10:41 +00:00
P_InitializeSidedef ( sd ) ;
2020-01-01 13:13:24 +00:00
isfrontside = sd - > line - > sidenum [ 0 ] = = i ;
2014-03-15 16:59:03 +00:00
2020-01-01 13:13:24 +00:00
// Repeat count for midtexture
if ( ( ( sd - > line - > flags & ( ML_TWOSIDED | ML_EFFECT5 ) ) = = ( ML_TWOSIDED | ML_EFFECT5 ) )
& & ! ( sd - > special > = 300 & & sd - > special < 500 ) ) // exempt linedef exec specials
{
2020-01-10 22:32:31 +00:00
sd - > repeatcnt = ( INT16 ) ( ( ( UINT16 ) textureoffset ) > > 12 ) ;
sd - > textureoffset = ( ( ( UINT16 ) textureoffset ) & 2047 ) < < FRACBITS ;
2020-01-01 13:13:24 +00:00
}
else
{
sd - > repeatcnt = 0 ;
sd - > textureoffset = textureoffset < < FRACBITS ;
}
2014-03-15 16:59:03 +00:00
sd - > rowoffset = SHORT ( msd - > rowoffset ) < < FRACBITS ;
2020-01-01 13:27:01 +00:00
P_SetSidedefSector ( i , SHORT ( msd - > sector ) ) ;
2014-03-15 16:59:03 +00:00
2019-12-28 15:58:48 +00:00
// Special info stored in texture fields!
2014-03-15 16:59:03 +00:00
switch ( sd - > special )
{
case 606 : //SoM: 4/4/2000: Just colormap transfer
2018-06-14 20:51:21 +00:00
case 447 : // Change colormap of tagged sectors! -- Monster Iestyn 14/06/18
2018-09-12 13:06:38 +00:00
case 455 : // Fade colormaps! mazmazz 9/12/2018 (:flag_us:)
2014-03-15 16:59:03 +00:00
// SoM: R_CreateColormap will only create a colormap in software mode...
// Perhaps we should just call it instead of doing the calculations here.
2020-03-20 10:19:30 +00:00
if ( ! udmf )
{
sd - > colormap_data = R_CreateColormapFromLinedef ( msd - > toptexture , msd - > midtexture , msd - > bottomtexture ) ;
sd - > toptexture = sd - > midtexture = sd - > bottomtexture = 0 ;
}
2018-09-10 20:32:54 +00:00
break ;
2014-03-15 16:59:03 +00:00
case 413 : // Change music
2016-01-08 03:48:20 +00:00
{
char process [ 8 + 1 ] ;
sd - > toptexture = sd - > midtexture = sd - > bottomtexture = 0 ;
if ( msd - > bottomtexture [ 0 ] ! = ' - ' | | msd - > bottomtexture [ 1 ] ! = ' \0 ' )
{
M_Memcpy ( process , msd - > bottomtexture , 8 ) ;
process [ 8 ] = ' \0 ' ;
2018-09-18 19:28:57 +00:00
sd - > bottomtexture = get_number ( process ) ;
2016-01-08 03:48:20 +00:00
}
2018-09-18 19:28:57 +00:00
if ( ! ( msd - > midtexture [ 0 ] = = ' - ' & & msd - > midtexture [ 1 ] = = ' \0 ' ) | | msd - > midtexture [ 1 ] ! = ' \0 ' )
{
M_Memcpy ( process , msd - > midtexture , 8 ) ;
process [ 8 ] = ' \0 ' ;
sd - > midtexture = get_number ( process ) ;
}
sd - > text = Z_Malloc ( 7 , PU_LEVEL , NULL ) ;
2019-12-29 08:39:50 +00:00
if ( isfrontside & & ! ( msd - > toptexture [ 0 ] = = ' - ' & & msd - > toptexture [ 1 ] = = ' \0 ' ) )
2018-09-18 19:28:57 +00:00
{
M_Memcpy ( process , msd - > toptexture , 8 ) ;
process [ 8 ] = ' \0 ' ;
// If they type in O_ or D_ and their music name, just shrug,
// then copy the rest instead.
if ( ( process [ 0 ] = = ' O ' | | process [ 0 ] = = ' D ' ) & & process [ 7 ] )
M_Memcpy ( sd - > text , process + 2 , 6 ) ;
else // Assume it's a proper music name.
M_Memcpy ( sd - > text , process , 6 ) ;
sd - > text [ 6 ] = 0 ;
}
else
sd - > text [ 0 ] = 0 ;
2016-01-08 03:48:20 +00:00
break ;
}
2016-06-04 23:23:20 +00:00
case 4 : // Speed pad parameters
2014-03-15 16:59:03 +00:00
{
sd - > toptexture = sd - > midtexture = sd - > bottomtexture = 0 ;
if ( msd - > toptexture [ 0 ] ! = ' - ' | | msd - > toptexture [ 1 ] ! = ' \0 ' )
{
char process [ 8 + 1 ] ;
M_Memcpy ( process , msd - > toptexture , 8 ) ;
process [ 8 ] = ' \0 ' ;
sd - > toptexture = get_number ( process ) ;
}
break ;
}
2021-09-21 08:14:55 +00:00
case 414 : // Play SFX
{
sd - > toptexture = sd - > midtexture = sd - > bottomtexture = 0 ;
if ( msd - > toptexture [ 0 ] ! = ' - ' | | msd - > toptexture [ 1 ] ! = ' \0 ' )
{
char process [ 8 + 1 ] ;
M_Memcpy ( process , msd - > toptexture , 8 ) ;
process [ 8 ] = ' \0 ' ;
sd - > text = Z_Malloc ( strlen ( process ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( sd - > text , process , strlen ( process ) + 1 ) ;
}
break ;
}
Hooh boy.
****
* MF2_MACEROTATE. Apply to any object. Replaces the indiscriminate spamming of A_MaceRotate each tic.
****
* Mace point mapthings have been slightly modified.
- MTF_AMBUSH: bigger luke theory (has no effect on custom mace, different effect on spring mace)
- MTF_OBJECTFLIP: flips the objects, but nothing else - just so it doesn't look out of place in gravflip sections
- MTF_OBJECTSPECIAL: keeps it from attempting to play swinging sounds
- angle: tag of controlling linedef
- parameter: number of "spokes" minus one - for example, a parameter of 2 results in 3 equidistant maces rotating around the same point.
****
* Mace linedefs have been significantly revamped.
- line dx: number of chain links
- line dy: speed (in FU)
- frontside floor height: Pitch (in degrees; how much it "tilts" over - Yaw influences the axis it's tilting on)
- frontside ceiling height: Yaw (in degrees; rotation of entire thing on xy plane)
- frontside x offset: Phase (in degrees; how far it is through the rotation cycle)
- frontside y offset: Max speed (in FU; if less than speed, set to speed*2)
- backside floor height: Pinch (in degrees; 0 if no backside; essentially makes rotation conical instead of wheel-like)
- backside ceiling height: Roll (in degrees; 0 if no backside; rotates on the axis of the spinning - identical to Phase for spinning maces, but useful for rotating swinging maces as opposed to just offsetting them)
- backside x offset: Number of "antispokes" (0 if no backside; makes that many spokes not exist so you can put another mace/chain type in there instead; for combo mace/chain instead turns them into chains directly)
- backside y offset: Width (in number of extra chains per side; 0 if no backside; creates a "skiprope" arrangement)
----
- ML_NOCLIMB: for chains and chain-mace combos, allow for player control of yaw through strafe keys
- ML_EFFECT1: replacing the seperate mapthings, this makes a mace type swing instead of spin.
- ML_EFFECT2: for all spokes of the mace wheel ending in maces, make the chains out of the mace type (inverted for firebars)
- ML_EFFECT3: spawn a bonus mace type at the center(s) of rotation
- ML_EFFECT4: don't clip inside ground
****
* Mapthing 1104 represents both spinning and swinging maces from prior versions of SRB2.
* Mapthing 1105 has gone from being a swinging mace variant to a combination of chains and maces in a single unit, provided the number of "spokes" is greater than one.
* Mapthing 1105 has gone from being a swinging chain variant to a vertical spring-on-a-ball-on-a-chain. Yellow by default, apply MTF_AMBUSH to turn into a red spring.
* Mapthing 1107 represents both spinning and swinging chains from prior versions of SRB2.
* Mapthing 1108 is completely untouched except to port over 2.1's functionality to the new backend.
* Mapthing 1109 is a Mario castle-level style firebar. This inverts the functionality of ML_EFFECT2 on the tagged linedef.
* Mapthing 1110 is a free slot should we want to implement another type of base-game mace.
* Mapthing 1111 is a custom mace. Use the linedef's frontside texture slots to identify a macetype mobjtype, then use the backside texture slots to identify a linktype mobjtype (defaults to MT_NULL if no backside).
****
Whooh. Requires new patch.dta for sprites.
2017-07-02 14:11:09 +00:00
case 9 : // Mace parameters
2016-06-04 23:23:20 +00:00
case 14 : // Bustable block parameters
2016-06-05 23:00:31 +00:00
case 15 : // Fan particle spawner parameters
2014-03-15 16:59:03 +00:00
{
char process [ 8 * 3 + 1 ] ;
memset ( process , 0 , 8 * 3 + 1 ) ;
sd - > toptexture = sd - > midtexture = sd - > bottomtexture = 0 ;
if ( msd - > toptexture [ 0 ] = = ' - ' & & msd - > toptexture [ 1 ] = = ' \0 ' )
break ;
else
M_Memcpy ( process , msd - > toptexture , 8 ) ;
if ( msd - > midtexture [ 0 ] ! = ' - ' | | msd - > midtexture [ 1 ] ! = ' \0 ' )
M_Memcpy ( process + strlen ( process ) , msd - > midtexture , 8 ) ;
if ( msd - > bottomtexture [ 0 ] ! = ' - ' | | msd - > bottomtexture [ 1 ] ! = ' \0 ' )
M_Memcpy ( process + strlen ( process ) , msd - > bottomtexture , 8 ) ;
sd - > toptexture = get_number ( process ) ;
break ;
}
2019-07-03 07:19:29 +00:00
case 331 : // Trigger linedef executor: Skin - Continuous
case 332 : // Trigger linedef executor: Skin - Each time
case 333 : // Trigger linedef executor: Skin - Once
2021-12-09 18:49:17 +00:00
case 334 : // Trigger linedef executor: Object dye - Continuous
case 335 : // Trigger linedef executor: Object dye - Each time
case 336 : // Trigger linedef executor: Object dye - Once
2021-09-21 05:36:54 +00:00
case 425 : // Calls P_SetMobjState on calling mobj
2021-09-21 06:34:55 +00:00
case 434 : // Custom Power
2021-09-21 05:36:54 +00:00
case 442 : // Calls P_SetMobjState on mobjs of a given type in the tagged sectors
2014-03-15 16:59:03 +00:00
case 443 : // Calls a named Lua function
2018-11-10 14:32:53 +00:00
case 459 : // Control text prompt (named tag)
2021-09-22 06:57:48 +00:00
case 461 : // Spawns an object on the map based on texture offsets
2021-09-21 05:44:55 +00:00
case 463 : // Colorizes an object
2014-03-15 16:59:03 +00:00
{
char process [ 8 * 3 + 1 ] ;
memset ( process , 0 , 8 * 3 + 1 ) ;
sd - > toptexture = sd - > midtexture = sd - > bottomtexture = 0 ;
if ( msd - > toptexture [ 0 ] = = ' - ' & & msd - > toptexture [ 1 ] = = ' \0 ' )
break ;
else
M_Memcpy ( process , msd - > toptexture , 8 ) ;
if ( msd - > midtexture [ 0 ] ! = ' - ' | | msd - > midtexture [ 1 ] ! = ' \0 ' )
M_Memcpy ( process + strlen ( process ) , msd - > midtexture , 8 ) ;
if ( msd - > bottomtexture [ 0 ] ! = ' - ' | | msd - > bottomtexture [ 1 ] ! = ' \0 ' )
M_Memcpy ( process + strlen ( process ) , msd - > bottomtexture , 8 ) ;
sd - > text = Z_Malloc ( strlen ( process ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( sd - > text , process , strlen ( process ) + 1 ) ;
break ;
}
2019-12-29 11:01:41 +00:00
case 259 : // Custom FOF
if ( ! isfrontside )
{
if ( ( msd - > toptexture [ 0 ] > = ' 0 ' & & msd - > toptexture [ 0 ] < = ' 9 ' )
| | ( msd - > toptexture [ 0 ] > = ' A ' & & msd - > toptexture [ 0 ] < = ' F ' ) )
sd - > toptexture = axtoi ( msd - > toptexture ) ;
else
2020-11-15 00:18:54 +00:00
I_Error ( " Custom FOF (line id %s) needs a value in the linedef's back side upper texture field. " , sizeu1 ( sd - > line - lines ) ) ;
2019-12-29 11:01:41 +00:00
sd - > midtexture = R_TextureNumForName ( msd - > midtexture ) ;
sd - > bottomtexture = R_TextureNumForName ( msd - > bottomtexture ) ;
break ;
}
// FALLTHRU
2014-03-15 16:59:03 +00:00
default : // normal cases
if ( msd - > toptexture [ 0 ] = = ' # ' )
{
char * col = msd - > toptexture ;
sd - > toptexture = sd - > bottomtexture =
( ( col [ 1 ] - ' 0 ' ) * 100 + ( col [ 2 ] - ' 0 ' ) * 10 + col [ 3 ] - ' 0 ' ) + 1 ;
sd - > midtexture = R_TextureNumForName ( msd - > midtexture ) ;
}
else
{
sd - > midtexture = R_TextureNumForName ( msd - > midtexture ) ;
sd - > toptexture = R_TextureNumForName ( msd - > toptexture ) ;
sd - > bottomtexture = R_TextureNumForName ( msd - > bottomtexture ) ;
}
break ;
}
}
2017-05-18 19:13:18 +00:00
}
2014-03-15 16:59:03 +00:00
2019-12-28 15:40:35 +00:00
static void P_LoadThings ( UINT8 * data )
2014-03-15 16:59:03 +00:00
{
2019-12-28 15:40:35 +00:00
mapthing_t * mt ;
size_t i ;
2014-03-15 16:59:03 +00:00
2019-12-28 15:40:35 +00:00
for ( i = 0 , mt = mapthings ; i < nummapthings ; i + + , mt + + )
{
mt - > x = READINT16 ( data ) ;
mt - > y = READINT16 ( data ) ;
2014-03-15 16:59:03 +00:00
2019-12-28 15:40:35 +00:00
mt - > angle = READINT16 ( data ) ;
mt - > type = READUINT16 ( data ) ;
mt - > options = READUINT16 ( data ) ;
mt - > extrainfo = ( UINT8 ) ( mt - > type > > 12 ) ;
2020-04-17 20:29:26 +00:00
Tag_FSet ( & mt - > tags , 0 ) ;
2020-04-19 13:18:36 +00:00
mt - > scale = FRACUNIT ;
2020-04-11 10:54:34 +00:00
memset ( mt - > args , 0 , NUMMAPTHINGARGS * sizeof ( * mt - > args ) ) ;
memset ( mt - > stringargs , 0x00 , NUMMAPTHINGSTRINGARGS * sizeof ( * mt - > stringargs ) ) ;
2020-04-19 12:39:16 +00:00
mt - > pitch = mt - > roll = 0 ;
2014-03-15 16:59:03 +00:00
2019-12-28 15:40:35 +00:00
mt - > type & = 4095 ;
2014-03-15 16:59:03 +00:00
2019-12-28 15:40:35 +00:00
if ( mt - > type = = 1705 | | ( mt - > type = = 750 & & mt - > extrainfo ) )
mt - > z = mt - > options ; // NiGHTS Hoops use the full flags bits to set the height.
else
mt - > z = mt - > options > > ZSHIFT ;
2019-12-30 20:23:00 +00:00
mt - > mobj = NULL ;
2019-12-28 15:40:35 +00:00
}
}
2014-03-15 16:59:03 +00:00
2019-12-30 10:33:22 +00:00
// Stores positions for relevant map data spread through a TEXTMAP.
UINT32 mapthingsPos [ UINT16_MAX ] ;
UINT32 linesPos [ UINT16_MAX ] ;
UINT32 sidesPos [ UINT16_MAX ] ;
UINT32 vertexesPos [ UINT16_MAX ] ;
UINT32 sectorsPos [ UINT16_MAX ] ;
2019-12-30 12:27:05 +00:00
// Determine total amount of map data in TEXTMAP.
static boolean TextmapCount ( UINT8 * data , size_t size )
2019-12-30 10:33:22 +00:00
{
2019-12-30 12:27:05 +00:00
char * tkn = M_GetToken ( ( char * ) data ) ;
2019-12-30 12:38:52 +00:00
UINT8 brackets = 0 ;
2019-12-30 12:27:05 +00:00
nummapthings = 0 ;
numlines = 0 ;
numsides = 0 ;
numvertexes = 0 ;
numsectors = 0 ;
2019-12-30 10:33:22 +00:00
// Look for namespace at the beginning.
2019-12-30 12:27:05 +00:00
if ( ! fastcmp ( tkn , " namespace " ) )
2019-12-30 10:33:22 +00:00
{
2019-12-30 12:27:05 +00:00
Z_Free ( tkn ) ;
2019-12-30 13:47:48 +00:00
CONS_Alert ( CONS_ERROR , " No namespace at beginning of lump! \n " ) ;
2019-12-30 12:27:05 +00:00
return false ;
}
Z_Free ( tkn ) ;
2019-12-30 10:33:22 +00:00
2019-12-30 12:27:05 +00:00
// Check if namespace is valid.
tkn = M_GetToken ( NULL ) ;
if ( ! fastcmp ( tkn , " srb2 " ) )
CONS_Alert ( CONS_WARNING , " Invalid namespace '%s', only 'srb2' is supported. \n " , tkn ) ;
Z_Free ( tkn ) ;
2019-12-30 10:33:22 +00:00
2019-12-30 12:27:05 +00:00
tkn = M_GetToken ( NULL ) ;
while ( tkn & & M_GetTokenPos ( ) < size )
{
// Avoid anything inside bracketed stuff, only look for external keywords.
2019-12-30 12:38:52 +00:00
if ( brackets )
2019-12-30 10:33:22 +00:00
{
2019-12-30 12:38:52 +00:00
if ( fastcmp ( tkn , " } " ) )
brackets - - ;
2019-12-30 10:33:22 +00:00
}
2019-12-30 12:38:52 +00:00
else if ( fastcmp ( tkn , " { " ) )
brackets + + ;
2019-12-30 12:27:05 +00:00
// Check for valid fields.
else if ( fastcmp ( tkn , " thing " ) )
mapthingsPos [ nummapthings + + ] = M_GetTokenPos ( ) ;
else if ( fastcmp ( tkn , " linedef " ) )
linesPos [ numlines + + ] = M_GetTokenPos ( ) ;
else if ( fastcmp ( tkn , " sidedef " ) )
sidesPos [ numsides + + ] = M_GetTokenPos ( ) ;
else if ( fastcmp ( tkn , " vertex " ) )
vertexesPos [ numvertexes + + ] = M_GetTokenPos ( ) ;
else if ( fastcmp ( tkn , " sector " ) )
sectorsPos [ numsectors + + ] = M_GetTokenPos ( ) ;
else
CONS_Alert ( CONS_NOTICE , " Unknown field '%s'. \n " , tkn ) ;
Z_Free ( tkn ) ;
tkn = M_GetToken ( NULL ) ;
2019-12-30 10:33:22 +00:00
}
2019-12-30 12:27:05 +00:00
Z_Free ( tkn ) ;
2019-12-30 13:47:48 +00:00
if ( brackets )
{
CONS_Alert ( CONS_ERROR , " Unclosed brackets detected in textmap lump. \n " ) ;
return false ;
}
2019-12-30 12:27:05 +00:00
return true ;
2019-12-30 10:33:22 +00:00
}
2020-01-01 14:52:59 +00:00
static void ParseTextmapVertexParameter ( UINT32 i , char * param , char * val )
2019-12-30 10:33:22 +00:00
{
if ( fastcmp ( param , " x " ) )
2020-01-01 14:52:59 +00:00
vertexes [ i ] . x = FLOAT_TO_FIXED ( atof ( val ) ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " y " ) )
2020-01-01 14:52:59 +00:00
vertexes [ i ] . y = FLOAT_TO_FIXED ( atof ( val ) ) ;
2020-01-04 09:24:42 +00:00
else if ( fastcmp ( param , " zfloor " ) )
{
vertexes [ i ] . floorz = FLOAT_TO_FIXED ( atof ( val ) ) ;
vertexes [ i ] . floorzset = true ;
}
else if ( fastcmp ( param , " zceiling " ) )
{
vertexes [ i ] . ceilingz = FLOAT_TO_FIXED ( atof ( val ) ) ;
vertexes [ i ] . ceilingzset = true ;
}
2019-12-30 10:33:22 +00:00
}
2020-03-15 08:55:57 +00:00
typedef struct textmap_colormap_s {
boolean used ;
INT32 lightcolor ;
UINT8 lightalpha ;
INT32 fadecolor ;
UINT8 fadealpha ;
UINT8 fadestart ;
UINT8 fadeend ;
UINT8 flags ;
} textmap_colormap_t ;
textmap_colormap_t textmap_colormap = { false , 0 , 25 , 0 , 25 , 0 , 31 , 0 } ;
2021-06-02 08:59:05 +00:00
typedef enum
{
PD_A = 1 ,
PD_B = 1 < < 1 ,
PD_C = 1 < < 2 ,
PD_D = 1 < < 3 ,
} planedef_t ;
typedef struct textmap_plane_s {
UINT8 defined ;
fixed_t a , b , c , d ;
} textmap_plane_t ;
textmap_plane_t textmap_planefloor = { 0 , 0 , 0 , 0 , 0 } ;
textmap_plane_t textmap_planeceiling = { 0 , 0 , 0 , 0 , 0 } ;
2020-01-01 14:52:59 +00:00
static void ParseTextmapSectorParameter ( UINT32 i , char * param , char * val )
2019-12-30 10:33:22 +00:00
{
if ( fastcmp ( param , " heightfloor " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . floorheight = atol ( val ) < < FRACBITS ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " heightceiling " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . ceilingheight = atol ( val ) < < FRACBITS ;
2019-12-30 10:33:22 +00:00
if ( fastcmp ( param , " texturefloor " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . floorpic = P_AddLevelFlat ( val , foundflats ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " textureceiling " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . ceilingpic = P_AddLevelFlat ( val , foundflats ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " lightlevel " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . lightlevel = atol ( val ) ;
2021-09-19 06:58:21 +00:00
else if ( fastcmp ( param , " lightfloor " ) )
sectors [ i ] . floorlightlevel = atol ( val ) ;
else if ( fastcmp ( param , " lightfloorabsolute " ) & & fastcmp ( " true " , val ) )
sectors [ i ] . floorlightabsolute = true ;
else if ( fastcmp ( param , " lightceiling " ) )
sectors [ i ] . ceilinglightlevel = atol ( val ) ;
else if ( fastcmp ( param , " lightceilingabsolute " ) & & fastcmp ( " true " , val ) )
sectors [ i ] . ceilinglightabsolute = true ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " special " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . special = atol ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " id " ) )
2020-04-17 22:23:24 +00:00
Tag_FSet ( & sectors [ i ] . tags , atol ( val ) ) ;
2020-04-12 09:56:36 +00:00
else if ( fastcmp ( param , " moreids " ) )
{
char * id = val ;
while ( id )
{
Tag_Add ( & sectors [ i ] . tags , atol ( id ) ) ;
if ( ( id = strchr ( id , ' ' ) ) )
id + + ;
}
}
2019-12-30 16:28:10 +00:00
else if ( fastcmp ( param , " xpanningfloor " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . floor_xoffs = FLOAT_TO_FIXED ( atof ( val ) ) ;
2019-12-30 16:28:10 +00:00
else if ( fastcmp ( param , " ypanningfloor " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . floor_yoffs = FLOAT_TO_FIXED ( atof ( val ) ) ;
2019-12-30 16:28:10 +00:00
else if ( fastcmp ( param , " xpanningceiling " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . ceiling_xoffs = FLOAT_TO_FIXED ( atof ( val ) ) ;
2019-12-30 16:28:10 +00:00
else if ( fastcmp ( param , " ypanningceiling " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . ceiling_yoffs = FLOAT_TO_FIXED ( atof ( val ) ) ;
2019-12-30 16:28:10 +00:00
else if ( fastcmp ( param , " rotationfloor " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . floorpic_angle = FixedAngle ( FLOAT_TO_FIXED ( atof ( val ) ) ) ;
2019-12-30 16:28:10 +00:00
else if ( fastcmp ( param , " rotationceiling " ) )
2020-01-01 14:52:59 +00:00
sectors [ i ] . ceilingpic_angle = FixedAngle ( FLOAT_TO_FIXED ( atof ( val ) ) ) ;
2021-06-02 08:59:05 +00:00
else if ( fastcmp ( param , " floorplane_a " ) )
{
textmap_planefloor . defined | = PD_A ;
textmap_planefloor . a = FLOAT_TO_FIXED ( atof ( val ) ) ;
}
else if ( fastcmp ( param , " floorplane_b " ) )
{
textmap_planefloor . defined | = PD_B ;
2021-06-02 09:21:37 +00:00
textmap_planefloor . b = FLOAT_TO_FIXED ( atof ( val ) ) ;
2021-06-02 08:59:05 +00:00
}
else if ( fastcmp ( param , " floorplane_c " ) )
{
textmap_planefloor . defined | = PD_C ;
2021-06-02 09:21:37 +00:00
textmap_planefloor . c = FLOAT_TO_FIXED ( atof ( val ) ) ;
2021-06-02 08:59:05 +00:00
}
else if ( fastcmp ( param , " floorplane_d " ) )
{
textmap_planefloor . defined | = PD_D ;
2021-06-02 09:21:37 +00:00
textmap_planefloor . d = FLOAT_TO_FIXED ( atof ( val ) ) ;
2021-06-02 08:59:05 +00:00
}
else if ( fastcmp ( param , " ceilingplane_a " ) )
{
textmap_planeceiling . defined | = PD_A ;
textmap_planeceiling . a = FLOAT_TO_FIXED ( atof ( val ) ) ;
}
else if ( fastcmp ( param , " ceilingplane_b " ) )
{
textmap_planeceiling . defined | = PD_B ;
2021-06-02 09:21:37 +00:00
textmap_planeceiling . b = FLOAT_TO_FIXED ( atof ( val ) ) ;
2021-06-02 08:59:05 +00:00
}
else if ( fastcmp ( param , " ceilingplane_c " ) )
{
textmap_planeceiling . defined | = PD_C ;
2021-06-02 09:21:37 +00:00
textmap_planeceiling . c = FLOAT_TO_FIXED ( atof ( val ) ) ;
2021-06-02 08:59:05 +00:00
}
else if ( fastcmp ( param , " ceilingplane_d " ) )
{
textmap_planeceiling . defined | = PD_D ;
2021-06-02 09:21:37 +00:00
textmap_planeceiling . d = FLOAT_TO_FIXED ( atof ( val ) ) ;
2021-06-02 08:59:05 +00:00
}
2020-03-15 08:55:57 +00:00
else if ( fastcmp ( param , " lightcolor " ) )
{
textmap_colormap . used = true ;
textmap_colormap . lightcolor = atol ( val ) ;
}
else if ( fastcmp ( param , " lightalpha " ) )
{
textmap_colormap . used = true ;
textmap_colormap . lightalpha = atol ( val ) ;
}
else if ( fastcmp ( param , " fadecolor " ) )
{
textmap_colormap . used = true ;
textmap_colormap . fadecolor = atol ( val ) ;
}
else if ( fastcmp ( param , " fadealpha " ) )
{
textmap_colormap . used = true ;
textmap_colormap . fadealpha = atol ( val ) ;
}
else if ( fastcmp ( param , " fadestart " ) )
{
textmap_colormap . used = true ;
textmap_colormap . fadestart = atol ( val ) ;
}
else if ( fastcmp ( param , " fadeend " ) )
{
textmap_colormap . used = true ;
textmap_colormap . fadeend = atol ( val ) ;
}
else if ( fastcmp ( param , " colormapfog " ) & & fastcmp ( " true " , val ) )
{
textmap_colormap . used = true ;
textmap_colormap . flags | = CMF_FOG ;
}
else if ( fastcmp ( param , " colormapfadesprites " ) & & fastcmp ( " true " , val ) )
{
textmap_colormap . used = true ;
textmap_colormap . flags | = CMF_FADEFULLBRIGHTSPRITES ;
}
2020-03-20 11:19:02 +00:00
else if ( fastcmp ( param , " colormapprotected " ) & & fastcmp ( " true " , val ) )
sectors [ i ] . colormap_protected = true ;
2019-12-30 10:33:22 +00:00
}
2020-01-01 14:52:59 +00:00
static void ParseTextmapSidedefParameter ( UINT32 i , char * param , char * val )
2019-12-30 10:33:22 +00:00
{
if ( fastcmp ( param , " offsetx " ) )
2020-01-01 14:52:59 +00:00
sides [ i ] . textureoffset = atol ( val ) < < FRACBITS ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " offsety " ) )
2020-01-01 14:52:59 +00:00
sides [ i ] . rowoffset = atol ( val ) < < FRACBITS ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " texturetop " ) )
2020-01-01 14:52:59 +00:00
sides [ i ] . toptexture = R_TextureNumForName ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " texturebottom " ) )
2020-01-01 14:52:59 +00:00
sides [ i ] . bottomtexture = R_TextureNumForName ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " texturemiddle " ) )
2020-01-01 14:52:59 +00:00
sides [ i ] . midtexture = R_TextureNumForName ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " sector " ) )
2020-01-01 14:52:59 +00:00
P_SetSidedefSector ( i , atol ( val ) ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " repeatcnt " ) )
2020-01-01 14:52:59 +00:00
sides [ i ] . repeatcnt = atol ( val ) ;
2019-12-30 10:33:22 +00:00
}
2020-01-01 14:52:59 +00:00
static void ParseTextmapLinedefParameter ( UINT32 i , char * param , char * val )
2019-12-30 10:33:22 +00:00
{
if ( fastcmp ( param , " id " ) )
2020-04-17 22:23:24 +00:00
Tag_FSet ( & lines [ i ] . tags , atol ( val ) ) ;
2020-04-12 09:56:36 +00:00
else if ( fastcmp ( param , " moreids " ) )
{
char * id = val ;
while ( id )
{
Tag_Add ( & lines [ i ] . tags , atol ( id ) ) ;
if ( ( id = strchr ( id , ' ' ) ) )
id + + ;
}
}
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " special " ) )
2020-01-01 14:52:59 +00:00
lines [ i ] . special = atol ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " v1 " ) )
2020-01-01 14:52:59 +00:00
P_SetLinedefV1 ( i , atol ( val ) ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " v2 " ) )
2020-01-01 14:52:59 +00:00
P_SetLinedefV2 ( i , atol ( val ) ) ;
2021-12-20 20:14:39 +00:00
else if ( fastncmp ( param , " stringarg " , 9 ) & & strlen ( param ) > 9 )
2020-01-24 22:02:42 +00:00
{
2021-12-20 20:14:39 +00:00
size_t argnum = atol ( param + 9 ) ;
2020-01-24 22:02:42 +00:00
if ( argnum > = NUMLINESTRINGARGS )
return ;
lines [ i ] . stringargs [ argnum ] = Z_Malloc ( strlen ( val ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ argnum ] , val , strlen ( val ) + 1 ) ;
2020-01-02 11:23:14 +00:00
}
else if ( fastncmp ( param , " arg " , 3 ) & & strlen ( param ) > 3 )
{
2020-01-24 22:02:42 +00:00
size_t argnum = atol ( param + 3 ) ;
if ( argnum > = NUMLINEARGS )
return ;
lines [ i ] . args [ argnum ] = atol ( val ) ;
}
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " sidefront " ) )
2020-01-01 14:52:59 +00:00
lines [ i ] . sidenum [ 0 ] = atol ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " sideback " ) )
2020-01-01 14:52:59 +00:00
lines [ i ] . sidenum [ 1 ] = atol ( val ) ;
2020-01-26 11:24:52 +00:00
else if ( fastcmp ( param , " alpha " ) )
lines [ i ] . alpha = FLOAT_TO_FIXED ( atof ( val ) ) ;
2020-05-03 18:41:37 +00:00
else if ( fastcmp ( param , " executordelay " ) )
lines [ i ] . executordelay = atol ( val ) ;
2019-12-30 10:33:22 +00:00
// Flags
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " blocking " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_IMPASSIBLE ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " blockmonsters " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_BLOCKMONSTERS ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " twosided " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_TWOSIDED ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " dontpegtop " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_DONTPEGTOP ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " dontpegbottom " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_DONTPEGBOTTOM ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " skewtd " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_EFFECT1 ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " noclimb " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_NOCLIMB ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " noskew " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_EFFECT2 ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " midpeg " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_EFFECT3 ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " midsolid " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_EFFECT4 ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " wrapmidtex " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_EFFECT5 ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " effect6 " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_EFFECT6 ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " nonet " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_NONET ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " netonly " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_NETONLY ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " bouncy " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_BOUNCY ;
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " transfer " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
lines [ i ] . flags | = ML_TFERLINE ;
}
2020-01-01 14:52:59 +00:00
static void ParseTextmapThingParameter ( UINT32 i , char * param , char * val )
2019-12-30 10:33:22 +00:00
{
2020-01-25 08:52:13 +00:00
if ( fastcmp ( param , " id " ) )
2020-04-17 22:23:24 +00:00
Tag_FSet ( & mapthings [ i ] . tags , atol ( val ) ) ;
2020-04-12 09:56:36 +00:00
else if ( fastcmp ( param , " moreids " ) )
{
char * id = val ;
while ( id )
{
Tag_Add ( & mapthings [ i ] . tags , atol ( id ) ) ;
if ( ( id = strchr ( id , ' ' ) ) )
id + + ;
}
}
else if ( fastcmp ( param , " x " ) )
2020-01-01 14:52:59 +00:00
mapthings [ i ] . x = atol ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " y " ) )
2020-01-01 14:52:59 +00:00
mapthings [ i ] . y = atol ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " height " ) )
2020-01-01 14:52:59 +00:00
mapthings [ i ] . z = atol ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " angle " ) )
2020-01-01 14:52:59 +00:00
mapthings [ i ] . angle = atol ( val ) ;
2020-04-19 12:39:16 +00:00
else if ( fastcmp ( param , " pitch " ) )
mapthings [ i ] . pitch = atol ( val ) ;
else if ( fastcmp ( param , " roll " ) )
mapthings [ i ] . roll = atol ( val ) ;
2019-12-30 10:33:22 +00:00
else if ( fastcmp ( param , " type " ) )
2020-01-01 14:52:59 +00:00
mapthings [ i ] . type = atol ( val ) ;
2020-04-19 13:18:36 +00:00
else if ( fastcmp ( param , " scale " ) | | fastcmp ( param , " scalex " ) | | fastcmp ( param , " scaley " ) )
mapthings [ i ] . scale = FLOAT_TO_FIXED ( atof ( val ) ) ;
2019-12-30 10:33:22 +00:00
// Flags
2020-01-01 14:52:59 +00:00
else if ( fastcmp ( param , " flip " ) & & fastcmp ( " true " , val ) )
2019-12-30 10:33:22 +00:00
mapthings [ i ] . options | = MTF_OBJECTFLIP ;
2020-04-11 10:54:34 +00:00
2021-12-20 20:14:39 +00:00
else if ( fastncmp ( param , " stringarg " , 9 ) & & strlen ( param ) > 9 )
2020-04-11 10:54:34 +00:00
{
2021-12-20 20:14:39 +00:00
size_t argnum = atol ( param + 9 ) ;
2020-04-11 10:54:34 +00:00
if ( argnum > = NUMMAPTHINGSTRINGARGS )
return ;
mapthings [ i ] . stringargs [ argnum ] = Z_Malloc ( strlen ( val ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( mapthings [ i ] . stringargs [ argnum ] , val , strlen ( val ) + 1 ) ;
}
else if ( fastncmp ( param , " arg " , 3 ) & & strlen ( param ) > 3 )
{
size_t argnum = atol ( param + 3 ) ;
if ( argnum > = NUMMAPTHINGARGS )
return ;
mapthings [ i ] . args [ argnum ] = atol ( val ) ;
}
2019-12-30 10:33:22 +00:00
}
/** From a given position table, run a specified parser function through a {}-encapsuled text.
*
* \ param Position of the data to parse , in the textmap .
* \ param Structure number ( mapthings , sectors , . . . ) .
* \ param Parser function pointer .
*/
2020-01-01 14:52:59 +00:00
static void TextmapParse ( UINT32 dataPos , size_t num , void ( * parser ) ( UINT32 , char * , char * ) )
2019-12-30 10:33:22 +00:00
{
2020-01-01 14:52:59 +00:00
char * param , * val ;
2019-12-30 10:33:22 +00:00
M_SetTokenPos ( dataPos ) ;
2020-01-01 14:52:59 +00:00
param = M_GetToken ( NULL ) ;
if ( ! fastcmp ( param , " { " ) )
2019-12-30 10:33:22 +00:00
{
2020-01-01 14:52:59 +00:00
Z_Free ( param ) ;
2019-12-30 13:33:41 +00:00
CONS_Alert ( CONS_WARNING , " Invalid UDMF data capsule! \n " ) ;
return ;
}
2020-01-01 14:52:59 +00:00
Z_Free ( param ) ;
2019-12-30 13:33:41 +00:00
2020-01-01 14:52:59 +00:00
while ( true )
2019-12-30 13:33:41 +00:00
{
2020-01-01 14:52:59 +00:00
param = M_GetToken ( NULL ) ;
if ( fastcmp ( param , " } " ) )
{
Z_Free ( param ) ;
break ;
}
val = M_GetToken ( NULL ) ;
parser ( num , param , val ) ;
Z_Free ( param ) ;
Z_Free ( val ) ;
2019-12-30 10:33:22 +00:00
}
}
2019-12-30 11:33:24 +00:00
/** Provides a fix to the flat alignment coordinate transform from standard Textmaps.
*/
2019-12-30 13:33:41 +00:00
static void TextmapFixFlatOffsets ( sector_t * sec )
2019-12-30 11:33:24 +00:00
{
if ( sec - > floorpic_angle )
{
fixed_t pc = FINECOSINE ( sec - > floorpic_angle > > ANGLETOFINESHIFT ) ;
fixed_t ps = FINESINE ( sec - > floorpic_angle > > ANGLETOFINESHIFT ) ;
fixed_t xoffs = sec - > floor_xoffs ;
fixed_t yoffs = sec - > floor_yoffs ;
sec - > floor_xoffs = ( FixedMul ( xoffs , pc ) % MAXFLATSIZE ) - ( FixedMul ( yoffs , ps ) % MAXFLATSIZE ) ;
sec - > floor_yoffs = ( FixedMul ( xoffs , ps ) % MAXFLATSIZE ) + ( FixedMul ( yoffs , pc ) % MAXFLATSIZE ) ;
}
if ( sec - > ceilingpic_angle )
{
fixed_t pc = FINECOSINE ( sec - > ceilingpic_angle > > ANGLETOFINESHIFT ) ;
fixed_t ps = FINESINE ( sec - > ceilingpic_angle > > ANGLETOFINESHIFT ) ;
fixed_t xoffs = sec - > ceiling_xoffs ;
fixed_t yoffs = sec - > ceiling_yoffs ;
sec - > ceiling_xoffs = ( FixedMul ( xoffs , pc ) % MAXFLATSIZE ) - ( FixedMul ( yoffs , ps ) % MAXFLATSIZE ) ;
sec - > ceiling_yoffs = ( FixedMul ( xoffs , ps ) % MAXFLATSIZE ) + ( FixedMul ( yoffs , pc ) % MAXFLATSIZE ) ;
}
}
2020-03-15 08:55:57 +00:00
static INT32 P_ColorToRGBA ( INT32 color , UINT8 alpha )
{
UINT8 r = ( color > > 16 ) & 0xFF ;
UINT8 g = ( color > > 8 ) & 0xFF ;
UINT8 b = color & 0xFF ;
return R_PutRgbaRGBA ( r , g , b , alpha ) ;
}
2019-12-30 10:33:22 +00:00
/** Loads the textmap data, after obtaining the elements count and allocating their respective space.
*/
2019-12-30 13:33:41 +00:00
static void P_LoadTextmap ( void )
2019-12-30 10:33:22 +00:00
{
UINT32 i ;
vertex_t * vt ;
sector_t * sc ;
line_t * ld ;
side_t * sd ;
mapthing_t * mt ;
2019-12-30 13:42:41 +00:00
CONS_Alert ( CONS_NOTICE , " UDMF support is still a work-in-progress; its specs and features are prone to change until it is fully implemented. \n " ) ;
2019-12-30 10:33:22 +00:00
/// Given the UDMF specs, some fields are given a default value.
2019-12-30 15:28:22 +00:00
/// If an element's field has a default value set, it is omitted
2019-12-30 10:33:22 +00:00
/// from the textmap, and therefore we have to account for it by
/// preemptively setting that value beforehand.
for ( i = 0 , vt = vertexes ; i < numvertexes ; i + + , vt + + )
{
// Defaults.
2020-01-01 22:52:30 +00:00
vt - > x = vt - > y = INT32_MAX ;
2020-01-04 09:24:42 +00:00
vt - > floorzset = vt - > ceilingzset = false ;
vt - > floorz = vt - > ceilingz = 0 ;
2019-12-30 10:33:22 +00:00
2019-12-30 15:28:22 +00:00
TextmapParse ( vertexesPos [ i ] , i , ParseTextmapVertexParameter ) ;
2020-01-01 22:52:30 +00:00
if ( vt - > x = = INT32_MAX )
I_Error ( " P_LoadTextmap: vertex %s has no x value set! \n " , sizeu1 ( i ) ) ;
if ( vt - > y = = INT32_MAX )
I_Error ( " P_LoadTextmap: vertex %s has no y value set! \n " , sizeu1 ( i ) ) ;
2019-12-30 10:33:22 +00:00
}
for ( i = 0 , sc = sectors ; i < numsectors ; i + + , sc + + )
{
// Defaults.
sc - > floorheight = 0 ;
sc - > ceilingheight = 0 ;
sc - > floorpic = 0 ;
sc - > ceilingpic = 0 ;
sc - > lightlevel = 255 ;
sc - > special = 0 ;
2020-04-17 09:21:40 +00:00
Tag_FSet ( & sc - > tags , 0 ) ;
2019-12-30 10:33:22 +00:00
2019-12-30 20:23:00 +00:00
sc - > floor_xoffs = sc - > floor_yoffs = 0 ;
sc - > ceiling_xoffs = sc - > ceiling_yoffs = 0 ;
sc - > floorpic_angle = sc - > ceilingpic_angle = 0 ;
2021-09-19 06:58:21 +00:00
sc - > floorlightlevel = sc - > ceilinglightlevel = 0 ;
sc - > floorlightabsolute = sc - > ceilinglightabsolute = false ;
2020-03-20 11:19:02 +00:00
sc - > colormap_protected = false ;
2020-03-15 08:55:57 +00:00
textmap_colormap . used = false ;
textmap_colormap . lightcolor = 0 ;
textmap_colormap . lightalpha = 25 ;
textmap_colormap . fadecolor = 0 ;
textmap_colormap . fadealpha = 25 ;
textmap_colormap . fadestart = 0 ;
textmap_colormap . fadeend = 31 ;
textmap_colormap . flags = 0 ;
2021-06-02 08:59:05 +00:00
textmap_planefloor . defined = 0 ;
textmap_planeceiling . defined = 0 ;
2019-12-30 16:28:10 +00:00
TextmapParse ( sectorsPos [ i ] , i , ParseTextmapSectorParameter ) ;
2020-04-17 09:21:40 +00:00
2019-12-30 20:23:00 +00:00
P_InitializeSector ( sc ) ;
2020-03-15 08:55:57 +00:00
if ( textmap_colormap . used )
{
INT32 rgba = P_ColorToRGBA ( textmap_colormap . lightcolor , textmap_colormap . lightalpha ) ;
INT32 fadergba = P_ColorToRGBA ( textmap_colormap . fadecolor , textmap_colormap . fadealpha ) ;
2020-03-20 10:19:30 +00:00
sc - > extra_colormap = sc - > spawn_extra_colormap = R_CreateColormap ( rgba , fadergba , textmap_colormap . fadestart , textmap_colormap . fadeend , textmap_colormap . flags ) ;
2020-03-15 08:55:57 +00:00
}
2021-06-02 08:59:05 +00:00
if ( textmap_planefloor . defined = = ( PD_A | PD_B | PD_C | PD_D ) )
{
sc - > f_slope = MakeViaEquationConstants ( textmap_planefloor . a , textmap_planefloor . b , textmap_planefloor . c , textmap_planefloor . d ) ;
sc - > hasslope = true ;
}
if ( textmap_planeceiling . defined = = ( PD_A | PD_B | PD_C | PD_D ) )
{
sc - > c_slope = MakeViaEquationConstants ( textmap_planeceiling . a , textmap_planeceiling . b , textmap_planeceiling . c , textmap_planeceiling . d ) ;
sc - > hasslope = true ;
}
2019-12-30 11:31:55 +00:00
TextmapFixFlatOffsets ( sc ) ;
2019-12-30 10:33:22 +00:00
}
for ( i = 0 , ld = lines ; i < numlines ; i + + , ld + + )
{
// Defaults.
2020-01-01 12:40:17 +00:00
ld - > v1 = ld - > v2 = NULL ;
ld - > flags = 0 ;
2019-12-30 10:33:22 +00:00
ld - > special = 0 ;
2020-04-17 09:21:40 +00:00
Tag_FSet ( & ld - > tags , 0 ) ;
2020-01-02 11:23:14 +00:00
memset ( ld - > args , 0 , NUMLINEARGS * sizeof ( * ld - > args ) ) ;
2020-01-12 23:59:35 +00:00
memset ( ld - > stringargs , 0x00 , NUMLINESTRINGARGS * sizeof ( * ld - > stringargs ) ) ;
2020-02-10 19:26:29 +00:00
ld - > alpha = FRACUNIT ;
2020-05-03 18:41:37 +00:00
ld - > executordelay = 0 ;
2020-01-01 12:40:17 +00:00
ld - > sidenum [ 0 ] = 0xffff ;
2019-12-30 10:33:22 +00:00
ld - > sidenum [ 1 ] = 0xffff ;
2019-12-30 15:28:22 +00:00
TextmapParse ( linesPos [ i ] , i , ParseTextmapLinedefParameter ) ;
2020-01-01 22:52:30 +00:00
2020-01-01 13:27:01 +00:00
if ( ! ld - > v1 )
2020-01-01 22:52:30 +00:00
I_Error ( " P_LoadTextmap: linedef %s has no v1 value set! \n " , sizeu1 ( i ) ) ;
2020-01-01 13:27:01 +00:00
if ( ! ld - > v2 )
2020-01-01 22:52:30 +00:00
I_Error ( " P_LoadTextmap: linedef %s has no v2 value set! \n " , sizeu1 ( i ) ) ;
if ( ld - > sidenum [ 0 ] = = 0xffff )
I_Error ( " P_LoadTextmap: linedef %s has no sidefront value set! \n " , sizeu1 ( i ) ) ;
2019-12-30 10:33:22 +00:00
P_InitializeLinedef ( ld ) ;
}
for ( i = 0 , sd = sides ; i < numsides ; i + + , sd + + )
{
// Defaults.
sd - > textureoffset = 0 ;
2020-01-01 12:40:17 +00:00
sd - > rowoffset = 0 ;
2019-12-30 10:33:22 +00:00
sd - > toptexture = R_TextureNumForName ( " - " ) ;
sd - > midtexture = R_TextureNumForName ( " - " ) ;
sd - > bottomtexture = R_TextureNumForName ( " - " ) ;
2020-01-01 12:40:17 +00:00
sd - > sector = NULL ;
2019-12-30 10:33:22 +00:00
sd - > repeatcnt = 0 ;
2019-12-30 15:28:22 +00:00
TextmapParse ( sidesPos [ i ] , i , ParseTextmapSidedefParameter ) ;
2020-01-01 13:27:01 +00:00
if ( ! sd - > sector )
2020-01-01 22:52:30 +00:00
I_Error ( " P_LoadTextmap: sidedef %s has no sector value set! \n " , sizeu1 ( i ) ) ;
2020-01-01 14:10:41 +00:00
P_InitializeSidedef ( sd ) ;
2019-12-30 10:33:22 +00:00
}
for ( i = 0 , mt = mapthings ; i < nummapthings ; i + + , mt + + )
{
// Defaults.
2019-12-30 20:23:00 +00:00
mt - > x = mt - > y = 0 ;
2020-04-22 07:00:29 +00:00
mt - > angle = mt - > pitch = mt - > roll = 0 ;
2019-12-30 20:23:00 +00:00
mt - > type = 0 ;
mt - > options = 0 ;
mt - > z = 0 ;
mt - > extrainfo = 0 ;
2020-04-17 09:21:40 +00:00
Tag_FSet ( & mt - > tags , 0 ) ;
2020-04-19 13:18:36 +00:00
mt - > scale = FRACUNIT ;
2020-04-11 10:54:34 +00:00
memset ( mt - > args , 0 , NUMMAPTHINGARGS * sizeof ( * mt - > args ) ) ;
memset ( mt - > stringargs , 0x00 , NUMMAPTHINGSTRINGARGS * sizeof ( * mt - > stringargs ) ) ;
2019-12-30 20:23:00 +00:00
mt - > mobj = NULL ;
2019-12-30 10:33:22 +00:00
2019-12-30 15:28:22 +00:00
TextmapParse ( mapthingsPos [ i ] , i , ParseTextmapThingParameter ) ;
2019-12-30 10:33:22 +00:00
}
}
2020-01-04 10:08:05 +00:00
static void P_ProcessLinedefsAfterSidedefs ( void )
{
size_t i = numlines ;
register line_t * ld = lines ;
for ( ; i - - ; ld + + )
{
ld - > frontsector = sides [ ld - > sidenum [ 0 ] ] . sector ; //e6y: Can't be -1 here
ld - > backsector = ld - > sidenum [ 1 ] ! = 0xffff ? sides [ ld - > sidenum [ 1 ] ] . sector : 0 ;
switch ( ld - > special )
{
2020-03-20 10:19:30 +00:00
// Compile linedef 'text' from both sidedefs 'text' for appropriate specials.
2020-01-04 10:08:05 +00:00
case 331 : // Trigger linedef executor: Skin - Continuous
case 332 : // Trigger linedef executor: Skin - Each time
case 333 : // Trigger linedef executor: Skin - Once
case 443 : // Calls a named Lua function
if ( sides [ ld - > sidenum [ 0 ] ] . text )
{
size_t len = strlen ( sides [ ld - > sidenum [ 0 ] ] . text ) + 1 ;
if ( ld - > sidenum [ 1 ] ! = 0xffff & & sides [ ld - > sidenum [ 1 ] ] . text )
len + = strlen ( sides [ ld - > sidenum [ 1 ] ] . text ) ;
ld - > text = Z_Malloc ( len , PU_LEVEL , NULL ) ;
M_Memcpy ( ld - > text , sides [ ld - > sidenum [ 0 ] ] . text , strlen ( sides [ ld - > sidenum [ 0 ] ] . text ) + 1 ) ;
if ( ld - > sidenum [ 1 ] ! = 0xffff & & sides [ ld - > sidenum [ 1 ] ] . text )
M_Memcpy ( ld - > text + strlen ( ld - > text ) + 1 , sides [ ld - > sidenum [ 1 ] ] . text , strlen ( sides [ ld - > sidenum [ 1 ] ] . text ) + 1 ) ;
}
break ;
2020-03-20 10:19:30 +00:00
case 447 : // Change colormap
case 455 : // Fade colormap
if ( udmf )
break ;
if ( ld - > flags & ML_DONTPEGBOTTOM ) // alternate alpha (by texture offsets)
{
extracolormap_t * exc = R_CopyColormap ( sides [ ld - > sidenum [ 0 ] ] . colormap_data , false ) ;
INT16 alpha = max ( min ( sides [ ld - > sidenum [ 0 ] ] . textureoffset > > FRACBITS , 25 ) , - 25 ) ;
INT16 fadealpha = max ( min ( sides [ ld - > sidenum [ 0 ] ] . rowoffset > > FRACBITS , 25 ) , - 25 ) ;
// If alpha is negative, set "subtract alpha" flag and store absolute value
if ( alpha < 0 )
{
alpha * = - 1 ;
2020-04-18 15:15:25 +00:00
ld - > args [ 2 ] | = TMCF_SUBLIGHTA ;
2020-03-20 10:19:30 +00:00
}
if ( fadealpha < 0 )
{
fadealpha * = - 1 ;
2020-04-18 15:15:25 +00:00
ld - > args [ 2 ] | = TMCF_SUBFADEA ;
2020-03-20 10:19:30 +00:00
}
exc - > rgba = R_GetRgbaRGB ( exc - > rgba ) + R_PutRgbaA ( alpha ) ;
exc - > fadergba = R_GetRgbaRGB ( exc - > fadergba ) + R_PutRgbaA ( fadealpha ) ;
if ( ! ( sides [ ld - > sidenum [ 0 ] ] . colormap_data = R_GetColormapFromList ( exc ) ) )
{
exc - > colormap = R_CreateLightTable ( exc ) ;
R_AddColormapToList ( exc ) ;
sides [ ld - > sidenum [ 0 ] ] . colormap_data = exc ;
}
else
Z_Free ( exc ) ;
}
break ;
2020-01-04 10:08:05 +00:00
}
}
}
2019-12-30 13:47:48 +00:00
static boolean P_LoadMapData ( const virtres_t * virt )
2019-12-28 15:40:35 +00:00
{
2019-12-30 12:27:05 +00:00
virtlump_t * virtvertexes = NULL , * virtsectors = NULL , * virtsidedefs = NULL , * virtlinedefs = NULL , * virtthings = NULL ;
2014-03-15 16:59:03 +00:00
2019-12-28 15:40:35 +00:00
// Count map data.
2020-03-15 15:23:15 +00:00
if ( udmf ) // Count how many entries for each type we got in textmap.
2019-12-30 13:47:48 +00:00
{
2020-03-15 15:23:15 +00:00
virtlump_t * textmap = vres_Find ( virt , " TEXTMAP " ) ;
2019-12-30 13:47:48 +00:00
if ( ! TextmapCount ( textmap - > data , textmap - > size ) )
return false ;
}
2019-12-28 15:40:35 +00:00
else
{
virtthings = vres_Find ( virt , " THINGS " ) ;
virtvertexes = vres_Find ( virt , " VERTEXES " ) ;
virtsectors = vres_Find ( virt , " SECTORS " ) ;
virtsidedefs = vres_Find ( virt , " SIDEDEFS " ) ;
virtlinedefs = vres_Find ( virt , " LINEDEFS " ) ;
if ( ! virtthings )
I_Error ( " THINGS lump not found " ) ;
if ( ! virtvertexes )
I_Error ( " VERTEXES lump not found " ) ;
if ( ! virtsectors )
I_Error ( " SECTORS lump not found " ) ;
if ( ! virtsidedefs )
I_Error ( " SIDEDEFS lump not found " ) ;
if ( ! virtlinedefs )
I_Error ( " LINEDEFS lump not found " ) ;
// Traditional doom map format just assumes the number of elements from the lump sizes.
numvertexes = virtvertexes - > size / sizeof ( mapvertex_t ) ;
numsectors = virtsectors - > size / sizeof ( mapsector_t ) ;
numsides = virtsidedefs - > size / sizeof ( mapsidedef_t ) ;
numlines = virtlinedefs - > size / sizeof ( maplinedef_t ) ;
nummapthings = virtthings - > size / ( 5 * sizeof ( INT16 ) ) ;
}
if ( numvertexes < = 0 )
I_Error ( " Level has no vertices " ) ;
if ( numsectors < = 0 )
I_Error ( " Level has no sectors " ) ;
if ( numsides < = 0 )
I_Error ( " Level has no sidedefs " ) ;
if ( numlines < = 0 )
I_Error ( " Level has no linedefs " ) ;
vertexes = Z_Calloc ( numvertexes * sizeof ( * vertexes ) , PU_LEVEL , NULL ) ;
sectors = Z_Calloc ( numsectors * sizeof ( * sectors ) , PU_LEVEL , NULL ) ;
sides = Z_Calloc ( numsides * sizeof ( * sides ) , PU_LEVEL , NULL ) ;
lines = Z_Calloc ( numlines * sizeof ( * lines ) , PU_LEVEL , NULL ) ;
mapthings = Z_Calloc ( nummapthings * sizeof ( * mapthings ) , PU_LEVEL , NULL ) ;
// Allocate a big chunk of memory as big as our MAXLEVELFLATS limit.
//Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty
foundflats = calloc ( MAXLEVELFLATS , sizeof ( * foundflats ) ) ;
if ( foundflats = = NULL )
I_Error ( " Ran out of memory while loading sectors \n " ) ;
numlevelflats = 0 ;
2019-12-30 10:33:22 +00:00
// Load map data.
2020-03-15 15:23:15 +00:00
if ( udmf )
2019-12-30 10:33:22 +00:00
P_LoadTextmap ( ) ;
2019-12-28 15:40:35 +00:00
else
{
P_LoadVertices ( virtvertexes - > data ) ;
P_LoadSectors ( virtsectors - > data ) ;
P_LoadLinedefs ( virtlinedefs - > data ) ;
P_LoadSidedefs ( virtsidedefs - > data ) ;
P_LoadThings ( virtthings - > data ) ;
}
2020-01-04 10:08:05 +00:00
P_ProcessLinedefsAfterSidedefs ( ) ;
2019-12-28 15:40:35 +00:00
R_ClearTextureNumCache ( true ) ;
// set the sky flat num
skyflatnum = P_AddLevelFlat ( SKYFLATNAME , foundflats ) ;
// copy table for global usage
levelflats = M_Memcpy ( Z_Calloc ( numlevelflats * sizeof ( * levelflats ) , PU_LEVEL , NULL ) , foundflats , numlevelflats * sizeof ( levelflat_t ) ) ;
free ( foundflats ) ;
// search for animated flats and set up
P_SetupLevelFlatAnims ( ) ;
2019-12-30 13:47:48 +00:00
return true ;
2019-12-28 15:40:35 +00:00
}
2019-12-29 18:54:04 +00:00
static void P_InitializeSubsector ( subsector_t * ss )
{
ss - > sector = NULL ;
ss - > validcount = 0 ;
}
2019-12-28 15:40:35 +00:00
static inline void P_LoadSubsectors ( UINT8 * data )
{
mapsubsector_t * ms = ( mapsubsector_t * ) data ;
subsector_t * ss = subsectors ;
size_t i ;
for ( i = 0 ; i < numsubsectors ; i + + , ss + + , ms + + )
{
ss - > numlines = SHORT ( ms - > numsegs ) ;
ss - > firstline = SHORT ( ms - > firstseg ) ;
2019-12-29 18:54:04 +00:00
P_InitializeSubsector ( ss ) ;
2019-12-28 15:40:35 +00:00
}
}
static void P_LoadNodes ( UINT8 * data )
{
UINT8 j , k ;
mapnode_t * mn = ( mapnode_t * ) data ;
node_t * no = nodes ;
size_t i ;
for ( i = 0 ; i < numnodes ; i + + , no + + , mn + + )
{
no - > x = SHORT ( mn - > x ) < < FRACBITS ;
no - > y = SHORT ( mn - > y ) < < FRACBITS ;
no - > dx = SHORT ( mn - > dx ) < < FRACBITS ;
no - > dy = SHORT ( mn - > dy ) < < FRACBITS ;
for ( j = 0 ; j < 2 ; j + + )
{
no - > children [ j ] = SHORT ( mn - > children [ j ] ) ;
for ( k = 0 ; k < 4 ; k + + )
no - > bbox [ j ] [ k ] = SHORT ( mn - > bbox [ j ] [ k ] ) < < FRACBITS ;
}
}
}
/** Computes the length of a seg in fracunits.
*
* \ param seg Seg to compute length for .
* \ return Length in fracunits .
*/
2020-10-12 03:13:22 +00:00
static fixed_t P_SegLength ( seg_t * seg )
2019-12-28 15:40:35 +00:00
{
INT64 dx = ( seg - > v2 - > x - seg - > v1 - > x ) > > 1 ;
INT64 dy = ( seg - > v2 - > y - seg - > v1 - > y ) > > 1 ;
return FixedHypot ( dx , dy ) < < 1 ;
}
# ifdef HWRENDER
/** Computes the length of a seg as a float.
* This is needed for OpenGL .
*
* \ param seg Seg to compute length for .
* \ return Length as a float .
*/
static inline float P_SegLengthFloat ( seg_t * seg )
{
float dx , dy ;
// make a vector (start at origin)
dx = FIXED_TO_FLOAT ( seg - > v2 - > x - seg - > v1 - > x ) ;
dy = FIXED_TO_FLOAT ( seg - > v2 - > y - seg - > v1 - > y ) ;
return ( float ) hypot ( dx , dy ) ;
}
# endif
2019-12-29 19:24:14 +00:00
static void P_InitializeSeg ( seg_t * seg )
{
2020-01-02 08:51:07 +00:00
if ( seg - > linedef )
{
2020-05-03 17:28:52 +00:00
UINT16 side = seg - > linedef - > sidenum [ seg - > side ] ;
if ( side = = 0xffff )
I_Error ( " P_InitializeSeg: Seg %s refers to side %d of linedef %s, which doesn't exist! \n " , sizeu1 ( ( size_t ) ( seg - segs ) ) , seg - > side , sizeu1 ( ( size_t ) ( seg - > linedef - lines ) ) ) ;
seg - > sidedef = & sides [ side ] ;
2019-12-29 19:24:14 +00:00
2020-01-02 08:51:07 +00:00
seg - > frontsector = seg - > sidedef - > sector ;
seg - > backsector = ( seg - > linedef - > flags & ML_TWOSIDED ) ? sides [ seg - > linedef - > sidenum [ seg - > side ^ 1 ] ] . sector : NULL ;
}
2019-12-29 19:24:14 +00:00
# ifdef HWRENDER
seg - > pv1 = seg - > pv2 = NULL ;
//Hurdler: 04/12/2000: for now, only used in hardware mode
seg - > lightmaps = NULL ; // list of static lightmap for this seg
# endif
seg - > numlights = 0 ;
seg - > rlights = NULL ;
seg - > polyseg = NULL ;
seg - > dontrenderme = false ;
}
2019-12-28 15:40:35 +00:00
static void P_LoadSegs ( UINT8 * data )
{
2019-12-29 19:24:14 +00:00
mapseg_t * ms = ( mapseg_t * ) data ;
seg_t * seg = segs ;
2019-12-28 15:40:35 +00:00
size_t i ;
2019-12-29 19:24:14 +00:00
for ( i = 0 ; i < numsegs ; i + + , seg + + , ms + + )
2019-12-28 15:40:35 +00:00
{
2019-12-29 19:24:14 +00:00
seg - > v1 = & vertexes [ SHORT ( ms - > v1 ) ] ;
seg - > v2 = & vertexes [ SHORT ( ms - > v2 ) ] ;
seg - > side = SHORT ( ms - > side ) ;
seg - > offset = ( SHORT ( ms - > offset ) ) < < FRACBITS ;
2019-12-28 15:40:35 +00:00
2019-12-29 19:24:14 +00:00
seg - > angle = ( SHORT ( ms - > angle ) ) < < FRACBITS ;
seg - > linedef = & lines [ SHORT ( ms - > linedef ) ] ;
seg - > length = P_SegLength ( seg ) ;
2019-12-28 15:40:35 +00:00
# ifdef HWRENDER
2019-12-29 19:24:14 +00:00
seg - > flength = ( rendermode = = render_opengl ) ? P_SegLengthFloat ( seg ) : 0 ;
2019-12-28 15:40:35 +00:00
# endif
2019-12-29 19:24:14 +00:00
seg - > glseg = false ;
P_InitializeSeg ( seg ) ;
2019-12-28 15:40:35 +00:00
}
}
2019-12-29 13:17:51 +00:00
typedef enum {
NT_DOOM ,
NT_XNOD ,
NT_ZNOD ,
NT_XGLN ,
NT_ZGLN ,
NT_XGL2 ,
NT_ZGL2 ,
NT_XGL3 ,
NT_ZGL3 ,
2019-12-29 14:50:53 +00:00
NT_UNSUPPORTED ,
NUMNODETYPES
2019-12-29 13:17:51 +00:00
} nodetype_t ;
2019-12-29 14:50:53 +00:00
// Find out the BSP format.
2019-12-29 21:11:15 +00:00
static nodetype_t P_GetNodetype ( const virtres_t * virt , UINT8 * * nodedata )
2019-12-29 14:50:53 +00:00
{
2019-12-30 00:52:39 +00:00
boolean supported [ NUMNODETYPES ] = { 0 } ;
2019-12-29 14:50:53 +00:00
nodetype_t nodetype = NT_UNSUPPORTED ;
char signature [ 4 + 1 ] ;
2020-03-15 15:23:15 +00:00
if ( udmf )
2019-12-29 14:50:53 +00:00
{
2019-12-29 21:11:15 +00:00
* nodedata = vres_Find ( virt , " ZNODES " ) - > data ;
2019-12-29 14:50:53 +00:00
supported [ NT_XGLN ] = supported [ NT_XGL3 ] = true ;
}
else
{
virtlump_t * virtsegs = vres_Find ( virt , " SEGS " ) ;
virtlump_t * virtssectors ;
if ( virtsegs & & virtsegs - > size )
2019-12-29 19:43:41 +00:00
{
2019-12-29 21:11:15 +00:00
* nodedata = vres_Find ( virt , " NODES " ) - > data ;
2019-12-29 14:50:53 +00:00
return NT_DOOM ; // Traditional map format BSP tree.
2019-12-29 19:43:41 +00:00
}
2019-12-29 14:50:53 +00:00
virtssectors = vres_Find ( virt , " SSECTORS " ) ;
if ( virtssectors & & virtssectors - > size )
{ // Possibly GL nodes: NODES ignored, SSECTORS takes precedence as nodes lump, (It is confusing yeah) and has a signature.
2019-12-29 21:11:15 +00:00
* nodedata = virtssectors - > data ;
2019-12-29 14:50:53 +00:00
supported [ NT_XGLN ] = supported [ NT_ZGLN ] = supported [ NT_XGL3 ] = true ;
}
else
{ // Possibly ZDoom extended nodes: SSECTORS is empty, NODES has a signature.
2019-12-29 21:11:15 +00:00
* nodedata = vres_Find ( virt , " NODES " ) - > data ;
2019-12-29 14:50:53 +00:00
supported [ NT_XNOD ] = supported [ NT_ZNOD ] = true ;
}
}
2019-12-29 21:11:15 +00:00
M_Memcpy ( signature , * nodedata , 4 ) ;
2019-12-29 14:59:15 +00:00
signature [ 4 ] = ' \0 ' ;
2019-12-29 21:11:15 +00:00
( * nodedata ) + = 4 ;
2019-12-29 14:59:15 +00:00
2019-12-29 14:50:53 +00:00
if ( ! strcmp ( signature , " XNOD " ) )
nodetype = NT_XNOD ;
else if ( ! strcmp ( signature , " ZNOD " ) )
nodetype = NT_ZNOD ;
else if ( ! strcmp ( signature , " XGLN " ) )
nodetype = NT_XGLN ;
else if ( ! strcmp ( signature , " ZGLN " ) )
nodetype = NT_ZGLN ;
else if ( ! strcmp ( signature , " XGL3 " ) )
nodetype = NT_XGL3 ;
return supported [ nodetype ] ? nodetype : NT_UNSUPPORTED ;
}
2019-12-29 17:07:44 +00:00
// Extended node formats feature additional vertices; useful for OpenGL, but totally useless in gamelogic.
2019-12-29 21:11:15 +00:00
static boolean P_LoadExtraVertices ( UINT8 * * data )
2019-12-29 17:07:44 +00:00
{
2019-12-29 21:11:15 +00:00
UINT32 origvrtx = READUINT32 ( ( * data ) ) ;
UINT32 xtrvrtx = READUINT32 ( ( * data ) ) ;
2019-12-29 17:07:44 +00:00
line_t * ld = lines ;
vertex_t * oldpos = vertexes ;
ssize_t offset ;
size_t i ;
if ( numvertexes ! = origvrtx ) // If native vertex count doesn't match node original vertex count, bail out (broken data?).
{
CONS_Alert ( CONS_WARNING , " Vertex count in map data and nodes differ! \n " ) ;
return false ;
}
if ( ! xtrvrtx )
return true ;
// If extra vertexes were generated, reallocate the vertex array and fix the pointers.
numvertexes + = xtrvrtx ;
vertexes = Z_Realloc ( vertexes , numvertexes * sizeof ( * vertexes ) , PU_LEVEL , NULL ) ;
offset = ( size_t ) ( vertexes - oldpos ) ;
for ( i = 0 , ld = lines ; i < numlines ; i + + , ld + + )
{
ld - > v1 + = offset ;
ld - > v2 + = offset ;
}
// Read extra vertex data.
for ( i = origvrtx ; i < numvertexes ; i + + )
{
2019-12-29 21:11:15 +00:00
vertexes [ i ] . x = READFIXED ( ( * data ) ) ;
vertexes [ i ] . y = READFIXED ( ( * data ) ) ;
2019-12-29 17:07:44 +00:00
}
return true ;
}
2019-12-29 21:11:15 +00:00
static boolean P_LoadExtendedSubsectorsAndSegs ( UINT8 * * data , nodetype_t nodetype )
2019-12-29 14:15:32 +00:00
{
2019-12-29 17:07:44 +00:00
size_t i , k ;
2019-12-29 14:15:32 +00:00
INT16 m ;
2019-12-29 18:54:04 +00:00
seg_t * seg ;
2019-12-29 14:15:32 +00:00
// Subsectors
2019-12-29 21:11:15 +00:00
numsubsectors = READUINT32 ( ( * data ) ) ;
2019-12-29 14:15:32 +00:00
subsectors = Z_Calloc ( numsubsectors * sizeof ( * subsectors ) , PU_LEVEL , NULL ) ;
for ( i = 0 ; i < numsubsectors ; i + + )
2019-12-29 21:11:15 +00:00
subsectors [ i ] . numlines = READUINT32 ( ( * data ) ) ;
2019-12-29 14:15:32 +00:00
// Segs
2019-12-29 21:11:15 +00:00
numsegs = READUINT32 ( ( * data ) ) ;
2019-12-29 14:15:32 +00:00
segs = Z_Calloc ( numsegs * sizeof ( * segs ) , PU_LEVEL , NULL ) ;
for ( i = 0 , k = 0 ; i < numsubsectors ; i + + )
{
subsectors [ i ] . firstline = k ;
2019-12-29 18:54:04 +00:00
P_InitializeSubsector ( & subsectors [ i ] ) ;
2019-12-29 14:15:32 +00:00
switch ( nodetype )
{
case NT_XGLN :
2019-12-29 18:04:50 +00:00
case NT_XGL3 :
2019-12-29 14:15:32 +00:00
for ( m = 0 ; m < subsectors [ i ] . numlines ; m + + , k + + )
{
2020-01-02 08:51:07 +00:00
UINT32 vertexnum = READUINT32 ( ( * data ) ) ;
2019-12-29 14:15:32 +00:00
UINT16 linenum ;
2019-12-29 19:24:14 +00:00
2020-01-02 08:51:07 +00:00
if ( vertexnum > = numvertexes )
2020-01-02 21:28:32 +00:00
I_Error ( " P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid vertex %d! \n " , sizeu1 ( k ) , m , vertexnum ) ;
2020-01-02 08:51:07 +00:00
segs [ k - 1 + ( ( m = = 0 ) ? subsectors [ i ] . numlines : 0 ) ] . v2 = segs [ k ] . v1 = & vertexes [ vertexnum ] ;
2019-12-29 19:24:14 +00:00
2020-01-02 08:51:07 +00:00
READUINT32 ( ( * data ) ) ; // partner, can be ignored by software renderer
2019-12-29 19:24:14 +00:00
2020-05-03 17:28:52 +00:00
linenum = ( nodetype = = NT_XGL3 ) ? READUINT32 ( ( * data ) ) : READUINT16 ( ( * data ) ) ;
2020-01-02 08:51:07 +00:00
if ( linenum ! = 0xFFFF & & linenum > = numlines )
2020-01-02 21:28:32 +00:00
I_Error ( " P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid linedef %d! \n " , sizeu1 ( k ) , m , linenum ) ;
2019-12-29 18:04:50 +00:00
segs [ k ] . glseg = ( linenum = = 0xFFFF ) ;
segs [ k ] . linedef = ( linenum = = 0xFFFF ) ? NULL : & lines [ linenum ] ;
2019-12-29 21:11:15 +00:00
segs [ k ] . side = READUINT8 ( ( * data ) ) ;
2019-12-29 14:15:32 +00:00
}
break ;
case NT_XNOD :
for ( m = 0 ; m < subsectors [ i ] . numlines ; m + + , k + + )
{
2020-01-02 08:51:07 +00:00
UINT32 v1num = READUINT32 ( ( * data ) ) ;
UINT32 v2num = READUINT32 ( ( * data ) ) ;
UINT16 linenum = READUINT16 ( ( * data ) ) ;
if ( v1num > = numvertexes )
2020-01-02 21:28:32 +00:00
I_Error ( " P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid v1 %d! \n " , sizeu1 ( k ) , m , v1num ) ;
2020-01-02 08:51:07 +00:00
if ( v2num > = numvertexes )
2020-01-02 21:28:32 +00:00
I_Error ( " P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid v2 %d! \n " , sizeu1 ( k ) , m , v2num ) ;
2020-01-02 08:51:07 +00:00
if ( linenum > = numlines )
2020-01-02 21:28:32 +00:00
I_Error ( " P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid linedef %d! \n " , sizeu1 ( k ) , m , linenum ) ;
2020-01-02 08:51:07 +00:00
segs [ k ] . v1 = & vertexes [ v1num ] ;
segs [ k ] . v2 = & vertexes [ v2num ] ;
segs [ k ] . linedef = & lines [ linenum ] ;
2019-12-29 21:11:15 +00:00
segs [ k ] . side = READUINT8 ( ( * data ) ) ;
2019-12-29 19:24:14 +00:00
segs [ k ] . glseg = false ;
2019-12-29 14:15:32 +00:00
}
break ;
default :
2019-12-29 19:24:14 +00:00
return false ;
2019-12-29 14:15:32 +00:00
}
}
2019-12-29 18:54:04 +00:00
for ( i = 0 , seg = segs ; i < numsegs ; i + + , seg + + )
2019-12-29 14:15:32 +00:00
{
2019-12-29 18:54:04 +00:00
vertex_t * v1 = seg - > v1 ;
vertex_t * v2 = seg - > v2 ;
2019-12-29 19:24:14 +00:00
P_InitializeSeg ( seg ) ;
2019-12-29 18:54:04 +00:00
seg - > angle = R_PointToAngle2 ( v1 - > x , v1 - > y , v2 - > x , v2 - > y ) ;
2020-01-02 08:51:07 +00:00
if ( seg - > linedef )
segs [ i ] . offset = FixedHypot ( v1 - > x - seg - > linedef - > v1 - > x , v1 - > y - seg - > linedef - > v1 - > y ) ;
2020-10-28 19:36:03 +00:00
seg - > length = P_SegLength ( seg ) ;
# ifdef HWRENDER
seg - > flength = ( rendermode = = render_opengl ) ? P_SegLengthFloat ( seg ) : 0 ;
# endif
2019-12-29 14:15:32 +00:00
}
2019-12-29 19:24:14 +00:00
return true ;
2019-12-29 18:54:04 +00:00
}
// Auxiliary function: Shrink node ID from 32-bit to 16-bit.
static UINT16 ShrinkNodeID ( UINT32 x ) {
UINT16 mask = ( x > > 16 ) & 0xC000 ;
UINT16 result = x ;
return result | mask ;
}
2019-12-29 21:11:15 +00:00
static void P_LoadExtendedNodes ( UINT8 * * data , nodetype_t nodetype )
2019-12-29 18:54:04 +00:00
{
node_t * mn ;
size_t i , j , k ;
boolean xgl3 = ( nodetype = = NT_XGL3 ) ;
2019-12-29 14:15:32 +00:00
2019-12-29 21:11:15 +00:00
numnodes = READINT32 ( ( * data ) ) ;
2019-12-29 14:15:32 +00:00
nodes = Z_Calloc ( numnodes * sizeof ( * nodes ) , PU_LEVEL , NULL ) ;
2019-12-29 18:54:04 +00:00
for ( i = 0 , mn = nodes ; i < numnodes ; i + + , mn + + )
{
// Splitter
2019-12-29 21:11:15 +00:00
mn - > x = xgl3 ? READINT32 ( ( * data ) ) : ( READINT16 ( ( * data ) ) < < FRACBITS ) ;
mn - > y = xgl3 ? READINT32 ( ( * data ) ) : ( READINT16 ( ( * data ) ) < < FRACBITS ) ;
mn - > dx = xgl3 ? READINT32 ( ( * data ) ) : ( READINT16 ( ( * data ) ) < < FRACBITS ) ;
mn - > dy = xgl3 ? READINT32 ( ( * data ) ) : ( READINT16 ( ( * data ) ) < < FRACBITS ) ;
2019-12-29 18:54:04 +00:00
// Bounding boxes
for ( j = 0 ; j < 2 ; j + + )
for ( k = 0 ; k < 4 ; k + + )
2019-12-29 21:11:15 +00:00
mn - > bbox [ j ] [ k ] = READINT16 ( ( * data ) ) < < FRACBITS ;
2019-12-29 18:54:04 +00:00
//Children
2019-12-29 21:11:15 +00:00
mn - > children [ 0 ] = ShrinkNodeID ( READUINT32 ( ( * data ) ) ) ; /// \todo Use UINT32 for node children in a future, instead?
mn - > children [ 1 ] = ShrinkNodeID ( READUINT32 ( ( * data ) ) ) ;
2019-12-29 18:54:04 +00:00
}
2019-12-29 14:15:32 +00:00
}
2019-12-28 15:40:35 +00:00
static void P_LoadMapBSP ( const virtres_t * virt )
{
2019-12-29 21:11:15 +00:00
UINT8 * nodedata = NULL ;
nodetype_t nodetype = P_GetNodetype ( virt , & nodedata ) ;
2019-12-29 13:17:51 +00:00
switch ( nodetype )
{
case NT_DOOM :
2019-12-29 14:50:53 +00:00
{
virtlump_t * virtssectors = vres_Find ( virt , " SSECTORS " ) ;
2019-12-29 21:11:15 +00:00
virtlump_t * virtnodes = vres_Find ( virt , " NODES " ) ;
2019-12-29 14:50:53 +00:00
virtlump_t * virtsegs = vres_Find ( virt , " SEGS " ) ;
2019-12-29 13:17:51 +00:00
numsubsectors = virtssectors - > size / sizeof ( mapsubsector_t ) ;
numnodes = virtnodes - > size / sizeof ( mapnode_t ) ;
numsegs = virtsegs - > size / sizeof ( mapseg_t ) ;
if ( numsubsectors < = 0 )
I_Error ( " Level has no subsectors (did you forget to run it through a nodesbuilder?) " ) ;
if ( numnodes < = 0 )
2021-05-24 05:00:01 +00:00
I_Error ( " Level has no nodes (does your map have at least 2 sectors?) " ) ;
2019-12-29 13:17:51 +00:00
if ( numsegs < = 0 )
I_Error ( " Level has no segs " ) ;
subsectors = Z_Calloc ( numsubsectors * sizeof ( * subsectors ) , PU_LEVEL , NULL ) ;
nodes = Z_Calloc ( numnodes * sizeof ( * nodes ) , PU_LEVEL , NULL ) ;
segs = Z_Calloc ( numsegs * sizeof ( * segs ) , PU_LEVEL , NULL ) ;
P_LoadSubsectors ( virtssectors - > data ) ;
P_LoadNodes ( virtnodes - > data ) ;
P_LoadSegs ( virtsegs - > data ) ;
break ;
2019-12-29 14:50:53 +00:00
}
2019-12-29 13:17:51 +00:00
case NT_XNOD :
case NT_XGLN :
case NT_XGL3 :
2019-12-29 21:11:15 +00:00
if ( ! P_LoadExtraVertices ( & nodedata ) )
2019-12-29 18:54:04 +00:00
return ;
2019-12-29 21:11:15 +00:00
if ( ! P_LoadExtendedSubsectorsAndSegs ( & nodedata , nodetype ) )
2019-12-29 18:54:04 +00:00
return ;
2019-12-29 21:11:15 +00:00
P_LoadExtendedNodes ( & nodedata , nodetype ) ;
2019-12-29 13:17:51 +00:00
break ;
default :
CONS_Alert ( CONS_WARNING , " Unsupported BSP format detected. \n " ) ;
return ;
}
return ;
2019-12-28 15:40:35 +00:00
}
// Split from P_LoadBlockMap for convenience
// -- Monster Iestyn 08/01/18
static void P_ReadBlockMapLump ( INT16 * wadblockmaplump , size_t count )
{
size_t i ;
blockmaplump = Z_Calloc ( sizeof ( * blockmaplump ) * count , PU_LEVEL , NULL ) ;
// killough 3/1/98: Expand wad blockmap into larger internal one,
// by treating all offsets except -1 as unsigned and zero-extending
// them. This potentially doubles the size of blockmaps allowed,
// because Doom originally considered the offsets as always signed.
blockmaplump [ 0 ] = SHORT ( wadblockmaplump [ 0 ] ) ;
blockmaplump [ 1 ] = SHORT ( wadblockmaplump [ 1 ] ) ;
blockmaplump [ 2 ] = ( INT32 ) ( SHORT ( wadblockmaplump [ 2 ] ) ) & 0xffff ;
blockmaplump [ 3 ] = ( INT32 ) ( SHORT ( wadblockmaplump [ 3 ] ) ) & 0xffff ;
for ( i = 4 ; i < count ; i + + )
{
INT16 t = SHORT ( wadblockmaplump [ i ] ) ; // killough 3/1/98
blockmaplump [ i ] = t = = - 1 ? ( INT32 ) - 1 : ( INT32 ) t & 0xffff ;
}
}
// This needs to be a separate function
// because making both the WAD and PK3 loading code use
// the same functions is trickier than it looks for blockmap
// -- Monster Iestyn 09/01/18
static boolean P_LoadBlockMap ( UINT8 * data , size_t count )
{
if ( ! count | | count > = 0x20000 )
return false ;
//CONS_Printf("Reading blockmap lump for pk3...\n");
// no need to malloc anything, assume the data is uncompressed for now
count / = 2 ;
P_ReadBlockMapLump ( ( INT16 * ) data , count ) ;
bmaporgx = blockmaplump [ 0 ] < < FRACBITS ;
bmaporgy = blockmaplump [ 1 ] < < FRACBITS ;
bmapwidth = blockmaplump [ 2 ] ;
bmapheight = blockmaplump [ 3 ] ;
// clear out mobj chains
count = sizeof ( * blocklinks ) * bmapwidth * bmapheight ;
blocklinks = Z_Calloc ( count , PU_LEVEL , NULL ) ;
blockmap = blockmaplump + 4 ;
// haleyjd 2/22/06: setup polyobject blockmap
count = sizeof ( * polyblocklinks ) * bmapwidth * bmapheight ;
polyblocklinks = Z_Calloc ( count , PU_LEVEL , NULL ) ;
return true ;
}
static boolean LineInBlock ( fixed_t cx1 , fixed_t cy1 , fixed_t cx2 , fixed_t cy2 , fixed_t bx1 , fixed_t by1 )
{
fixed_t bbox [ 4 ] ;
line_t testline ;
vertex_t vtest ;
bbox [ BOXRIGHT ] = bx1 + MAPBLOCKUNITS ;
bbox [ BOXTOP ] = by1 + MAPBLOCKUNITS ;
bbox [ BOXLEFT ] = bx1 ;
bbox [ BOXBOTTOM ] = by1 ;
// Trivial rejection
if ( cx1 < bbox [ BOXLEFT ] & & cx2 < bbox [ BOXLEFT ] )
return false ;
if ( cx1 > bbox [ BOXRIGHT ] & & cx2 > bbox [ BOXRIGHT ] )
return false ;
if ( cy1 < bbox [ BOXBOTTOM ] & & cy2 < bbox [ BOXBOTTOM ] )
return false ;
if ( cy1 > bbox [ BOXTOP ] & & cy2 > bbox [ BOXTOP ] )
return false ;
// Rats, guess we gotta check
// if the line intersects
// any sides of the block.
cx1 < < = FRACBITS ;
cy1 < < = FRACBITS ;
cx2 < < = FRACBITS ;
cy2 < < = FRACBITS ;
bbox [ BOXTOP ] < < = FRACBITS ;
bbox [ BOXBOTTOM ] < < = FRACBITS ;
bbox [ BOXLEFT ] < < = FRACBITS ;
bbox [ BOXRIGHT ] < < = FRACBITS ;
testline . v1 = & vtest ;
testline . v1 - > x = cx1 ;
2014-03-15 16:59:03 +00:00
testline . v1 - > y = cy1 ;
testline . dx = cx2 - cx1 ;
testline . dy = cy2 - cy1 ;
2015-01-01 19:50:31 +00:00
if ( ( testline . dx > 0 ) ^ ( testline . dy > 0 ) )
testline . slopetype = ST_NEGATIVE ;
else
testline . slopetype = ST_POSITIVE ;
2014-03-15 16:59:03 +00:00
2015-01-01 19:50:31 +00:00
return P_BoxOnLineSide ( bbox , & testline ) = = - 1 ;
2014-03-15 16:59:03 +00:00
}
//
// killough 10/98:
//
// Rewritten to use faster algorithm.
//
// SSN Edit: Killough's wasn't accurate enough, sometimes excluding
// blocks that the line did in fact exist in, so now we use
// a fail-safe approach that puts a 'box' around each line.
//
// Please note: This section of code is not interchangable with TeamTNT's
// code which attempts to fix the same problem.
static void P_CreateBlockMap ( void )
{
register size_t i ;
fixed_t minx = INT32_MAX , miny = INT32_MAX , maxx = INT32_MIN , maxy = INT32_MIN ;
// First find limits of map
for ( i = 0 ; i < numvertexes ; i + + )
{
if ( vertexes [ i ] . x > > FRACBITS < minx )
minx = vertexes [ i ] . x > > FRACBITS ;
else if ( vertexes [ i ] . x > > FRACBITS > maxx )
maxx = vertexes [ i ] . x > > FRACBITS ;
if ( vertexes [ i ] . y > > FRACBITS < miny )
miny = vertexes [ i ] . y > > FRACBITS ;
else if ( vertexes [ i ] . y > > FRACBITS > maxy )
maxy = vertexes [ i ] . y > > FRACBITS ;
}
// Save blockmap parameters
bmaporgx = minx < < FRACBITS ;
bmaporgy = miny < < FRACBITS ;
bmapwidth = ( ( maxx - minx ) > > MAPBTOFRAC ) + 1 ;
bmapheight = ( ( maxy - miny ) > > MAPBTOFRAC ) + 1 ;
// Compute blockmap, which is stored as a 2d array of variable-sized lists.
//
// Pseudocode:
//
// For each linedef:
//
// Map the starting and ending vertices to blocks.
//
// Starting in the starting vertex's block, do:
//
// Add linedef to current block's list, dynamically resizing it.
//
// If current block is the same as the ending vertex's block, exit loop.
//
// Move to an adjacent block by moving towards the ending block in
// either the x or y direction, to the block which contains the linedef.
{
typedef struct
{
INT32 n , nalloc ;
INT32 * list ;
} bmap_t ; // blocklist structure
size_t tot = bmapwidth * bmapheight ; // size of blockmap
bmap_t * bmap = calloc ( tot , sizeof ( * bmap ) ) ; // array of blocklists
boolean straight ;
if ( bmap = = NULL ) I_Error ( " %s: Out of memory making blockmap " , " P_CreateBlockMap " ) ;
for ( i = 0 ; i < numlines ; i + + )
{
// starting coordinates
INT32 x = ( lines [ i ] . v1 - > x > > FRACBITS ) - minx ;
INT32 y = ( lines [ i ] . v1 - > y > > FRACBITS ) - miny ;
INT32 bxstart , bxend , bystart , byend , v2x , v2y , curblockx , curblocky ;
v2x = lines [ i ] . v2 - > x > > FRACBITS ;
v2y = lines [ i ] . v2 - > y > > FRACBITS ;
// Draw a "box" around the line.
bxstart = ( x > > MAPBTOFRAC ) ;
bystart = ( y > > MAPBTOFRAC ) ;
v2x - = minx ;
v2y - = miny ;
bxend = ( ( v2x ) > > MAPBTOFRAC ) ;
byend = ( ( v2y ) > > MAPBTOFRAC ) ;
if ( bxend < bxstart )
{
INT32 temp = bxstart ;
bxstart = bxend ;
bxend = temp ;
}
if ( byend < bystart )
{
INT32 temp = bystart ;
bystart = byend ;
byend = temp ;
}
// Catch straight lines
// This fixes the error where straight lines
// directly on a blockmap boundary would not
// be included in the proper blocks.
if ( lines [ i ] . v1 - > y = = lines [ i ] . v2 - > y )
{
straight = true ;
bystart - - ;
byend + + ;
}
else if ( lines [ i ] . v1 - > x = = lines [ i ] . v2 - > x )
{
straight = true ;
bxstart - - ;
bxend + + ;
}
else
straight = false ;
// Now we simply iterate block-by-block until we reach the end block.
for ( curblockx = bxstart ; curblockx < = bxend ; curblockx + + )
for ( curblocky = bystart ; curblocky < = byend ; curblocky + + )
{
size_t b = curblocky * bmapwidth + curblockx ;
if ( b > = tot )
continue ;
if ( ! straight & & ! ( LineInBlock ( ( fixed_t ) x , ( fixed_t ) y , ( fixed_t ) v2x , ( fixed_t ) v2y , ( fixed_t ) ( curblockx < < MAPBTOFRAC ) , ( fixed_t ) ( curblocky < < MAPBTOFRAC ) ) ) )
continue ;
// Increase size of allocated list if necessary
if ( bmap [ b ] . n > = bmap [ b ] . nalloc )
{
// Graue 02-29-2004: make code more readable, don't realloc a null pointer
// (because it crashes for me, and because the comp.lang.c FAQ says so)
if ( bmap [ b ] . nalloc = = 0 )
bmap [ b ] . nalloc = 8 ;
else
bmap [ b ] . nalloc * = 2 ;
bmap [ b ] . list = Z_Realloc ( bmap [ b ] . list , bmap [ b ] . nalloc * sizeof ( * bmap - > list ) , PU_CACHE , & bmap [ b ] . list ) ;
if ( ! bmap [ b ] . list )
I_Error ( " Out of Memory in P_CreateBlockMap " ) ;
}
// Add linedef to end of list
bmap [ b ] . list [ bmap [ b ] . n + + ] = ( INT32 ) i ;
}
}
// Compute the total size of the blockmap.
//
// Compression of empty blocks is performed by reserving two offset words
// at tot and tot+1.
//
// 4 words, unused if this routine is called, are reserved at the start.
{
size_t count = tot + 6 ; // we need at least 1 word per block, plus reserved's
for ( i = 0 ; i < tot ; i + + )
if ( bmap [ i ] . n )
count + = bmap [ i ] . n + 2 ; // 1 header word + 1 trailer word + blocklist
// Allocate blockmap lump with computed count
blockmaplump = Z_Calloc ( sizeof ( * blockmaplump ) * count , PU_LEVEL , NULL ) ;
}
// Now compress the blockmap.
{
size_t ndx = tot + = 4 ; // Advance index to start of linedef lists
bmap_t * bp = bmap ; // Start of uncompressed blockmap
blockmaplump [ ndx + + ] = 0 ; // Store an empty blockmap list at start
blockmaplump [ ndx + + ] = - 1 ; // (Used for compression)
for ( i = 4 ; i < tot ; i + + , bp + + )
if ( bp - > n ) // Non-empty blocklist
{
blockmaplump [ blockmaplump [ i ] = ( INT32 ) ( ndx + + ) ] = 0 ; // Store index & header
do
blockmaplump [ ndx + + ] = bp - > list [ - - bp - > n ] ; // Copy linedef list
while ( bp - > n ) ;
blockmaplump [ ndx + + ] = - 1 ; // Store trailer
Z_Free ( bp - > list ) ; // Free linedef list
}
else // Empty blocklist: point to reserved empty blocklist
blockmaplump [ i ] = ( INT32 ) tot ;
free ( bmap ) ; // Free uncompressed blockmap
}
}
{
size_t count = sizeof ( * blocklinks ) * bmapwidth * bmapheight ;
// clear out mobj chains (copied from from P_LoadBlockMap)
blocklinks = Z_Calloc ( count , PU_LEVEL , NULL ) ;
blockmap = blockmaplump + 4 ;
// haleyjd 2/22/06: setup polyobject blockmap
count = sizeof ( * polyblocklinks ) * bmapwidth * bmapheight ;
polyblocklinks = Z_Calloc ( count , PU_LEVEL , NULL ) ;
}
2019-12-28 15:40:35 +00:00
}
// PK3 version
// -- Monster Iestyn 09/01/18
static void P_LoadReject ( UINT8 * data , size_t count )
{
if ( ! count ) // zero length, someone probably used ZDBSP
{
rejectmatrix = NULL ;
CONS_Debug ( DBG_SETUP , " P_LoadReject: REJECT lump has size 0, will not be loaded \n " ) ;
}
else
{
rejectmatrix = Z_Malloc ( count , PU_LEVEL , NULL ) ; // allocate memory for the reject matrix
M_Memcpy ( rejectmatrix , data , count ) ; // copy the data into it
}
}
static void P_LoadMapLUT ( const virtres_t * virt )
{
virtlump_t * virtblockmap = vres_Find ( virt , " BLOCKMAP " ) ;
virtlump_t * virtreject = vres_Find ( virt , " REJECT " ) ;
// Lookup tables
if ( virtreject )
P_LoadReject ( virtreject - > data , virtreject - > size ) ;
else
rejectmatrix = NULL ;
if ( ! ( virtblockmap & & P_LoadBlockMap ( virtblockmap - > data , virtblockmap - > size ) ) )
P_CreateBlockMap ( ) ;
}
2014-03-15 16:59:03 +00:00
//
2019-12-28 16:40:08 +00:00
// P_LinkMapData
2014-03-15 16:59:03 +00:00
// Builds sector line lists and subsector sector numbers.
// Finds block bounding boxes for sectors.
//
2019-12-28 16:40:08 +00:00
static void P_LinkMapData ( void )
2014-03-15 16:59:03 +00:00
{
2016-04-02 16:01:58 +00:00
size_t i , j ;
2014-03-15 16:59:03 +00:00
line_t * li ;
sector_t * sector ;
subsector_t * ss = subsectors ;
size_t sidei ;
seg_t * seg ;
fixed_t bbox [ 4 ] ;
// look up sector number for each subsector
for ( i = 0 ; i < numsubsectors ; i + + , ss + + )
{
if ( ss - > firstline > = numsegs )
2019-12-28 16:40:08 +00:00
CorruptMapError ( va ( " P_LinkMapData: ss->firstline invalid "
2014-03-15 16:59:03 +00:00
" (subsector %s, firstline refers to %d of %s) " , sizeu1 ( i ) , ss - > firstline ,
sizeu2 ( numsegs ) ) ) ;
seg = & segs [ ss - > firstline ] ;
sidei = ( size_t ) ( seg - > sidedef - sides ) ;
if ( ! seg - > sidedef )
2019-12-28 16:40:08 +00:00
CorruptMapError ( va ( " P_LinkMapData: seg->sidedef is NULL "
2014-03-15 16:59:03 +00:00
" (subsector %s, firstline is %d) " , sizeu1 ( i ) , ss - > firstline ) ) ;
if ( seg - > sidedef - sides < 0 | | seg - > sidedef - sides > ( UINT16 ) numsides )
2019-12-28 16:40:08 +00:00
CorruptMapError ( va ( " P_LinkMapData: seg->sidedef refers to sidedef %s of %s "
2014-03-15 16:59:03 +00:00
" (subsector %s, firstline is %d) " , sizeu1 ( sidei ) , sizeu2 ( numsides ) ,
sizeu3 ( i ) , ss - > firstline ) ) ;
if ( ! seg - > sidedef - > sector )
2019-12-28 16:40:08 +00:00
CorruptMapError ( va ( " P_LinkMapData: seg->sidedef->sector is NULL "
2014-03-15 16:59:03 +00:00
" (subsector %s, firstline is %d, sidedef is %s) " , sizeu1 ( i ) , ss - > firstline ,
sizeu1 ( sidei ) ) ) ;
ss - > sector = seg - > sidedef - > sector ;
}
// count number of lines in each sector
for ( i = 0 , li = lines ; i < numlines ; i + + , li + + )
{
li - > frontsector - > linecount + + ;
if ( li - > backsector & & li - > backsector ! = li - > frontsector )
li - > backsector - > linecount + + ;
}
// allocate linebuffers for each sector
for ( i = 0 , sector = sectors ; i < numsectors ; i + + , sector + + )
{
2016-06-11 15:14:08 +00:00
if ( sector - > linecount = = 0 ) // no lines found?
{
sector - > lines = NULL ;
2019-12-28 16:40:08 +00:00
CONS_Debug ( DBG_SETUP , " P_LinkMapData: sector %s has no lines \n " , sizeu1 ( i ) ) ;
2016-06-11 15:14:08 +00:00
}
else
{
sector - > lines = Z_Calloc ( sector - > linecount * sizeof ( line_t * ) , PU_LEVEL , NULL ) ;
2014-03-15 16:59:03 +00:00
2016-06-11 15:14:08 +00:00
// zero the count, since we'll later use this to track how many we've recorded
sector - > linecount = 0 ;
}
2014-03-15 16:59:03 +00:00
}
// iterate through lines, assigning them to sectors' linebuffers,
// and recalculate the counts in the process
for ( i = 0 , li = lines ; i < numlines ; i + + , li + + )
{
li - > frontsector - > lines [ li - > frontsector - > linecount + + ] = li ;
if ( li - > backsector & & li - > backsector ! = li - > frontsector )
li - > backsector - > lines [ li - > backsector - > linecount + + ] = li ;
}
// set soundorg's position for each sector
for ( i = 0 , sector = sectors ; i < numsectors ; i + + , sector + + )
{
M_ClearBox ( bbox ) ;
2016-06-11 15:14:08 +00:00
if ( sector - > linecount ! = 0 )
2014-03-15 16:59:03 +00:00
{
2016-06-11 15:14:08 +00:00
for ( j = 0 ; j < sector - > linecount ; j + + )
{
li = sector - > lines [ j ] ;
M_AddToBox ( bbox , li - > v1 - > x , li - > v1 - > y ) ;
M_AddToBox ( bbox , li - > v2 - > x , li - > v2 - > y ) ;
}
2014-03-15 16:59:03 +00:00
}
// set the degenmobj_t to the middle of the bounding box
sector - > soundorg . x = ( ( ( bbox [ BOXRIGHT ] > > FRACBITS ) + ( bbox [ BOXLEFT ] > > FRACBITS ) ) / 2 ) < < FRACBITS ;
sector - > soundorg . y = ( ( ( bbox [ BOXTOP ] > > FRACBITS ) + ( bbox [ BOXBOTTOM ] > > FRACBITS ) ) / 2 ) < < FRACBITS ;
sector - > soundorg . z = sector - > floorheight ; // default to sector's floor height
}
}
2021-04-26 23:27:39 +00:00
// For maps in binary format, add multi-tags from linedef specials. This must be done
// before any linedef specials have been processed.
2021-05-29 03:59:39 +00:00
static void P_AddBinaryMapTagsFromLine ( sector_t * sector , line_t * line )
{
Tag_Add ( & sector - > tags , Tag_FGet ( & line - > tags ) ) ;
if ( line - > flags & ML_EFFECT6 ) {
if ( sides [ line - > sidenum [ 0 ] ] . textureoffset )
2021-05-29 04:40:06 +00:00
Tag_Add ( & sector - > tags , ( INT32 ) sides [ line - > sidenum [ 0 ] ] . textureoffset / FRACUNIT ) ;
2021-05-29 03:59:39 +00:00
if ( sides [ line - > sidenum [ 0 ] ] . rowoffset )
2021-05-29 04:40:06 +00:00
Tag_Add ( & sector - > tags , ( INT32 ) sides [ line - > sidenum [ 0 ] ] . rowoffset / FRACUNIT ) ;
2021-05-29 03:59:39 +00:00
}
if ( line - > flags & ML_TFERLINE ) {
if ( sides [ line - > sidenum [ 1 ] ] . textureoffset )
2021-05-29 04:40:06 +00:00
Tag_Add ( & sector - > tags , ( INT32 ) sides [ line - > sidenum [ 1 ] ] . textureoffset / FRACUNIT ) ;
2021-05-29 03:59:39 +00:00
if ( sides [ line - > sidenum [ 1 ] ] . rowoffset )
2021-05-29 04:40:06 +00:00
Tag_Add ( & sector - > tags , ( INT32 ) sides [ line - > sidenum [ 1 ] ] . rowoffset / FRACUNIT ) ;
2021-05-29 03:59:39 +00:00
}
}
2021-04-26 23:27:39 +00:00
static void P_AddBinaryMapTags ( void )
{
size_t i ;
for ( i = 0 ; i < numlines ; i + + )
{
2021-05-29 03:59:39 +00:00
// 96: Apply Tag to Tagged Sectors
2021-04-26 23:27:39 +00:00
// 97: Apply Tag to Front Sector
// 98: Apply Tag to Back Sector
// 99: Apply Tag to Front and Back Sectors
2021-05-29 03:59:39 +00:00
if ( lines [ i ] . special = = 96 ) {
2021-05-29 15:08:46 +00:00
size_t j ;
2021-05-29 03:59:39 +00:00
mtag_t tag = Tag_FGet ( & lines [ i ] . frontsector - > tags ) ;
2021-05-30 16:16:15 +00:00
mtag_t target_tag = Tag_FGet ( & lines [ i ] . tags ) ;
mtag_t offset_tags [ 4 ] ;
memset ( offset_tags , 0 , sizeof ( mtag_t ) * 4 ) ;
2021-05-29 15:08:46 +00:00
if ( lines [ i ] . flags & ML_EFFECT6 ) {
2021-06-01 14:09:57 +00:00
offset_tags [ 0 ] = ( INT32 ) sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset / FRACUNIT ;
offset_tags [ 1 ] = ( INT32 ) sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset / FRACUNIT ;
2021-05-29 15:08:46 +00:00
}
if ( lines [ i ] . flags & ML_TFERLINE ) {
2021-06-01 14:09:57 +00:00
offset_tags [ 2 ] = ( INT32 ) sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset / FRACUNIT ;
offset_tags [ 3 ] = ( INT32 ) sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset / FRACUNIT ;
2021-05-29 15:08:46 +00:00
}
for ( j = 0 ; j < numsectors ; j + + ) {
2021-06-10 15:49:33 +00:00
boolean matches_target_tag = target_tag & & Tag_Find ( & sectors [ j ] . tags , target_tag ) ;
2021-05-30 16:16:15 +00:00
size_t k ; for ( k = 0 ; k < 4 ; k + + ) {
if ( lines [ i ] . flags & ML_EFFECT5 ) {
2021-06-01 21:10:29 +00:00
if ( matches_target_tag | | ( offset_tags [ k ] & & Tag_Find ( & sectors [ j ] . tags , offset_tags [ k ] ) ) ) {
2021-05-30 16:16:15 +00:00
Tag_Add ( & sectors [ j ] . tags , tag ) ;
break ;
}
} else if ( matches_target_tag ) {
if ( k = = 0 )
Tag_Add ( & sectors [ j ] . tags , tag ) ;
if ( offset_tags [ k ] )
Tag_Add ( & sectors [ j ] . tags , offset_tags [ k ] ) ;
2021-05-29 15:08:46 +00:00
}
}
2021-05-29 04:54:31 +00:00
}
2021-05-29 16:28:06 +00:00
} else {
if ( lines [ i ] . special = = 97 | | lines [ i ] . special = = 99 )
P_AddBinaryMapTagsFromLine ( lines [ i ] . frontsector , & lines [ i ] ) ;
if ( lines [ i ] . special = = 98 | | lines [ i ] . special = = 99 )
P_AddBinaryMapTagsFromLine ( lines [ i ] . backsector , & lines [ i ] ) ;
2021-05-29 03:59:39 +00:00
}
2021-04-26 23:27:39 +00:00
}
2021-09-21 10:55:22 +00:00
for ( i = 0 ; i < nummapthings ; i + + )
{
switch ( mapthings [ i ] . type )
{
case 291 :
2021-12-21 16:58:37 +00:00
case 322 :
2021-09-21 10:55:22 +00:00
case 750 :
case 760 :
case 761 :
case 762 :
Tag_FSet ( & mapthings [ i ] . tags , mapthings [ i ] . angle ) ;
break ;
2021-12-26 19:09:38 +00:00
case 290 :
2021-12-27 14:37:21 +00:00
case 292 :
2021-12-25 08:58:00 +00:00
case 294 :
2021-09-21 10:55:22 +00:00
case 780 :
Tag_FSet ( & mapthings [ i ] . tags , mapthings [ i ] . extrainfo ) ;
break ;
default :
break ;
}
}
2021-04-26 23:27:39 +00:00
}
2021-12-14 18:08:59 +00:00
static void P_WriteConstant ( INT32 constant , char * * target )
{
char buffer [ 12 ] ;
sprintf ( buffer , " %d " , constant ) ;
* target = Z_Malloc ( strlen ( buffer ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( * target , buffer , strlen ( buffer ) + 1 ) ;
}
2021-12-16 06:00:30 +00:00
static line_t * P_FindPointPushLine ( taglist_t * list )
{
INT32 i , l ;
for ( i = 0 ; i < list - > count ; i + + )
{
mtag_t tag = list - > tags [ i ] ;
TAG_ITER_LINES ( tag , l )
{
if ( Tag_FGet ( & lines [ l ] . tags ) ! = tag )
continue ;
if ( lines [ l ] . special ! = 547 )
continue ;
return & lines [ l ] ;
}
}
return NULL ;
}
2020-01-05 13:31:56 +00:00
//For maps in binary format, converts setup of specials to UDMF format.
static void P_ConvertBinaryMap ( void )
{
size_t i ;
2021-12-28 10:42:53 +00:00
mobjtype_t mobjtypeofthing [ 4096 ] = { 0 } ;
2021-12-27 14:07:37 +00:00
mobjtype_t mobjtype ;
2020-01-05 13:31:56 +00:00
for ( i = 0 ; i < numlines ; i + + )
{
2020-04-17 09:04:44 +00:00
mtag_t tag = Tag_FGet ( & lines [ i ] . tags ) ;
2020-01-05 13:31:56 +00:00
switch ( lines [ i ] . special )
{
2021-12-29 07:12:28 +00:00
case 7 : //Sector flat alignment
lines [ i ] . args [ 0 ] = tag ;
if ( ( lines [ i ] . flags & ( ML_NETONLY | ML_NONET ) ) = = ( ML_NETONLY | ML_NONET ) )
{
CONS_Alert ( CONS_WARNING , M_GetText ( " Flat alignment linedef (tag %d) doesn't have anything to do. \n Consider changing the linedef's flag configuration or removing it entirely. \n " ) , tag ) ;
lines [ i ] . special = 0 ;
}
else if ( lines [ i ] . flags & ML_NETONLY )
lines [ i ] . args [ 1 ] = TMP_CEILING ;
else if ( lines [ i ] . flags & ML_NONET )
lines [ i ] . args [ 1 ] = TMP_FLOOR ;
else
lines [ i ] . args [ 1 ] = TMP_BOTH ;
lines [ i ] . flags & = ~ ( ML_NETONLY | ML_NONET ) ;
if ( lines [ i ] . flags & ML_EFFECT6 ) // Set offset through x and y texture offsets
{
angle_t flatangle = InvAngle ( R_PointToAngle2 ( lines [ i ] . v1 - > x , lines [ i ] . v1 - > y , lines [ i ] . v2 - > x , lines [ i ] . v2 - > y ) ) ;
fixed_t xoffs = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset ;
fixed_t yoffs = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset ;
//If no tag is given, apply to front sector
if ( lines [ i ] . args [ 0 ] = = 0 )
P_ApplyFlatAlignment ( lines [ i ] . frontsector , flatangle , xoffs , yoffs , lines [ i ] . args [ 1 ] ! = TMP_CEILING , lines [ i ] . args [ 1 ] ! = TMP_FLOOR ) ;
else
{
INT32 s ;
TAG_ITER_SECTORS ( lines [ i ] . args [ 0 ] , s )
P_ApplyFlatAlignment ( sectors + s , flatangle , xoffs , yoffs , lines [ i ] . args [ 1 ] ! = TMP_CEILING , lines [ i ] . args [ 1 ] ! = TMP_FLOOR ) ;
}
lines [ i ] . special = 0 ;
}
break ;
case 10 : //Culling plane
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2020-05-04 20:40:49 +00:00
case 20 : //PolyObject first line
{
2020-07-10 14:51:11 +00:00
INT32 check = - 1 ;
INT32 paramline = - 1 ;
2021-02-11 12:24:20 +00:00
TAG_ITER_LINES ( tag , check )
2020-07-10 14:51:11 +00:00
{
if ( lines [ check ] . special = = 22 )
{
paramline = check ;
break ;
}
}
2020-05-04 20:40:49 +00:00
//PolyObject ID
2020-07-10 14:51:11 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-05-04 20:40:49 +00:00
//Default: Invisible planes
lines [ i ] . args [ 3 ] | = TMPF_INVISIBLEPLANES ;
//Linedef executor tag
lines [ i ] . args [ 4 ] = 32000 + lines [ i ] . args [ 0 ] ;
if ( paramline = = - 1 )
break ; // no extra settings to apply, let's leave it
//Parent ID
lines [ i ] . args [ 1 ] = lines [ paramline ] . frontsector - > special ;
//Translucency
lines [ i ] . args [ 2 ] = ( lines [ paramline ] . flags & ML_DONTPEGTOP )
? ( sides [ lines [ paramline ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS )
: ( ( lines [ paramline ] . frontsector - > floorheight > > FRACBITS ) / 100 ) ;
//Flags
if ( lines [ paramline ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 3 ] | = TMPF_NOINSIDES ;
if ( lines [ paramline ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 3 ] | = TMPF_INTANGIBLE ;
if ( lines [ paramline ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 3 ] | = TMPF_PUSHABLESTOP ;
if ( lines [ paramline ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 3 ] & = ~ TMPF_INVISIBLEPLANES ;
/*if (lines[paramline].flags & ML_EFFECT5)
lines [ i ] . args [ 3 ] | = TMPF_DONTCLIPPLANES ; */
2020-06-09 07:44:49 +00:00
if ( lines [ paramline ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 3 ] | = TMPF_SPLAT ;
2020-05-04 20:40:49 +00:00
if ( lines [ paramline ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 3 ] | = TMPF_EXECUTOR ;
break ;
}
2021-07-04 12:10:11 +00:00
case 30 : //Polyobject - waving flag
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
break ;
2021-07-04 12:41:37 +00:00
case 31 : //Polyobject - displacement by front sector
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > FRACBITS ;
break ;
case 32 : //Polyobject - angular displacement by front sector
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset ? sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS : 128 ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset ? sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS : 90 ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 3 ] | = TMPR_DONTROTATEOTHERS ;
else if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 3 ] | = TMPR_ROTATEPLAYERS ;
break ;
2021-06-25 08:12:16 +00:00
case 50 : //Instantly lower floor on level load
case 51 : //Instantly raise ceiling on level load
lines [ i ] . args [ 0 ] = tag ;
break ;
2021-06-27 07:53:57 +00:00
case 52 : //Continuously falling sector
lines [ i ] . args [ 0 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2021-06-25 08:12:16 +00:00
case 53 : //Continuous floor/ceiling mover
case 54 : //Continuous floor mover
case 55 : //Continuous ceiling mover
lines [ i ] . args [ 0 ] = tag ;
2021-06-27 10:36:46 +00:00
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 53 ) ? TMP_BOTH : lines [ i ] . special - 54 ;
2021-06-26 08:23:12 +00:00
lines [ i ] . args [ 2 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 3 ] = lines [ i ] . args [ 2 ] ;
lines [ i ] . args [ 4 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 5 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
2021-06-25 09:11:16 +00:00
lines [ i ] . special = 53 ;
2021-06-25 08:12:16 +00:00
break ;
case 56 : //Continuous two-speed floor/ceiling mover
case 57 : //Continuous two-speed floor mover
case 58 : //Continuous two-speed ceiling mover
lines [ i ] . args [ 0 ] = tag ;
2021-06-27 10:36:46 +00:00
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 56 ) ? TMP_BOTH : lines [ i ] . special - 57 ;
2021-06-26 08:23:12 +00:00
lines [ i ] . args [ 2 ] = abs ( lines [ i ] . dx ) > > FRACBITS ;
lines [ i ] . args [ 3 ] = abs ( lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 4 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 5 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
2021-06-25 09:11:16 +00:00
lines [ i ] . special = 56 ;
2021-06-25 08:12:16 +00:00
break ;
case 59 : //Activate moving platform
case 60 : //Activate moving platform (adjustable speed)
lines [ i ] . args [ 0 ] = tag ;
2021-06-25 09:11:16 +00:00
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 60 ) ? P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS : 8 ;
2021-06-25 09:33:16 +00:00
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 4 ] = ( lines [ i ] . flags & ML_NOCLIMB ) ? 1 : 0 ;
2021-06-25 09:11:16 +00:00
lines [ i ] . special = 60 ;
2021-06-25 08:12:16 +00:00
break ;
case 61 : //Crusher (Ceiling to floor)
case 62 : //Crusher (Floor to ceiling)
lines [ i ] . args [ 0 ] = tag ;
2021-06-26 10:53:14 +00:00
lines [ i ] . args [ 1 ] = lines [ i ] . special - 61 ;
if ( lines [ i ] . flags & ML_EFFECT4 )
{
lines [ i ] . args [ 2 ] = abs ( lines [ i ] . dx ) > > FRACBITS ;
lines [ i ] . args [ 3 ] = lines [ i ] . args [ 2 ] ;
}
else
{
lines [ i ] . args [ 2 ] = R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > ( FRACBITS + 1 ) ;
lines [ i ] . args [ 3 ] = lines [ i ] . args [ 2 ] / 4 ;
}
lines [ i ] . special = 61 ;
2021-06-25 08:12:16 +00:00
break ;
2021-12-29 10:03:00 +00:00
case 63 : //Fake floor/ceiling planes
lines [ i ] . args [ 0 ] = tag ;
break ;
2021-06-27 07:53:57 +00:00
case 66 : //Move floor by displacement
case 67 : //Move ceiling by displacement
case 68 : //Move floor and ceiling by displacement
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = lines [ i ] . special - 66 ;
lines [ i ] . args [ 2 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . special = 66 ;
break ;
2020-05-03 10:44:30 +00:00
case 76 : //Make FOF bouncy
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-05-03 10:44:30 +00:00
lines [ i ] . args [ 1 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
break ;
2020-03-20 15:03:48 +00:00
case 100 : //FOF: solid, opaque, shadowcasting
case 101 : //FOF: solid, opaque, non-shadowcasting
case 102 : //FOF: solid, translucent
case 103 : //FOF: solid, sides only
case 104 : //FOF: solid, no sides
case 105 : //FOF: solid, invisible
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-03-20 15:03:48 +00:00
2020-06-12 14:45:18 +00:00
//Alpha
2020-03-20 15:03:48 +00:00
if ( lines [ i ] . special = = 102 )
{
2020-04-13 23:34:11 +00:00
if ( lines [ i ] . flags & ML_NOCLIMB )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 2 ] | = TMFA_INSIDES ;
2020-03-20 15:03:48 +00:00
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
2020-03-20 15:03:48 +00:00
else
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
2020-03-20 15:03:48 +00:00
}
2020-06-12 14:45:18 +00:00
else
lines [ i ] . args [ 1 ] = 255 ;
2020-03-20 15:03:48 +00:00
2020-06-12 14:45:18 +00:00
//Appearance
if ( lines [ i ] . special = = 105 )
2021-06-27 16:45:56 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOPLANES | TMFA_NOSIDES ;
2020-06-12 14:45:18 +00:00
else if ( lines [ i ] . special = = 104 )
2021-06-27 16:45:56 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOSIDES ;
2020-06-12 14:45:18 +00:00
else if ( lines [ i ] . special = = 103 )
2021-06-27 16:45:56 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOPLANES ;
2020-03-20 15:03:48 +00:00
if ( lines [ i ] . special ! = 100 & & ( lines [ i ] . special ! = 104 | | ! ( lines [ i ] . flags & ML_NOCLIMB ) ) )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOSHADE ;
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
//Tangibility
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 3 ] | = TMFT_DONTBLOCKOTHERS ;
if ( lines [ i ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 3 ] | = TMFT_DONTBLOCKPLAYER ;
2020-03-20 15:03:48 +00:00
2020-03-20 15:08:48 +00:00
lines [ i ] . special = 100 ;
break ;
2020-03-20 15:15:39 +00:00
case 120 : //FOF: water, opaque
case 121 : //FOF: water, translucent
case 122 : //FOF: water, opaque, no sides
case 123 : //FOF: water, translucent, no sides
case 124 : //FOF: goo water, translucent
case 125 : //FOF: goo water, translucent, no sides
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-03-20 15:15:39 +00:00
2020-06-12 07:00:06 +00:00
//Alpha
2020-03-20 15:15:39 +00:00
if ( lines [ i ] . special = = 120 | | lines [ i ] . special = = 122 )
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 1 ] = 255 ;
2020-03-20 15:15:39 +00:00
else
{
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
2020-03-20 15:15:39 +00:00
else
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 2 ] | = TMFW_SPLAT ;
2020-03-20 15:15:39 +00:00
}
//No sides?
if ( lines [ i ] . special = = 122 | | lines [ i ] . special = = 123 | | lines [ i ] . special = = 125 )
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 2 ] | = TMFW_NOSIDES ;
2020-03-20 15:15:39 +00:00
//Flags
if ( lines [ i ] . flags & ML_NOCLIMB )
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 2 ] | = TMFW_DOUBLESHADOW ;
2020-03-20 15:15:39 +00:00
if ( lines [ i ] . flags & ML_EFFECT4 )
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 2 ] | = TMFW_COLORMAPONLY ;
2020-03-20 15:15:39 +00:00
if ( ! ( lines [ i ] . flags & ML_EFFECT5 ) )
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 2 ] | = TMFW_NORIPPLE ;
2020-03-20 15:15:39 +00:00
//Goo?
if ( lines [ i ] . special > = 124 )
2020-06-12 07:00:06 +00:00
lines [ i ] . args [ 2 ] | = TMFW_GOOWATER ;
//Splat rendering?
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 2 ] | = TMFW_SPLAT ;
2020-03-20 15:15:39 +00:00
lines [ i ] . special = 120 ;
break ;
2020-03-20 15:08:48 +00:00
case 140 : //FOF: intangible from bottom, opaque
case 141 : //FOF: intangible from bottom, translucent
case 142 : //FOF: intangible from bottom, translucent, no sides
case 143 : //FOF: intangible from top, opaque
case 144 : //FOF: intangible from top, translucent
case 145 : //FOF: intangible from top, translucent, no sides
case 146 : //FOF: only tangible from sides
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-03-20 15:08:48 +00:00
2020-06-12 14:45:18 +00:00
//Alpha
if ( lines [ i ] . special = = 141 | | lines [ i ] . special = = 142 | | lines [ i ] . special = = 144 | | lines [ i ] . special = = 145 )
{
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 2 ] | = TMFA_INSIDES ;
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
else
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
2020-06-12 14:45:18 +00:00
}
else
lines [ i ] . args [ 1 ] = 255 ;
//Appearance
2020-03-20 15:08:48 +00:00
if ( lines [ i ] . special = = 142 | | lines [ i ] . special = = 145 )
2021-06-27 16:45:56 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOSIDES ;
2020-03-20 15:08:48 +00:00
else if ( lines [ i ] . special = = 146 )
2021-06-27 16:45:56 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOPLANES ;
2020-06-12 14:45:18 +00:00
if ( lines [ i ] . special ! = 146 & & ( lines [ i ] . flags & ML_NOCLIMB ) )
lines [ i ] . args [ 2 ] | = TMFA_NOSHADE ;
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
2020-03-20 15:08:48 +00:00
2020-04-13 23:34:11 +00:00
//Tangibility
if ( lines [ i ] . special < = 142 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 3 ] | = TMFT_INTANGIBLEBOTTOM ;
2020-04-13 23:34:11 +00:00
else if ( lines [ i ] . special < = 145 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 3 ] | = TMFT_INTANGIBLETOP ;
2020-04-13 23:34:11 +00:00
else
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 3 ] | = TMFT_INTANGIBLEBOTTOM | TMFT_INTANGIBLETOP ;
2020-04-13 23:34:11 +00:00
if ( lines [ i ] . flags & ML_EFFECT1 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 3 ] | = TMFT_DONTBLOCKOTHERS ;
2020-04-13 23:34:11 +00:00
if ( lines [ i ] . flags & ML_EFFECT2 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 3 ] | = TMFT_DONTBLOCKPLAYER ;
2020-03-20 15:08:48 +00:00
2020-03-20 15:03:48 +00:00
lines [ i ] . special = 100 ;
break ;
2020-04-27 08:29:29 +00:00
case 150 : //FOF: Air bobbing
case 151 : //FOF: Air bobbing (adjustable)
case 152 : //FOF: Reverse air bobbing (adjustable)
case 153 : //FOF: Dynamically sinking platform
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-06-12 15:48:43 +00:00
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 150 ) ? 16 : ( P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ) ;
2020-04-27 08:58:38 +00:00
//Flags
2020-04-27 08:29:29 +00:00
if ( lines [ i ] . special = = 152 )
2020-06-12 15:48:43 +00:00
lines [ i ] . args [ 2 ] | = TMFB_REVERSE ;
2020-04-27 08:29:29 +00:00
if ( lines [ i ] . flags & ML_NOCLIMB )
2020-06-12 15:48:43 +00:00
lines [ i ] . args [ 2 ] | = TMFB_SPINDASH ;
2020-04-27 08:29:29 +00:00
if ( lines [ i ] . special = = 153 )
2020-06-12 15:48:43 +00:00
lines [ i ] . args [ 2 ] | = TMFB_DYNAMIC ;
2020-04-27 08:58:38 +00:00
2020-04-27 08:29:29 +00:00
lines [ i ] . special = 150 ;
break ;
2020-04-27 09:05:27 +00:00
case 160 : //FOF: Water bobbing
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-27 09:05:27 +00:00
break ;
2020-04-15 07:44:33 +00:00
case 170 : //FOF: Crumbling, respawn
case 171 : //FOF: Crumbling, no respawn
case 172 : //FOF: Crumbling, respawn, intangible from bottom
case 173 : //FOF: Crumbling, no respawn, intangible from bottom
case 174 : //FOF: Crumbling, respawn, intangible from bottom, translucent
case 175 : //FOF: Crumbling, no respawn, intangible from bottom, translucent
case 176 : //FOF: Crumbling, respawn, floating, bobbing
case 177 : //FOF: Crumbling, no respawn, floating, bobbing
case 178 : //FOF: Crumbling, respawn, floating
case 179 : //FOF: Crumbling, no respawn, floating
case 180 : //FOF: Crumbling, respawn, air bobbing
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-06-12 07:28:41 +00:00
//Alpha
2020-04-15 07:44:33 +00:00
if ( lines [ i ] . special > = 174 & & lines [ i ] . special < = 175 )
2020-04-15 07:49:00 +00:00
{
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
2020-06-12 07:28:41 +00:00
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
2020-04-15 07:49:00 +00:00
else
2020-06-12 07:28:41 +00:00
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 3 ] | = TMFC_SPLAT ;
2020-04-15 07:49:00 +00:00
}
2020-06-12 07:28:41 +00:00
else
lines [ i ] . args [ 1 ] = 255 ;
if ( lines [ i ] . special > = 172 & & lines [ i ] . special < = 175 )
{
lines [ i ] . args [ 2 ] | = TMFT_INTANGIBLEBOTTOM ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 3 ] | = TMFC_NOSHADE ;
}
2020-04-15 07:44:33 +00:00
if ( lines [ i ] . special % 2 = = 1 )
2020-06-12 07:28:41 +00:00
lines [ i ] . args [ 3 ] | = TMFC_NORETURN ;
2020-04-15 07:44:33 +00:00
if ( lines [ i ] . special = = 176 | | lines [ i ] . special = = 177 | | lines [ i ] . special = = 180 )
2020-06-12 07:28:41 +00:00
lines [ i ] . args [ 3 ] | = TMFC_AIRBOB ;
2020-04-15 07:44:33 +00:00
if ( lines [ i ] . special > = 176 & & lines [ i ] . special < = 179 )
2020-06-12 07:28:41 +00:00
lines [ i ] . args [ 3 ] | = TMFC_FLOATBOB ;
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 3 ] | = TMFC_SPLAT ;
2020-05-02 08:40:35 +00:00
if ( lines [ i ] . flags & ML_EFFECT1 )
2020-06-12 07:28:41 +00:00
lines [ i ] . args [ 2 ] | = TMFT_DONTBLOCKOTHERS ;
2020-05-02 08:40:35 +00:00
if ( lines [ i ] . flags & ML_EFFECT2 )
2020-06-12 07:28:41 +00:00
lines [ i ] . args [ 2 ] | = TMFT_DONTBLOCKPLAYER ;
2020-05-02 08:40:35 +00:00
2020-04-15 07:44:33 +00:00
lines [ i ] . special = 170 ;
break ;
2020-04-27 09:52:31 +00:00
case 190 : // FOF: Rising, solid, opaque, shadowcasting
case 191 : // FOF: Rising, solid, opaque, non-shadowcasting
case 192 : // FOF: Rising, solid, translucent
case 193 : // FOF: Rising, solid, invisible
case 194 : // FOF: Rising, intangible from bottom, opaque
case 195 : // FOF: Rising, intangible from bottom, translucent
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-27 09:52:31 +00:00
//Translucency
if ( lines [ i ] . special = = 192 | | lines [ i ] . special = = 195 )
{
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
2020-04-27 09:52:31 +00:00
else
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
2020-04-27 09:52:31 +00:00
}
2020-06-12 14:45:18 +00:00
else
lines [ i ] . args [ 1 ] = 255 ;
2020-04-27 09:52:31 +00:00
2020-06-12 14:45:18 +00:00
//Appearance
if ( lines [ i ] . special = = 193 )
2021-06-27 16:45:56 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOPLANES | TMFA_NOSIDES ;
2020-06-12 14:45:18 +00:00
if ( lines [ i ] . special > = 194 )
2021-06-27 16:45:56 +00:00
lines [ i ] . args [ 2 ] | = TMFA_INSIDES ;
2020-04-27 09:52:31 +00:00
if ( lines [ i ] . special ! = 190 & & ( lines [ i ] . special < = 193 | | lines [ i ] . flags & ML_NOCLIMB ) )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOSHADE ;
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
//Tangibility
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 3 ] | = TMFT_DONTBLOCKOTHERS ;
if ( lines [ i ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 3 ] | = TMFT_DONTBLOCKPLAYER ;
if ( lines [ i ] . special > = 194 )
lines [ i ] . args [ 3 ] | = TMFT_INTANGIBLEBOTTOM ;
2020-04-27 09:52:31 +00:00
//Speed
2020-04-27 09:56:29 +00:00
lines [ i ] . args [ 4 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
2020-04-27 09:52:31 +00:00
//Flags
if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 5 ] | = TMFR_REVERSE ;
if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 5 ] | = TMFR_SPINDASH ;
lines [ i ] . special = 190 ;
break ;
2020-04-14 07:03:00 +00:00
case 200 : //FOF: Light block
case 201 : //FOF: Half light block
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-14 07:03:00 +00:00
if ( lines [ i ] . special = = 201 )
lines [ i ] . args [ 1 ] = 1 ;
lines [ i ] . special = 200 ;
break ;
2020-04-14 07:06:02 +00:00
case 202 : //FOF: Fog block
case 223 : //FOF: Intangible, invisible
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-14 07:06:02 +00:00
break ;
2020-04-14 08:13:38 +00:00
case 220 : //FOF: Intangible, opaque
case 221 : //FOF: Intangible, translucent
case 222 : //FOF: Intangible, sides only
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-14 08:13:38 +00:00
2020-06-12 14:45:18 +00:00
//Alpha
2020-04-14 08:13:38 +00:00
if ( lines [ i ] . special = = 221 )
{
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
2020-04-14 08:13:38 +00:00
else
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
2020-04-14 08:13:38 +00:00
}
2020-06-12 14:45:18 +00:00
else
lines [ i ] . args [ 1 ] = 255 ;
//Appearance
if ( lines [ i ] . special = = 222 )
lines [ i ] . args [ 2 ] | = TMFA_NOPLANES ;
2021-09-17 07:57:53 +00:00
if ( lines [ i ] . special = = 221 )
2020-06-12 14:45:18 +00:00
lines [ i ] . args [ 2 ] | = TMFA_INSIDES ;
2020-04-14 08:13:38 +00:00
if ( lines [ i ] . special ! = 220 & & ! ( lines [ i ] . flags & ML_NOCLIMB ) )
2020-04-18 16:02:43 +00:00
lines [ i ] . args [ 2 ] | = TMFA_NOSHADE ;
2020-06-12 14:45:18 +00:00
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 2 ] | = TMFA_SPLAT ;
2020-04-14 08:13:38 +00:00
lines [ i ] . special = 220 ;
break ;
2020-04-14 07:14:10 +00:00
case 250 : //FOF: Mario block
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-18 16:02:43 +00:00
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 1 ] | = TMFM_BRICK ;
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 1 ] | = TMFM_INVISIBLE ;
2020-04-14 07:14:10 +00:00
break ;
2020-04-14 07:43:49 +00:00
case 251 : //FOF: Thwomp block
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-14 07:43:49 +00:00
if ( lines [ i ] . flags & ML_EFFECT5 ) //Custom speeds
{
lines [ i ] . args [ 1 ] = lines [ i ] . dy > > FRACBITS ;
lines [ i ] . args [ 2 ] = lines [ i ] . dx > > FRACBITS ;
}
else
{
lines [ i ] . args [ 1 ] = 80 ;
lines [ i ] . args [ 2 ] = 16 ;
}
if ( lines [ i ] . flags & ML_EFFECT4 )
2021-12-14 18:08:59 +00:00
P_WriteConstant ( sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS , & lines [ i ] . stringargs [ 0 ] ) ;
2020-04-14 07:43:49 +00:00
break ;
2020-04-14 09:45:37 +00:00
case 252 : //FOF: Shatter block
case 253 : //FOF: Shatter block, translucent
case 254 : //FOF: Bustable block
case 255 : //FOF: Spin-bustable block
case 256 : //FOF: Spin-bustable block, translucent
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-14 09:45:37 +00:00
2020-06-12 08:31:26 +00:00
//Alpha
2020-04-14 09:45:37 +00:00
if ( lines [ i ] . special = = 253 | | lines [ i ] . special = = 256 )
{
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
2020-06-12 08:31:26 +00:00
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
2020-04-14 09:45:37 +00:00
else
2020-06-12 08:31:26 +00:00
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 3 ] | = TMFB_SPLAT ;
2020-04-14 09:45:37 +00:00
}
2020-06-12 08:31:26 +00:00
else
lines [ i ] . args [ 1 ] = 255 ;
2020-04-14 09:45:37 +00:00
2020-06-12 08:31:26 +00:00
//Bustable type
if ( lines [ i ] . special < = 253 )
lines [ i ] . args [ 2 ] = TMFB_TOUCH ;
else if ( lines [ i ] . special > = 255 )
lines [ i ] . args [ 2 ] = TMFB_SPIN ;
else if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 2 ] = TMFB_STRONG ;
else
lines [ i ] . args [ 2 ] = TMFB_REGULAR ;
//Flags
2020-04-14 09:45:37 +00:00
if ( lines [ i ] . flags & ML_EFFECT4 )
2020-04-18 16:02:43 +00:00
lines [ i ] . args [ 3 ] | = TMFB_PUSHABLES ;
2020-04-14 09:45:37 +00:00
if ( lines [ i ] . flags & ML_EFFECT5 )
{
2020-04-18 16:02:43 +00:00
lines [ i ] . args [ 3 ] | = TMFB_EXECUTOR ;
2020-04-14 09:45:37 +00:00
lines [ i ] . args [ 4 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
}
if ( lines [ i ] . special = = 252 & & lines [ i ] . flags & ML_NOCLIMB )
2020-06-12 08:31:26 +00:00
lines [ i ] . args [ 3 ] | = TMFB_ONLYBOTTOM ;
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 3 ] | = TMFB_SPLAT ;
2020-04-14 09:45:37 +00:00
lines [ i ] . special = 254 ;
break ;
2020-04-14 09:56:11 +00:00
case 257 : //FOF: Quicksand
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-04-14 09:56:11 +00:00
if ( ! ( lines [ i ] . flags & ML_EFFECT5 ) )
2020-06-12 16:22:16 +00:00
lines [ i ] . args [ 1 ] = 1 ; //No ripple effect
lines [ i ] . args [ 2 ] = lines [ i ] . dx > > FRACBITS ; //Sinking speed
lines [ i ] . args [ 3 ] = lines [ i ] . dy > > FRACBITS ; //Friction
2020-04-14 09:56:11 +00:00
break ;
2020-04-14 07:51:48 +00:00
case 258 : //FOF: Laser
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-06-12 08:17:52 +00:00
//Alpha
2020-06-12 08:03:27 +00:00
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
else
lines [ i ] . args [ 1 ] = 128 ;
2020-06-12 08:17:52 +00:00
//Flags
2020-04-14 07:51:48 +00:00
if ( lines [ i ] . flags & ML_EFFECT1 )
2020-06-12 08:17:52 +00:00
lines [ i ] . args [ 2 ] = TMFL_NOBOSSES ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . flags & ML_EFFECT6 | | lines [ i ] . args [ 1 ] = = 256 )
2020-06-12 08:17:52 +00:00
lines [ i ] . args [ 2 ] = TMFL_SPLAT ;
2020-04-14 07:51:48 +00:00
break ;
2020-05-02 21:00:22 +00:00
case 259 : //Custom FOF
if ( lines [ i ] . sidenum [ 1 ] = = 0xffff )
2020-11-13 12:23:14 +00:00
I_Error ( " Custom FOF (tag %d) found without a linedef back side! " , tag ) ;
2020-05-02 21:00:22 +00:00
2020-11-13 12:23:14 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-06-12 07:57:56 +00:00
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 1 ] ] . toptexture ;
if ( lines [ i ] . flags & ML_EFFECT6 )
lines [ i ] . args [ 2 ] | = FF_SPLAT ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 1 ] ] . midtexture ;
if ( lines [ i ] . args [ 2 ] & FF_TRANSLUCENT )
2020-05-02 21:00:22 +00:00
{
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture > 0 )
2020-06-12 07:57:56 +00:00
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . toptexture ;
2020-05-02 21:00:22 +00:00
else
2020-06-12 07:57:56 +00:00
lines [ i ] . args [ 1 ] = 128 ;
2021-06-27 16:45:56 +00:00
//Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels
if ( lines [ i ] . args [ 1 ] = = 256 )
lines [ i ] . args [ 2 ] | = FF_SPLAT ;
2020-05-02 21:00:22 +00:00
}
2020-06-12 07:57:56 +00:00
else
lines [ i ] . args [ 1 ] = 255 ;
2020-05-02 21:00:22 +00:00
break ;
2021-12-09 06:30:55 +00:00
case 300 : //Trigger linedef executor - Continuous
case 301 : //Trigger linedef executor - Each time
case 302 : //Trigger linedef executor - Once
2021-12-09 18:17:16 +00:00
if ( lines [ i ] . special = = 302 )
lines [ i ] . args [ 0 ] = TMT_ONCE ;
else if ( lines [ i ] . special = = 301 )
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMT_CONTINUOUS ;
2021-12-09 06:30:55 +00:00
lines [ i ] . special = 300 ;
break ;
2021-12-09 06:47:01 +00:00
case 303 : //Ring count - Continuous
case 304 : //Ring count - Once
lines [ i ] . args [ 0 ] = ( lines [ i ] . special = = 304 ) ? TMT_ONCE : TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 2 ] = TMC_LTE ;
else if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 2 ] = TMC_GTE ;
else
lines [ i ] . args [ 2 ] = TMC_EQUAL ;
lines [ i ] . args [ 3 ] = ! ! ( lines [ i ] . flags & ML_EFFECT4 ) ;
lines [ i ] . special = 303 ;
break ;
2021-12-09 18:17:16 +00:00
case 305 : //Character ability - Continuous
case 306 : //Character ability - Each time
case 307 : //Character ability - Once
if ( lines [ i ] . special = = 307 )
lines [ i ] . args [ 0 ] = TMT_ONCE ;
else if ( lines [ i ] . special = = 306 )
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = ( P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ) / 10 ;
lines [ i ] . special = 305 ;
break ;
2021-12-09 17:56:50 +00:00
case 308 : //Race only - once
lines [ i ] . args [ 0 ] = TMT_ONCE ;
lines [ i ] . args [ 1 ] = GTR_RACE ;
2021-12-09 19:37:39 +00:00
lines [ i ] . args [ 2 ] = TMF_HASANY ;
2021-12-09 17:56:50 +00:00
break ;
2021-12-09 07:49:50 +00:00
case 309 : //CTF red team - continuous
case 310 : //CTF red team - each time
case 311 : //CTF blue team - continuous
case 312 : //CTF blue team - each time
2021-12-09 15:10:39 +00:00
if ( lines [ i ] . special % 2 = = 0 )
2021-12-09 07:49:50 +00:00
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = ( lines [ i ] . special > 310 ) ? TMT_BLUE : TMT_RED ;
lines [ i ] . special = 309 ;
break ;
2021-09-26 18:42:01 +00:00
case 313 : //No more enemies - once
lines [ i ] . args [ 0 ] = tag ;
break ;
2021-12-09 06:56:15 +00:00
case 314 : //Number of pushables - Continuous
case 315 : //Number of pushables - Once
lines [ i ] . args [ 0 ] = ( lines [ i ] . special = = 315 ) ? TMT_ONCE : TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 2 ] = TMC_GTE ;
else if ( lines [ i ] . flags & ML_EFFECT4 )
2021-12-09 19:57:44 +00:00
lines [ i ] . args [ 2 ] = TMC_LTE ;
2021-12-09 06:56:15 +00:00
else
lines [ i ] . args [ 2 ] = TMC_EQUAL ;
lines [ i ] . special = 314 ;
break ;
2021-12-09 07:08:04 +00:00
case 317 : //Condition set trigger - Continuous
case 318 : //Condition set trigger - Once
lines [ i ] . args [ 0 ] = ( lines [ i ] . special = = 318 ) ? TMT_ONCE : TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . special = 317 ;
break ;
case 319 : //Unlockable trigger - Continuous
case 320 : //Unlockable trigger - Once
lines [ i ] . args [ 0 ] = ( lines [ i ] . special = = 320 ) ? TMT_ONCE : TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . special = 319 ;
break ;
2021-12-09 17:15:27 +00:00
case 321 : //Trigger after X calls - Continuous
case 322 : //Trigger after X calls - Each time
if ( lines [ i ] . special % 2 = = 0 )
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMXT_EACHTIMEENTERANDEXIT : TMXT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMXT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
{
lines [ i ] . args [ 2 ] = 1 ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
}
else
lines [ i ] . args [ 2 ] = lines [ i ] . args [ 3 ] = 0 ;
lines [ i ] . special = 321 ;
break ;
2021-09-23 08:21:53 +00:00
case 323 : //NiGHTSerize - Each time
case 324 : //NiGHTSerize - Once
case 325 : //DeNiGHTSerize - Each time
case 326 : //DeNiGHTSerize - Once
case 327 : //NiGHTS lap - Each time
case 328 : //NiGHTS lap - Once
case 329 : //Ideya capture touch - Each time
case 330 : //Ideya capture touch - Once
lines [ i ] . args [ 0 ] = ( lines [ i ] . special + 1 ) % 2 ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 3 ] = TMC_LTE ;
else if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 3 ] = TMC_GTE ;
else
lines [ i ] . args [ 3 ] = TMC_EQUAL ;
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 4 ] = TMC_LTE ;
else if ( lines [ i ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 4 ] = TMC_GTE ;
else
lines [ i ] . args [ 4 ] = TMC_EQUAL ;
if ( lines [ i ] . flags & ML_DONTPEGBOTTOM )
lines [ i ] . args [ 5 ] = TMNP_SLOWEST ;
else if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 5 ] = TMNP_TRIGGERER ;
else
lines [ i ] . args [ 5 ] = TMNP_FASTEST ;
if ( lines [ i ] . special % 2 = = 0 )
lines [ i ] . special - - ;
if ( lines [ i ] . special = = 323 )
{
if ( lines [ i ] . flags & ML_TFERLINE )
lines [ i ] . args [ 6 ] = TMN_FROMNONIGHTS ;
else if ( lines [ i ] . flags & ML_DONTPEGTOP )
lines [ i ] . args [ 6 ] = TMN_FROMNIGHTS ;
else
lines [ i ] . args [ 6 ] = TMN_ALWAYS ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 7 ] | = TMN_BONUSLAPS ;
if ( lines [ i ] . flags & ML_BOUNCY )
lines [ i ] . args [ 7 ] | = TMN_LEVELCOMPLETION ;
}
else if ( lines [ i ] . special = = 325 )
{
if ( lines [ i ] . flags & ML_TFERLINE )
lines [ i ] . args [ 6 ] = TMD_NOBODYNIGHTS ;
else if ( lines [ i ] . flags & ML_DONTPEGTOP )
lines [ i ] . args [ 6 ] = TMD_SOMEBODYNIGHTS ;
else
lines [ i ] . args [ 6 ] = TMD_ALWAYS ;
lines [ i ] . args [ 7 ] = ! ! ( lines [ i ] . flags & ML_EFFECT3 ) ;
}
else if ( lines [ i ] . special = = 327 )
lines [ i ] . args [ 6 ] = ! ! ( lines [ i ] . flags & ML_EFFECT3 ) ;
else
{
if ( lines [ i ] . flags & ML_DONTPEGTOP )
lines [ i ] . args [ 6 ] = TMS_ALWAYS ;
else if ( lines [ i ] . flags & ML_BOUNCY )
lines [ i ] . args [ 6 ] = TMS_IFNOTENOUGH ;
else
lines [ i ] . args [ 6 ] = TMS_IFENOUGH ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 7 ] | = TMI_BONUSLAPS ;
if ( lines [ i ] . flags & ML_TFERLINE )
lines [ i ] . args [ 7 ] | = TMI_ENTER ;
}
break ;
2021-12-09 18:33:02 +00:00
case 331 : // Player skin - continuous
case 332 : // Player skin - each time
case 333 : // Player skin - once
if ( lines [ i ] . special = = 303 )
lines [ i ] . args [ 0 ] = TMT_ONCE ;
else if ( lines [ i ] . special = = 302 )
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
if ( lines [ i ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( lines [ i ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , lines [ i ] . text , strlen ( lines [ i ] . text ) + 1 ) ;
}
lines [ i ] . special = 331 ;
break ;
2021-12-09 18:49:17 +00:00
case 334 : // Object dye - continuous
case 335 : // Object dye - each time
case 336 : // Object dye - once
if ( lines [ i ] . special = = 336 )
lines [ i ] . args [ 0 ] = TMT_ONCE ;
else if ( lines [ i ] . special = = 335 )
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
lines [ i ] . special = 334 ;
break ;
2021-12-09 19:37:39 +00:00
case 337 : //Emerald check - continuous
case 338 : //Emerald check - each time
case 339 : //Emerald check - once
if ( lines [ i ] . special = = 339 )
lines [ i ] . args [ 0 ] = TMT_ONCE ;
else if ( lines [ i ] . special = = 338 )
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = EMERALD1 | EMERALD2 | EMERALD3 | EMERALD4 | EMERALD5 | EMERALD6 | EMERALD7 ;
lines [ i ] . args [ 2 ] = TMF_HASALL ;
lines [ i ] . special = 337 ;
break ;
2021-12-09 19:57:44 +00:00
case 340 : //NiGHTS mare - continuous
case 341 : //NiGHTS mare - each time
case 342 : //NiGHTS mare - once
if ( lines [ i ] . special = = 342 )
lines [ i ] . args [ 0 ] = TMT_ONCE ;
else if ( lines [ i ] . special = = 341 )
lines [ i ] . args [ 0 ] = ( lines [ i ] . flags & ML_BOUNCY ) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER ;
else
lines [ i ] . args [ 0 ] = TMT_CONTINUOUS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 2 ] = TMC_LTE ;
else if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 2 ] = TMC_GTE ;
else
lines [ i ] . args [ 2 ] = TMC_EQUAL ;
lines [ i ] . special = 340 ;
break ;
2021-06-25 08:12:16 +00:00
case 400 : //Set tagged sector's floor height/texture
case 401 : //Set tagged sector's ceiling height/texture
lines [ i ] . args [ 0 ] = tag ;
2021-06-27 10:21:26 +00:00
lines [ i ] . args [ 1 ] = lines [ i ] . special - 400 ;
2021-09-21 09:35:04 +00:00
lines [ i ] . args [ 2 ] = ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
2021-06-25 16:34:56 +00:00
lines [ i ] . special = 400 ;
2021-06-25 08:12:16 +00:00
break ;
2021-09-19 12:23:04 +00:00
case 402 : //Copy light level
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = 0 ;
break ;
2021-06-25 08:12:16 +00:00
case 403 : //Move tagged sector's floor
case 404 : //Move tagged sector's ceiling
lines [ i ] . args [ 0 ] = tag ;
2021-06-26 06:31:59 +00:00
lines [ i ] . args [ 1 ] = lines [ i ] . special - 403 ;
lines [ i ] . args [ 2 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
2021-06-26 13:28:28 +00:00
lines [ i ] . args [ 3 ] = ( lines [ i ] . flags & ML_BLOCKMONSTERS ) ? sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS : 0 ;
lines [ i ] . args [ 4 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
2021-06-26 06:31:59 +00:00
lines [ i ] . special = 403 ;
2021-06-25 08:12:16 +00:00
break ;
case 405 : //Move floor according to front texture offsets
case 407 : //Move ceiling according to front texture offsets
lines [ i ] . args [ 0 ] = tag ;
2021-06-27 10:36:46 +00:00
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 405 ) ? TMP_FLOOR : TMP_CEILING ;
2021-06-26 06:43:35 +00:00
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 4 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
lines [ i ] . special = 405 ;
2021-06-25 08:12:16 +00:00
break ;
2021-06-27 09:56:06 +00:00
case 408 : //Set flats
lines [ i ] . args [ 0 ] = tag ;
if ( ( lines [ i ] . flags & ( ML_NOCLIMB | ML_EFFECT4 ) ) = = ( ML_NOCLIMB | ML_EFFECT4 ) )
{
CONS_Alert ( CONS_WARNING , M_GetText ( " Set flats linedef (tag %d) doesn't have anything to do. \n Consider changing the linedef's flag configuration or removing it entirely. \n " ) , tag ) ;
lines [ i ] . special = 0 ;
}
else if ( lines [ i ] . flags & ML_NOCLIMB )
2021-06-27 10:36:46 +00:00
lines [ i ] . args [ 1 ] = TMP_CEILING ;
2021-06-27 09:56:06 +00:00
else if ( lines [ i ] . flags & ML_EFFECT4 )
2021-06-27 10:36:46 +00:00
lines [ i ] . args [ 1 ] = TMP_FLOOR ;
2021-06-27 09:56:06 +00:00
else
2021-06-27 10:36:46 +00:00
lines [ i ] . args [ 1 ] = TMP_BOTH ;
2021-06-27 09:56:06 +00:00
break ;
2021-09-21 09:30:34 +00:00
case 409 : //Change tagged sector's tag
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 2 ] = TMT_ADD ;
else if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 2 ] = TMT_REMOVE ;
else
lines [ i ] . args [ 2 ] = TMT_REPLACEFIRST ;
break ;
case 410 : //Change front sector's tag
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 1 ] = TMT_ADD ;
else if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 1 ] = TMT_REMOVE ;
else
lines [ i ] . args [ 1 ] = TMT_REPLACEFIRST ;
break ;
2021-06-27 07:53:57 +00:00
case 411 : //Stop plane movement
lines [ i ] . args [ 0 ] = tag ;
break ;
2021-09-21 13:31:53 +00:00
case 412 : //Teleporter
lines [ i ] . args [ 0 ] = tag ;
if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 1 ] | = TMT_SILENT ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 1 ] | = TMT_KEEPANGLE ;
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 1 ] | = TMT_KEEPMOMENTUM ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 1 ] | = TMT_RELATIVE ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 4 ] = lines [ i ] . frontsector - > ceilingheight > > FRACBITS ;
break ;
2021-09-22 06:57:48 +00:00
case 413 : //Change music
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 0 ] | = TMM_ALLPLAYERS ;
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 0 ] | = TMM_OFFSET ;
if ( lines [ i ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 0 ] | = TMM_FADE ;
if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 0 ] | = TMM_NORELOAD ;
if ( lines [ i ] . flags & ML_BOUNCY )
lines [ i ] . args [ 0 ] | = TMM_FORCERESET ;
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 0 ] | = TMM_NOLOOP ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . midtexture ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 4 ] = ( lines [ i ] . sidenum [ 1 ] ! = 0xffff ) ? sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS : 0 ;
lines [ i ] . args [ 5 ] = ( lines [ i ] . sidenum [ 1 ] ! = 0xffff ) ? sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS : - 1 ;
lines [ i ] . args [ 6 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . bottomtexture ;
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
break ;
2021-09-21 08:14:55 +00:00
case 414 : //Play sound effect
lines [ i ] . args [ 2 ] = tag ;
if ( tag ! = 0 )
{
if ( lines [ i ] . flags & ML_EFFECT5 )
{
lines [ i ] . args [ 0 ] = TMSS_TAGGEDSECTOR ;
lines [ i ] . args [ 1 ] = TMSL_EVERYONE ;
}
else
{
lines [ i ] . args [ 0 ] = TMSS_NOWHERE ;
lines [ i ] . args [ 1 ] = TMSL_TAGGEDSECTOR ;
}
}
else
{
if ( lines [ i ] . flags & ML_NOCLIMB )
{
lines [ i ] . args [ 0 ] = TMSS_NOWHERE ;
lines [ i ] . args [ 1 ] = TMSL_TRIGGERER ;
}
else if ( lines [ i ] . flags & ML_EFFECT4 )
{
lines [ i ] . args [ 0 ] = TMSS_NOWHERE ;
lines [ i ] . args [ 1 ] = TMSL_EVERYONE ;
}
else if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
{
lines [ i ] . args [ 0 ] = TMSS_TRIGGERSECTOR ;
lines [ i ] . args [ 1 ] = TMSL_EVERYONE ;
}
else
{
lines [ i ] . args [ 0 ] = TMSS_TRIGGERMOBJ ;
lines [ i ] . args [ 1 ] = TMSL_EVERYONE ;
}
}
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
break ;
2021-09-20 10:32:01 +00:00
case 415 : //Run script
{
INT32 scrnum ;
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( 9 , PU_LEVEL , NULL ) ;
strcpy ( lines [ i ] . stringargs [ 0 ] , G_BuildMapName ( gamemap ) ) ;
lines [ i ] . stringargs [ 0 ] [ 0 ] = ' S ' ;
lines [ i ] . stringargs [ 0 ] [ 1 ] = ' C ' ;
lines [ i ] . stringargs [ 0 ] [ 2 ] = ' R ' ;
scrnum = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
if ( scrnum < 0 | | scrnum > 999 )
{
scrnum = 0 ;
lines [ i ] . stringargs [ 0 ] [ 5 ] = lines [ i ] . stringargs [ 0 ] [ 6 ] = lines [ i ] . stringargs [ 0 ] [ 7 ] = ' 0 ' ;
}
else
{
lines [ i ] . stringargs [ 0 ] [ 5 ] = ( char ) ( ' 0 ' + ( char ) ( ( scrnum / 100 ) ) ) ;
lines [ i ] . stringargs [ 0 ] [ 6 ] = ( char ) ( ' 0 ' + ( char ) ( ( scrnum % 100 ) / 10 ) ) ;
lines [ i ] . stringargs [ 0 ] [ 7 ] = ( char ) ( ' 0 ' + ( char ) ( scrnum % 10 ) ) ;
}
lines [ i ] . stringargs [ 0 ] [ 8 ] = ' \0 ' ;
break ;
}
2021-09-19 15:07:08 +00:00
case 416 : //Start adjustable flickering light
case 417 : //Start adjustable pulsating light
case 602 : //Adjustable pulsating light
case 603 : //Adjustable flickering light
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 2 ] = lines [ i ] . frontsector - > lightlevel ;
if ( ( lines [ i ] . flags & ML_NOCLIMB ) & & lines [ i ] . backsector )
lines [ i ] . args [ 4 ] = lines [ i ] . backsector - > lightlevel ;
else
lines [ i ] . args [ 3 ] = 1 ;
break ;
case 418 : //Start adjustable blinking light (unsynchronized)
case 419 : //Start adjustable blinking light (synchronized)
case 604 : //Adjustable blinking light (unsynchronized)
case 605 : //Adjustable blinking light (synchronized)
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = abs ( lines [ i ] . dx ) > > FRACBITS ;
lines [ i ] . args [ 2 ] = abs ( lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 3 ] = lines [ i ] . frontsector - > lightlevel ;
if ( ( lines [ i ] . flags & ML_NOCLIMB ) & & lines [ i ] . backsector )
lines [ i ] . args [ 5 ] = lines [ i ] . backsector - > lightlevel ;
else
lines [ i ] . args [ 4 ] | = TMB_USETARGET ;
if ( lines [ i ] . special % 2 = = 1 )
{
lines [ i ] . args [ 4 ] | = TMB_SYNC ;
lines [ i ] . special - - ;
}
break ;
2021-09-19 12:23:04 +00:00
case 420 : //Fade light level
lines [ i ] . args [ 0 ] = tag ;
if ( lines [ i ] . flags & ML_DONTPEGBOTTOM )
{
lines [ i ] . args [ 1 ] = max ( sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS , 0 ) ;
// failsafe: if user specifies Back Y Offset and NOT Front Y Offset, use the Back Offset
// to be consistent with other light and fade specials
lines [ i ] . args [ 2 ] = ( ( lines [ i ] . sidenum [ 1 ] ! = 0xFFFF & & ! ( sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ) ) ?
max ( min ( sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS , 255 ) , 0 )
: max ( min ( sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS , 255 ) , 0 ) ) ;
}
else
{
lines [ i ] . args [ 1 ] = lines [ i ] . frontsector - > lightlevel ;
lines [ i ] . args [ 2 ] = abs ( P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) ) > > FRACBITS ;
}
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 3 ] | = TMF_TICBASED ;
if ( lines [ i ] . flags & ML_EFFECT5 )
2021-09-19 21:12:30 +00:00
lines [ i ] . args [ 3 ] | = TMF_OVERRIDE ;
2021-09-19 12:23:04 +00:00
break ;
case 421 : //Stop lighting effect
lines [ i ] . args [ 0 ] = tag ;
break ;
2021-09-21 12:59:58 +00:00
case 422 : //Switch to cut-away view
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 2 ] = ( lines [ i ] . flags & ML_NOCLIMB ) ? sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS : 0 ;
break ;
2021-09-20 10:42:31 +00:00
case 423 : //Change sky
case 424 : //Change weather
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2021-09-21 05:36:54 +00:00
case 425 : //Change object state
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
break ;
2021-09-20 11:31:32 +00:00
case 426 : //Stop object
lines [ i ] . args [ 0 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
case 427 : //Award score
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
break ;
2021-06-25 08:12:16 +00:00
case 428 : //Start platform movement
lines [ i ] . args [ 0 ] = tag ;
2021-06-25 09:11:16 +00:00
lines [ i ] . args [ 1 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
2021-06-25 09:33:16 +00:00
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 4 ] = ( lines [ i ] . flags & ML_NOCLIMB ) ? 1 : 0 ;
2021-06-25 08:12:16 +00:00
break ;
case 429 : //Crush ceiling once
case 430 : //Crush floor once
case 431 : //Crush floor and ceiling once
lines [ i ] . args [ 0 ] = tag ;
2021-06-27 10:36:46 +00:00
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 429 ) ? TMP_CEILING : ( ( lines [ i ] . special = = 430 ) ? TMP_FLOOR : TMP_BOTH ) ;
2021-06-26 10:53:14 +00:00
if ( lines [ i ] . special = = 430 | | lines [ i ] . flags & ML_EFFECT4 )
{
lines [ i ] . args [ 2 ] = abs ( lines [ i ] . dx ) > > FRACBITS ;
lines [ i ] . args [ 3 ] = lines [ i ] . args [ 2 ] ;
}
else
{
lines [ i ] . args [ 2 ] = R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > ( FRACBITS + 1 ) ;
lines [ i ] . args [ 3 ] = lines [ i ] . args [ 2 ] / 4 ;
}
lines [ i ] . special = 429 ;
2021-06-25 08:12:16 +00:00
break ;
2021-09-20 11:31:32 +00:00
case 432 : //Enable/disable 2D mode
lines [ i ] . args [ 0 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
case 433 : //Enable/disable gravity flip
lines [ i ] . args [ 0 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2021-09-21 06:34:55 +00:00
case 434 : //Award power-up
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
if ( lines [ i ] . sidenum [ 1 ] ! = 0xffff & & lines [ i ] . flags & ML_BLOCKMONSTERS ) // read power from back sidedef
{
lines [ i ] . stringargs [ 1 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 1 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 1 ] , sides [ lines [ i ] . sidenum [ 1 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 1 ] ] . text ) + 1 ) ;
}
else
2021-12-14 18:08:59 +00:00
P_WriteConstant ( ( lines [ i ] . flags & ML_NOCLIMB ) ? - 1 : ( sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ) , & lines [ i ] . stringargs [ 1 ] ) ;
2021-09-21 06:34:55 +00:00
break ;
2021-07-02 10:51:39 +00:00
case 435 : //Change plane scroller direction
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > FRACBITS ;
break ;
2021-09-22 05:32:39 +00:00
case 436 : //Shatter FOF
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
break ;
2021-09-20 11:31:32 +00:00
case 437 : //Disable player control
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2021-09-20 12:50:18 +00:00
case 438 : //Change object size
lines [ i ] . args [ 0 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
break ;
2021-09-20 12:42:21 +00:00
case 439 : //Change tagged linedef's textures
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = TMSD_FRONTBACK ;
lines [ i ] . args [ 2 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2021-09-20 12:25:07 +00:00
case 441 : //Condition set trigger
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
break ;
2021-09-21 05:36:54 +00:00
case 442 : //Change object type state
lines [ i ] . args [ 0 ] = tag ;
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
if ( lines [ i ] . sidenum [ 1 ] = = 0xffff )
lines [ i ] . args [ 1 ] = 1 ;
else
{
lines [ i ] . args [ 1 ] = 0 ;
if ( sides [ lines [ i ] . sidenum [ 1 ] ] . text )
{
lines [ i ] . stringargs [ 1 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 1 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 1 ] , sides [ lines [ i ] . sidenum [ 1 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 1 ] ] . text ) + 1 ) ;
}
}
break ;
2020-01-11 14:38:50 +00:00
case 443 : //Call Lua function
if ( lines [ i ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( lines [ i ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , lines [ i ] . text , strlen ( lines [ i ] . text ) + 1 ) ;
}
else
CONS_Alert ( CONS_WARNING , " Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields) \n " , sizeu1 ( i ) ) ;
break ;
2021-09-20 12:25:07 +00:00
case 444 : //Earthquake
lines [ i ] . args [ 0 ] = P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
break ;
2021-09-22 05:32:39 +00:00
case 445 : //Make FOF disappear/reappear
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
case 446 : //Make FOF crumble
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 2 ] | = TMFR_NORETURN ;
if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 2 ] | = TMFR_CHECKFLAG ;
break ;
2020-03-20 10:19:30 +00:00
case 447 : //Change colormap
2021-09-21 13:34:47 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_EFFECT3 )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 2 ] | = TMCF_RELATIVE ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_EFFECT1 )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 2 ] | = TMCF_SUBLIGHTR | TMCF_SUBFADER ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_NOCLIMB )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 2 ] | = TMCF_SUBLIGHTG | TMCF_SUBFADEG ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_EFFECT2 )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 2 ] | = TMCF_SUBLIGHTB | TMCF_SUBFADEB ;
2020-03-20 10:19:30 +00:00
break ;
2021-09-20 12:25:07 +00:00
case 448 : //Change skybox
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( ( lines [ i ] . flags & ( ML_EFFECT4 | ML_BLOCKMONSTERS ) ) = = ML_EFFECT4 ) // Solid Midtexture is on but Block Enemies is off?
{
CONS_Alert ( CONS_WARNING ,
M_GetText ( " Skybox switch linedef (tag %d) doesn't have anything to do. \n Consider changing the linedef's flag configuration or removing it entirely. \n " ) ,
tag ) ;
lines [ i ] . special = 0 ;
break ;
}
else if ( ( lines [ i ] . flags & ( ML_EFFECT4 | ML_BLOCKMONSTERS ) ) = = ( ML_EFFECT4 | ML_BLOCKMONSTERS ) )
lines [ i ] . args [ 2 ] = TMS_CENTERPOINT ;
else if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 2 ] = TMS_BOTH ;
else
lines [ i ] . args [ 2 ] = TMS_VIEWPOINT ;
lines [ i ] . args [ 3 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
case 449 : //Enable bosses with parameters
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
case 450 : //Execute linedef executor (specific tag)
lines [ i ] . args [ 0 ] = tag ;
break ;
case 451 : //Execute linedef executor (random tag in range)
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
break ;
2021-09-22 05:32:39 +00:00
case 452 : //Set FOF translucency
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = lines [ i ] . sidenum [ 1 ] ! = 0xffff ? ( sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS ) : ( P_AproxDistance ( lines [ i ] . dx , lines [ i ] . dy ) > > FRACBITS ) ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 3 ] | = TMST_RELATIVE ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 3 ] | = TMST_DONTDOTRANSLUCENT ;
break ;
case 453 : //Fade FOF
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = lines [ i ] . sidenum [ 1 ] ! = 0xffff ? ( sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS ) : ( lines [ i ] . dx > > FRACBITS ) ;
lines [ i ] . args [ 3 ] = lines [ i ] . sidenum [ 1 ] ! = 0xffff ? ( sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS ) : ( abs ( lines [ i ] . dy ) > > FRACBITS ) ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 4 ] | = TMFT_RELATIVE ;
if ( lines [ i ] . flags & ML_EFFECT5 )
lines [ i ] . args [ 4 ] | = TMFT_OVERRIDE ;
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 4 ] | = TMFT_TICBASED ;
if ( lines [ i ] . flags & ML_BOUNCY )
lines [ i ] . args [ 4 ] | = TMFT_IGNORECOLLISION ;
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 4 ] | = TMFT_GHOSTFADE ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 4 ] | = TMFT_DONTDOTRANSLUCENT ;
if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 4 ] | = TMFT_DONTDOEXISTS ;
if ( lines [ i ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 4 ] | = ( TMFT_DONTDOLIGHTING | TMFT_DONTDOCOLORMAP ) ;
if ( lines [ i ] . flags & ML_TFERLINE )
lines [ i ] . args [ 4 ] | = TMFT_USEEXACTALPHA ;
break ;
case 454 : //Stop fading FOF
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = ! ! ( lines [ i ] . flags & ML_BLOCKMONSTERS ) ;
break ;
2020-03-20 10:19:30 +00:00
case 455 : //Fade colormap
{
INT32 speed = ( INT32 ) ( ( ( ( lines [ i ] . flags & ML_DONTPEGBOTTOM ) | | ! sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset ) & & lines [ i ] . sidenum [ 1 ] ! = 0xFFFF ) ?
abs ( sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS )
: abs ( sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ) ) ;
2021-09-21 13:34:47 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 2 ] = speed ;
else
lines [ i ] . args [ 2 ] = ( 256 + speed - 1 ) / speed ;
if ( lines [ i ] . flags & ML_EFFECT3 )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 3 ] | = TMCF_RELATIVE ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_EFFECT1 )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 3 ] | = TMCF_SUBLIGHTR | TMCF_SUBFADER ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_NOCLIMB )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 3 ] | = TMCF_SUBLIGHTG | TMCF_SUBFADEG ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_EFFECT2 )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 3 ] | = TMCF_SUBLIGHTB | TMCF_SUBFADEB ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_BOUNCY )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 3 ] | = TMCF_FROMBLACK ;
2020-03-20 10:19:30 +00:00
if ( lines [ i ] . flags & ML_EFFECT5 )
2020-04-18 15:15:25 +00:00
lines [ i ] . args [ 3 ] | = TMCF_OVERRIDE ;
2020-03-20 10:19:30 +00:00
break ;
}
case 456 : //Stop fading colormap
2021-09-21 13:34:47 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-03-20 10:19:30 +00:00
break ;
2021-09-21 13:10:50 +00:00
case 457 : //Track object's angle
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = ( lines [ i ] . sidenum [ 1 ] ! = 0xffff ) ? sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS : 0 ;
lines [ i ] . args [ 4 ] = ! ! ( lines [ i ] . flags & ML_EFFECT2 ) ;
break ;
2021-09-21 07:05:40 +00:00
case 459 : //Control text prompt
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_BLOCKMONSTERS )
lines [ i ] . args [ 2 ] | = TMP_CLOSE ;
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 2 ] | = TMP_RUNPOSTEXEC ;
if ( lines [ i ] . flags & ML_TFERLINE )
lines [ i ] . args [ 2 ] | = TMP_CALLBYNAME ;
if ( lines [ i ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 2 ] | = TMP_KEEPCONTROLS ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 2 ] | = TMP_KEEPREALTIME ;
/*if (lines[i].flags & ML_NOCLIMB)
lines [ i ] . args [ 2 ] | = TMP_ALLPLAYERS ;
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 2 ] | = ML_EFFECT4 ; */
lines [ i ] . args [ 3 ] = ( lines [ i ] . sidenum [ 1 ] ! = 0xFFFF ) ? sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS : tag ;
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
break ;
2021-09-20 12:25:07 +00:00
case 460 : //Award rings
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
break ;
2021-09-22 06:57:48 +00:00
case 461 : //Spawn object
lines [ i ] . args [ 0 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = lines [ i ] . frontsector - > floorheight > > FRACBITS ;
lines [ i ] . args [ 3 ] = ( lines [ i ] . flags & ML_EFFECT1 ) ? AngleFixed ( R_PointToAngle2 ( lines [ i ] . v1 - > x , lines [ i ] . v1 - > y , lines [ i ] . v2 - > x , lines [ i ] . v2 - > y ) ) > > FRACBITS : 0 ;
if ( lines [ i ] . flags & ML_NOCLIMB )
{
if ( lines [ i ] . sidenum [ 1 ] ! = 0xffff ) // Make sure the linedef has a back side
{
lines [ i ] . args [ 4 ] = 1 ;
lines [ i ] . args [ 5 ] = sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 6 ] = sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 7 ] = lines [ i ] . frontsector - > ceilingheight > > FRACBITS ;
}
else
{
CONS_Alert ( CONS_WARNING , " Linedef Type %d - Spawn Object: Linedef is set for random range but has no back side. \n " , lines [ i ] . special ) ;
lines [ i ] . args [ 4 ] = 0 ;
}
}
else
lines [ i ] . args [ 4 ] = 0 ;
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
break ;
2021-09-21 05:44:55 +00:00
case 463 : //Dye object
if ( sides [ lines [ i ] . sidenum [ 0 ] ] . text )
{
lines [ i ] . stringargs [ 0 ] = Z_Malloc ( strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 , PU_LEVEL , NULL ) ;
M_Memcpy ( lines [ i ] . stringargs [ 0 ] , sides [ lines [ i ] . sidenum [ 0 ] ] . text , strlen ( sides [ lines [ i ] . sidenum [ 0 ] ] . text ) + 1 ) ;
}
break ;
2021-09-21 08:35:01 +00:00
case 464 : //Trigger egg capsule
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2021-09-20 12:25:07 +00:00
case 466 : //Set level failure state
lines [ i ] . args [ 0 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2021-09-20 05:54:10 +00:00
case 467 : //Set light level
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = TML_SECTOR ;
lines [ i ] . args [ 3 ] = ! ! ( lines [ i ] . flags & ML_EFFECT3 ) ;
break ;
2021-07-02 15:18:55 +00:00
case 480 : //Polyobject - door slide
case 481 : //Polyobject - door move
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( lines [ i ] . sidenum [ 1 ] ! = 0xffff )
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS ;
break ;
2021-07-04 10:54:48 +00:00
case 482 : //Polyobject - move
case 483 : //Polyobject - move, override
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = lines [ i ] . special = = 483 ;
lines [ i ] . special = 482 ;
break ;
case 484 : //Polyobject - rotate right
case 485 : //Polyobject - rotate right, override
case 486 : //Polyobject - rotate left
case 487 : //Polyobject - rotate left, override
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( lines [ i ] . args [ 2 ] = = 360 )
lines [ i ] . args [ 3 ] | = TMPR_CONTINUOUS ;
else if ( lines [ i ] . args [ 2 ] = = 0 )
lines [ i ] . args [ 2 ] = 360 ;
if ( lines [ i ] . special < 486 )
lines [ i ] . args [ 2 ] * = - 1 ;
if ( lines [ i ] . flags & ML_NOCLIMB )
lines [ i ] . args [ 3 ] | = TMPR_DONTROTATEOTHERS ;
else if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 3 ] | = TMPR_ROTATEPLAYERS ;
if ( lines [ i ] . special % 2 = = 1 )
lines [ i ] . args [ 3 ] | = TMPR_OVERRIDE ;
lines [ i ] . special = 484 ;
break ;
2021-07-04 11:20:10 +00:00
case 488 : //Polyobject - move by waypoints
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 3 ] = PWR_WRAP ;
else if ( lines [ i ] . flags & ML_EFFECT2 )
lines [ i ] . args [ 3 ] = PWR_COMEBACK ;
else
lines [ i ] . args [ 3 ] = PWR_STOP ;
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 4 ] | = PWF_REVERSE ;
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 4 ] | = PWF_LOOP ;
break ;
2021-07-04 11:45:41 +00:00
case 489 : //Polyobject - turn invisible, intangible
case 490 : //Polyobject - turn visible, tangible
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = 491 - lines [ i ] . special ;
if ( ! ( lines [ i ] . flags & ML_NOCLIMB ) )
lines [ i ] . args [ 2 ] = lines [ i ] . args [ 1 ] ;
lines [ i ] . special = 489 ;
break ;
2021-07-04 13:37:42 +00:00
case 491 : //Polyobject - set translucency
lines [ i ] . args [ 0 ] = tag ;
// If Front X Offset is specified, use that. Else, use floorheight.
lines [ i ] . args [ 1 ] = ( sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset ? sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset : lines [ i ] . frontsector - > floorheight ) > > FRACBITS ;
// If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000.
if ( ! ( lines [ i ] . flags & ML_DONTPEGBOTTOM ) )
lines [ i ] . args [ 1 ] / = 100 ;
lines [ i ] . args [ 2 ] = ! ! ( lines [ i ] . flags & ML_EFFECT3 ) ;
break ;
2021-07-04 17:28:14 +00:00
case 492 : //Polyobject - fade translucency
lines [ i ] . args [ 0 ] = tag ;
// If Front X Offset is specified, use that. Else, use floorheight.
lines [ i ] . args [ 1 ] = ( sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset ? sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset : lines [ i ] . frontsector - > floorheight ) > > FRACBITS ;
// If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000.
if ( ! ( lines [ i ] . flags & ML_DONTPEGBOTTOM ) )
lines [ i ] . args [ 1 ] / = 100 ;
// allow Back Y Offset to be consistent with other fade specials
lines [ i ] . args [ 2 ] = ( lines [ i ] . sidenum [ 1 ] ! = 0xffff & & ! sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset ) ?
abs ( sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS )
: abs ( sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ) ;
if ( lines [ i ] . flags & ML_EFFECT3 )
lines [ i ] . args [ 3 ] | = TMPF_RELATIVE ;
if ( lines [ i ] . flags & ML_EFFECT5 )
lines [ i ] . args [ 3 ] | = TMPF_OVERRIDE ;
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 3 ] | = TMPF_TICBASED ;
if ( lines [ i ] . flags & ML_BOUNCY )
lines [ i ] . args [ 3 ] | = TMPF_IGNORECOLLISION ;
if ( lines [ i ] . flags & ML_EFFECT1 )
lines [ i ] . args [ 3 ] | = TMPF_GHOSTFADE ;
break ;
2021-06-30 21:50:54 +00:00
case 500 : //Scroll front wall left
case 501 : //Scroll front wall right
lines [ i ] . args [ 0 ] = 0 ;
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 500 ) ? - 1 : 1 ;
lines [ i ] . args [ 2 ] = 0 ;
lines [ i ] . special = 500 ;
break ;
case 502 : //Scroll tagged wall
case 503 : //Scroll tagged wall (accelerative)
case 504 : //Scroll tagged wall (displacement)
lines [ i ] . args [ 0 ] = tag ;
if ( lines [ i ] . flags & ML_EFFECT3 )
{
if ( lines [ i ] . sidenum [ 1 ] = = 0xffff )
{
CONS_Debug ( DBG_GAMELOGIC , " Line special %d (line #%s) missing back side! \n " , lines [ i ] . special , sizeu1 ( i ) ) ;
lines [ i ] . special = 0 ;
break ;
}
lines [ i ] . args [ 1 ] = 1 ;
}
else
lines [ i ] . args [ 1 ] = 0 ;
if ( lines [ i ] . flags & ML_EFFECT2 )
{
lines [ i ] . args [ 2 ] = lines [ i ] . dx > > ( FRACBITS + SCROLL_SHIFT ) ;
lines [ i ] . args [ 3 ] = lines [ i ] . dy > > ( FRACBITS + SCROLL_SHIFT ) ;
}
else
{
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
}
lines [ i ] . args [ 4 ] = lines [ i ] . special - 502 ;
lines [ i ] . special = 502 ;
break ;
case 505 : //Scroll front wall by front side offsets
case 506 : //Scroll front wall by back side offsets
case 507 : //Scroll back wall by front side offsets
case 508 : //Scroll back wall by back side offsets
lines [ i ] . args [ 0 ] = lines [ i ] . special > = 507 ;
if ( lines [ i ] . special % 2 = = 0 )
{
if ( lines [ i ] . sidenum [ 1 ] = = 0xffff )
{
CONS_Debug ( DBG_GAMELOGIC , " Line special %d (line #%s) missing back side! \n " , lines [ i ] . special , sizeu1 ( i ) ) ;
lines [ i ] . special = 0 ;
break ;
}
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS ;
}
else
{
lines [ i ] . args [ 1 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
}
lines [ i ] . special = 500 ;
break ;
case 510 : //Scroll floor texture
case 511 : //Scroll floor texture (accelerative)
case 512 : //Scroll floor texture (displacement)
case 513 : //Scroll ceiling texture
case 514 : //Scroll ceiling texture (accelerative)
case 515 : //Scroll ceiling texture (displacement)
case 520 : //Carry objects on floor
case 521 : //Carry objects on floor (accelerative)
case 522 : //Carry objects on floor (displacement)
case 523 : //Carry objects on ceiling
case 524 : //Carry objects on ceiling (accelerative)
case 525 : //Carry objects on ceiling (displacement)
case 530 : //Scroll floor texture and carry objects
case 531 : //Scroll floor texture and carry objects (accelerative)
case 532 : //Scroll floor texture and carry objects (displacement)
case 533 : //Scroll ceiling texture and carry objects
case 534 : //Scroll ceiling texture and carry objects (accelerative)
case 535 : //Scroll ceiling texture and carry objects (displacement)
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = ( ( lines [ i ] . special % 10 ) < 3 ) ? TMP_FLOOR : TMP_CEILING ;
lines [ i ] . args [ 2 ] = ( ( lines [ i ] . special - 510 ) / 10 + 1 ) % 3 ;
lines [ i ] . args [ 3 ] = R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > FRACBITS ;
lines [ i ] . args [ 4 ] = ( lines [ i ] . special % 10 ) % 3 ;
2021-06-30 22:47:56 +00:00
if ( lines [ i ] . args [ 2 ] ! = TMS_SCROLLONLY & & ! ( lines [ i ] . flags & ML_NOCLIMB ) )
lines [ i ] . args [ 4 ] | = TMST_NONEXCLUSIVE ;
2021-06-30 21:50:54 +00:00
lines [ i ] . special = 510 ;
break ;
2021-07-01 18:35:13 +00:00
case 541 : //Wind
case 542 : //Upwards wind
case 543 : //Downwards wind
case 544 : //Current
case 545 : //Upwards current
case 546 : //Downwards current
lines [ i ] . args [ 0 ] = tag ;
switch ( ( lines [ i ] . special - 541 ) % 3 )
{
case 0 :
lines [ i ] . args [ 1 ] = R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > FRACBITS ;
break ;
case 1 :
lines [ i ] . args [ 2 ] = R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > FRACBITS ;
break ;
case 2 :
lines [ i ] . args [ 2 ] = - R_PointToDist2 ( lines [ i ] . v2 - > x , lines [ i ] . v2 - > y , lines [ i ] . v1 - > x , lines [ i ] . v1 - > y ) > > FRACBITS ;
break ;
}
lines [ i ] . args [ 3 ] = ( lines [ i ] . special > = 544 ) ? p_current : p_wind ;
if ( lines [ i ] . flags & ML_EFFECT4 )
lines [ i ] . args [ 4 ] | = TMPF_SLIDE ;
if ( ! ( lines [ i ] . flags & ML_NOCLIMB ) )
lines [ i ] . args [ 4 ] | = TMPF_NONEXCLUSIVE ;
lines [ i ] . special = 541 ;
break ;
2021-09-20 06:36:55 +00:00
case 600 : //Floor lighting
case 601 : //Ceiling lighting
lines [ i ] . args [ 0 ] = tag ;
lines [ i ] . args [ 1 ] = ( lines [ i ] . special = = 601 ) ? TMP_CEILING : TMP_FLOOR ;
lines [ i ] . special = 600 ;
break ;
2020-03-20 10:19:30 +00:00
case 606 : //Colormap
2021-09-21 13:34:47 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-03-20 10:19:30 +00:00
break ;
2020-01-05 13:31:56 +00:00
case 700 : //Slope front sector floor
case 701 : //Slope front sector ceiling
case 702 : //Slope front sector floor and ceiling
case 703 : //Slope front sector floor and back sector ceiling
case 710 : //Slope back sector floor
case 711 : //Slope back sector ceiling
case 712 : //Slope back sector floor and ceiling
case 713 : //Slope back sector floor and front sector ceiling
{
boolean frontfloor = ( lines [ i ] . special = = 700 | | lines [ i ] . special = = 702 | | lines [ i ] . special = = 703 ) ;
boolean backfloor = ( lines [ i ] . special = = 710 | | lines [ i ] . special = = 712 | | lines [ i ] . special = = 713 ) ;
boolean frontceil = ( lines [ i ] . special = = 701 | | lines [ i ] . special = = 702 | | lines [ i ] . special = = 713 ) ;
boolean backceil = ( lines [ i ] . special = = 711 | | lines [ i ] . special = = 712 | | lines [ i ] . special = = 703 ) ;
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 0 ] = backfloor ? TMS_BACK : ( frontfloor ? TMS_FRONT : TMS_NONE ) ;
lines [ i ] . args [ 1 ] = backceil ? TMS_BACK : ( frontceil ? TMS_FRONT : TMS_NONE ) ;
2020-01-05 13:31:56 +00:00
if ( lines [ i ] . flags & ML_NETONLY )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 2 ] | = TMSL_NOPHYSICS ;
2020-01-05 13:31:56 +00:00
if ( lines [ i ] . flags & ML_NONET )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 2 ] | = TMSL_DYNAMIC ;
2020-01-05 13:31:56 +00:00
2021-06-17 11:23:27 +00:00
if ( lines [ i ] . flags & ML_TFERLINE )
{
lines [ i ] . args [ 4 ] | = backfloor ? TMSC_BACKTOFRONTFLOOR : ( frontfloor ? TMSC_FRONTTOBACKFLOOR : 0 ) ;
lines [ i ] . args [ 4 ] | = backceil ? TMSC_BACKTOFRONTCEILING : ( frontceil ? TMSC_FRONTTOBACKCEILING : 0 ) ;
}
2020-01-05 13:31:56 +00:00
lines [ i ] . special = 700 ;
break ;
}
2020-01-06 14:34:28 +00:00
case 704 : //Slope front sector floor by 3 tagged vertices
case 705 : //Slope front sector ceiling by 3 tagged vertices
case 714 : //Slope back sector floor by 3 tagged vertices
case 715 : //Slope back sector ceiling by 3 tagged vertices
{
if ( lines [ i ] . special = = 704 )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 0 ] = TMSP_FRONTFLOOR ;
2020-01-06 14:34:28 +00:00
else if ( lines [ i ] . special = = 705 )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 0 ] = TMSP_FRONTCEILING ;
2020-01-06 14:34:28 +00:00
else if ( lines [ i ] . special = = 714 )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 0 ] = TMSP_BACKFLOOR ;
2020-01-06 14:34:28 +00:00
else if ( lines [ i ] . special = = 715 )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 0 ] = TMSP_BACKCEILING ;
2020-01-06 14:34:28 +00:00
2020-04-17 09:04:44 +00:00
lines [ i ] . args [ 1 ] = tag ;
2020-01-06 14:34:28 +00:00
if ( lines [ i ] . flags & ML_EFFECT6 )
{
UINT8 side = lines [ i ] . special > = 714 ;
if ( side = = 1 & & lines [ i ] . sidenum [ 1 ] = = 0xffff )
CONS_Debug ( DBG_GAMELOGIC , " P_ConvertBinaryMap: Line special %d (line #%s) missing 2nd side! \n " , lines [ i ] . special , sizeu1 ( i ) ) ;
else
{
lines [ i ] . args [ 2 ] = sides [ lines [ i ] . sidenum [ side ] ] . textureoffset > > FRACBITS ;
lines [ i ] . args [ 3 ] = sides [ lines [ i ] . sidenum [ side ] ] . rowoffset > > FRACBITS ;
}
}
else
{
lines [ i ] . args [ 2 ] = lines [ i ] . args [ 1 ] ;
lines [ i ] . args [ 3 ] = lines [ i ] . args [ 1 ] ;
}
if ( lines [ i ] . flags & ML_NETONLY )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 4 ] | = TMSL_NOPHYSICS ;
2020-01-06 14:34:28 +00:00
if ( lines [ i ] . flags & ML_NONET )
2020-04-18 14:55:56 +00:00
lines [ i ] . args [ 4 ] | = TMSL_DYNAMIC ;
2020-01-06 14:34:28 +00:00
lines [ i ] . special = 704 ;
break ;
}
2020-01-06 16:39:39 +00:00
case 720 : //Copy front side floor slope
case 721 : //Copy front side ceiling slope
case 722 : //Copy front side floor and ceiling slope
if ( lines [ i ] . special ! = 721 )
2020-04-17 09:04:44 +00:00
lines [ i ] . args [ 0 ] = tag ;
2020-01-06 16:39:39 +00:00
if ( lines [ i ] . special ! = 720 )
2020-04-17 09:04:44 +00:00
lines [ i ] . args [ 1 ] = tag ;
2020-01-06 16:39:39 +00:00
lines [ i ] . special = 720 ;
break ;
2021-02-17 15:06:02 +00:00
case 723 : //Copy back side floor slope
case 724 : //Copy back side ceiling slope
case 725 : //Copy back side floor and ceiling slope
if ( lines [ i ] . special ! = 724 )
lines [ i ] . args [ 2 ] = tag ;
if ( lines [ i ] . special ! = 723 )
lines [ i ] . args [ 3 ] = tag ;
lines [ i ] . special = 720 ;
break ;
case 730 : //Copy front side floor slope to back side
case 731 : //Copy front side ceiling slope to back side
case 732 : //Copy front side floor and ceiling slope to back side
if ( lines [ i ] . special ! = 731 )
lines [ i ] . args [ 4 ] | = TMSC_FRONTTOBACKFLOOR ;
if ( lines [ i ] . special ! = 730 )
lines [ i ] . args [ 4 ] | = TMSC_FRONTTOBACKCEILING ;
lines [ i ] . special = 720 ;
break ;
case 733 : //Copy back side floor slope to front side
case 734 : //Copy back side ceiling slope to front side
case 735 : //Copy back side floor and ceiling slope to front side
if ( lines [ i ] . special ! = 734 )
lines [ i ] . args [ 4 ] | = TMSC_BACKTOFRONTFLOOR ;
if ( lines [ i ] . special ! = 733 )
lines [ i ] . args [ 4 ] | = TMSC_BACKTOFRONTCEILING ;
lines [ i ] . special = 720 ;
break ;
2021-12-29 14:29:59 +00:00
case 799 : //Set dynamic slope vertex to front sector height
lines [ i ] . args [ 0 ] = ! ! ( lines [ i ] . flags & ML_NOCLIMB ) ;
break ;
2020-01-26 11:24:52 +00:00
case 900 : //Translucent wall (10%)
case 901 : //Translucent wall (20%)
case 902 : //Translucent wall (30%)
case 903 : //Translucent wall (40%)
case 904 : //Translucent wall (50%)
case 905 : //Translucent wall (60%)
case 906 : //Translucent wall (70%)
case 907 : //Translucent wall (80%)
case 908 : //Translucent wall (90%)
lines [ i ] . alpha = ( ( 909 - lines [ i ] . special ) < < FRACBITS ) / 10 ;
break ;
2020-01-05 13:31:56 +00:00
}
2020-05-03 18:41:37 +00:00
//Linedef executor delay
if ( lines [ i ] . special > = 400 & & lines [ i ] . special < 500 )
{
//Dummy value to indicate that this executor is delayed.
//The real value is taken from the back sector at runtime.
if ( lines [ i ] . flags & ML_DONTPEGTOP )
lines [ i ] . executordelay = 1 ;
}
2020-01-05 13:31:56 +00:00
}
2020-01-25 09:01:01 +00:00
2021-12-27 14:07:37 +00:00
for ( i = 0 ; i < NUMMOBJTYPES ; i + + )
{
if ( mobjinfo [ i ] . doomednum < 0 | | mobjinfo [ i ] . doomednum > = 4096 )
continue ;
mobjtypeofthing [ mobjinfo [ i ] . doomednum ] = ( mobjtype_t ) i ;
}
2020-01-25 09:01:01 +00:00
for ( i = 0 ; i < nummapthings ; i + + )
{
2021-12-27 14:07:37 +00:00
mobjtype = mobjtypeofthing [ mapthings [ i ] . type ] ;
if ( mobjtype )
{
if ( mobjinfo [ mobjtype ] . flags & MF_BOSS )
{
INT32 paramoffset = mapthings [ i ] . extrainfo * LE_PARAMWIDTH ;
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo ;
2021-12-28 21:52:24 +00:00
mapthings [ i ] . args [ 1 ] = ! ! ( mapthings [ i ] . options & MTF_OBJECTSPECIAL ) ;
mapthings [ i ] . args [ 2 ] = LE_BOSSDEAD + paramoffset ;
mapthings [ i ] . args [ 3 ] = LE_ALLBOSSESDEAD + paramoffset ;
mapthings [ i ] . args [ 4 ] = LE_PINCHPHASE + paramoffset ;
2021-12-27 14:07:37 +00:00
}
2021-12-28 13:01:45 +00:00
if ( mobjinfo [ mobjtype ] . flags & MF_NIGHTSITEM )
{
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 0 ] | = TMNI_BONUSONLY ;
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 0 ] | = TMNI_REVEAL ;
}
2021-12-28 13:28:36 +00:00
if ( mobjinfo [ mobjtype ] . flags & MF_PUSHABLE )
{
if ( ( mapthings [ i ] . options & ( MTF_OBJECTSPECIAL | MTF_AMBUSH ) ) = = ( MTF_OBJECTSPECIAL | MTF_AMBUSH ) )
mapthings [ i ] . args [ 0 ] = TMP_CLASSIC ;
else if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 0 ] = TMP_SLIDE ;
else if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 0 ] = TMP_IMMOVABLE ;
else
mapthings [ i ] . args [ 0 ] = TMP_NORMAL ;
}
2021-12-28 16:54:26 +00:00
if ( ( mobjinfo [ mobjtype ] . flags & MF_SPRING ) & & mobjinfo [ mobjtype ] . painchance = = 3 )
2021-12-28 15:38:52 +00:00
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
2021-12-28 16:54:26 +00:00
if ( mobjinfo [ mobjtype ] . flags & MF_MONITOR )
{
if ( ( mapthings [ i ] . options & MTF_EXTRA ) & & mapthings [ i ] . angle & 16384 )
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle & 16383 ;
if ( mobjinfo [ mobjtype ] . speed ! = 0 )
{
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 1 ] = TMMR_STRONG ;
else if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 1 ] = TMMR_WEAK ;
else
mapthings [ i ] . args [ 1 ] = TMMR_SAME ;
}
}
2021-12-27 14:07:37 +00:00
}
2021-12-27 16:36:16 +00:00
if ( mapthings [ i ] . type > = 1 & & mapthings [ i ] . type < = 35 ) //Player starts
{
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
continue ;
}
else if ( mapthings [ i ] . type > = 2200 & & mapthings [ i ] . type < = 2217 ) //Flickies
{
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
if ( mapthings [ i ] . options & MTF_EXTRA )
mapthings [ i ] . args [ 1 ] | = TMFF_AIMLESS ;
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 1 ] | = TMFF_STATIONARY ;
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 1 ] | = TMFF_HOP ;
if ( mapthings [ i ] . type = = 2207 )
mapthings [ i ] . args [ 2 ] = mapthings [ i ] . extrainfo ;
continue ;
}
2020-01-25 09:01:01 +00:00
switch ( mapthings [ i ] . type )
{
2021-12-21 16:26:55 +00:00
case 102 : //SDURF
case 1805 : //Puma
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
break ;
2021-12-20 22:28:18 +00:00
case 110 : //THZ Turret
mapthings [ i ] . args [ 0 ] = LE_TURRET ;
break ;
2021-12-21 16:45:43 +00:00
case 111 : //Pop-up Turret
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
break ;
2021-12-28 12:14:48 +00:00
case 103 : //Buzz (Gold)
case 104 : //Buzz (Red)
case 105 : //Jetty-syn Bomber
case 106 : //Jetty-syn Gunner
case 117 : //Robo-Hood
case 126 : //Crushstacean
case 128 : //Bumblebore
case 132 : //Cacolantern
case 138 : //Banpyura
case 1602 : //Pian
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
case 119 : //Egg Guard
if ( ( mapthings [ i ] . options & ( MTF_EXTRA | MTF_OBJECTSPECIAL ) ) = = MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 0 ] = TMGD_LEFT ;
else if ( ( mapthings [ i ] . options & ( MTF_EXTRA | MTF_OBJECTSPECIAL ) ) = = MTF_EXTRA )
mapthings [ i ] . args [ 0 ] = TMGD_RIGHT ;
else
mapthings [ i ] . args [ 0 ] = TMGD_BACK ;
mapthings [ i ] . args [ 1 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-21 20:51:37 +00:00
case 127 : //Hive Elemental
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo ;
break ;
2021-12-21 20:57:35 +00:00
case 135 : //Pterabyte Spawner
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo + 1 ;
break ;
2021-12-21 21:00:42 +00:00
case 136 : //Pyre Fly
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-28 21:52:24 +00:00
case 202 : //Egg Slimer
mapthings [ i ] . args [ 5 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-27 14:07:37 +00:00
case 203 : //Egg Colosseum
2021-12-28 21:52:24 +00:00
mapthings [ i ] . args [ 5 ] = LE_BOSS4DROP + mapthings [ i ] . extrainfo * LE_PARAMWIDTH ;
2021-12-27 14:07:37 +00:00
break ;
case 204 : //Fang
2021-12-28 21:52:24 +00:00
mapthings [ i ] . args [ 4 ] = LE_BOSS4DROP + mapthings [ i ] . extrainfo * LE_PARAMWIDTH ;
if ( mapthings [ i ] . options & MTF_EXTRA )
mapthings [ i ] . args [ 5 ] | = TMF_GRAYSCALE ;
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 5 ] | = TMF_SKIPINTRO ;
2021-12-27 14:07:37 +00:00
break ;
case 206 : //Brak Eggman (Old)
2021-12-28 21:52:24 +00:00
mapthings [ i ] . args [ 5 ] = LE_BRAKPLATFORM + mapthings [ i ] . extrainfo * LE_PARAMWIDTH ;
break ;
case 207 : //Metal Sonic (Race)
case 2104 : //Amy Cameo
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_EXTRA ) ;
break ;
case 208 : //Metal Sonic (Battle)
mapthings [ i ] . args [ 5 ] = ! ! ( mapthings [ i ] . options & MTF_EXTRA ) ;
2021-12-27 14:07:37 +00:00
break ;
case 209 : //Brak Eggman
2021-12-28 21:52:24 +00:00
mapthings [ i ] . args [ 5 ] = LE_BRAKVILEATACK + mapthings [ i ] . extrainfo * LE_PARAMWIDTH ;
if ( mapthings [ i ] . options & MTF_EXTRA )
mapthings [ i ] . args [ 6 ] | = TMB_NODEATHFLING ;
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 6 ] | = TMB_BARRIER ;
2021-12-27 14:07:37 +00:00
break ;
2021-12-27 14:37:21 +00:00
case 292 : //Boss waypoint
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
mapthings [ i ] . args [ 1 ] = mapthings [ i ] . options & 7 ;
break ;
2021-12-28 12:14:48 +00:00
case 294 : //Fang waypoint
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-28 15:38:52 +00:00
case 300 : //Ring
case 301 : //Bounce ring
case 302 : //Rail ring
case 303 : //Infinity ring
case 304 : //Automatic ring
case 305 : //Explosion ring
case 306 : //Scatter ring
case 307 : //Grenade ring
case 308 : //Red team ring
case 309 : //Blue team ring
case 312 : //Emerald token
case 320 : //Emerald hunt location
case 321 : //Match chaos emerald spawn
case 322 : //Emblem
case 330 : //Bounce ring panel
case 331 : //Rail ring panel
case 332 : //Automatic ring panel
case 333 : //Explosion ring panel
case 334 : //Scatter ring panel
case 335 : //Grenade ring panel
case 520 : //Bomb sphere
case 521 : //Spikeball
case 1706 : //Blue sphere
case 1800 : //Coin
mapthings [ i ] . args [ 0 ] = ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-28 16:54:26 +00:00
case 409 : //Extra life monitor
mapthings [ i ] . args [ 2 ] = ! ( mapthings [ i ] . options & ( MTF_AMBUSH | MTF_OBJECTSPECIAL ) ) ;
break ;
2021-12-28 12:14:48 +00:00
case 500 : //Air bubble patch
2021-12-25 08:58:00 +00:00
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-21 17:27:19 +00:00
case 502 : //Star post
if ( mapthings [ i ] . extrainfo )
// Allow thing Parameter to define star post num too!
// For starposts above param 15 (the 16th), add 360 to the angle like before and start parameter from 1 (NOT 0)!
// So the 16th starpost is angle=0 param=15, the 17th would be angle=360 param=1.
// This seems more intuitive for mappers to use, since most SP maps won't have over 16 consecutive star posts.
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo + ( mapthings [ i ] . angle / 360 ) * 15 ;
else
// Old behavior if Parameter is 0; add 360 to the angle for each consecutive star post.
mapthings [ i ] . args [ 0 ] = ( mapthings [ i ] . angle / 360 ) ;
2021-12-28 15:38:52 +00:00
mapthings [ i ] . args [ 1 ] = ! ! ( mapthings [ i ] . options & MTF_OBJECTSPECIAL ) ;
2021-12-21 17:27:19 +00:00
break ;
2021-12-27 06:32:57 +00:00
case 522 : //Wall spike
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
{
mapthings [ i ] . args [ 0 ] = mobjinfo [ MT_WALLSPIKE ] . speed + mapthings [ i ] . angle / 360 ;
mapthings [ i ] . args [ 1 ] = ( 16 - mapthings [ i ] . extrainfo ) * mapthings [ i ] . args [ 0 ] / 16 ;
if ( mapthings [ i ] . options & MTF_EXTRA )
mapthings [ i ] . args [ 2 ] | = TMSF_RETRACTED ;
}
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 2 ] | = TMSF_INTANGIBLE ;
break ;
case 523 : //Spike
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
{
mapthings [ i ] . args [ 0 ] = mobjinfo [ MT_SPIKE ] . speed + mapthings [ i ] . angle ;
mapthings [ i ] . args [ 1 ] = ( 16 - mapthings [ i ] . extrainfo ) * mapthings [ i ] . args [ 0 ] / 16 ;
if ( mapthings [ i ] . options & MTF_EXTRA )
mapthings [ i ] . args [ 2 ] | = TMSF_RETRACTED ;
}
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 2 ] | = TMSF_INTANGIBLE ;
break ;
2021-12-28 06:40:38 +00:00
case 540 : //Fan
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
2021-12-28 12:14:48 +00:00
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 1 ] | = TMF_INVISIBLE ;
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 1 ] | = TMF_NODISTANCECHECK ;
2021-12-28 06:40:38 +00:00
break ;
2021-12-28 15:38:52 +00:00
case 541 : //Gas jet
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-28 07:26:04 +00:00
case 543 : //Balloon
if ( mapthings [ i ] . angle > 0 )
P_WriteConstant ( ( ( mapthings [ i ] . angle - 1 ) % ( numskincolors - 1 ) ) + 1 , & mapthings [ i ] . stringargs [ 0 ] ) ;
2021-12-28 12:14:48 +00:00
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
2021-12-28 07:26:04 +00:00
break ;
2021-12-27 20:28:42 +00:00
case 555 : //Diagonal yellow spring
case 556 : //Diagonal red spring
case 557 : //Diagonal blue spring
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 0 ] | = TMDS_NOGRAVITY ;
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 0 ] | = TMDS_ROTATEEXTRA ;
break ;
2021-12-28 15:38:52 +00:00
case 558 : //Horizontal yellow spring
case 559 : //Horizontal red spring
case 560 : //Horizontal blue spring
mapthings [ i ] . args [ 0 ] = ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-28 08:58:45 +00:00
case 700 : //Water ambience A
case 701 : //Water ambience A
case 702 : //Water ambience A
case 703 : //Water ambience A
case 704 : //Water ambience A
case 705 : //Water ambience A
case 706 : //Water ambience A
case 707 : //Water ambience A
mapthings [ i ] . args [ 0 ] = 35 ;
P_WriteConstant ( sfx_amwtr1 + mapthings [ i ] . type - 700 , & mapthings [ i ] . stringargs [ 0 ] ) ;
mapthings [ i ] . type = 700 ;
break ;
case 708 : //Disco ambience
mapthings [ i ] . args [ 0 ] = 512 ;
P_WriteConstant ( sfx_ambint , & mapthings [ i ] . stringargs [ 0 ] ) ;
mapthings [ i ] . type = 700 ;
break ;
case 709 : //Volcano ambience
mapthings [ i ] . args [ 0 ] = 220 ;
P_WriteConstant ( sfx_ambin2 , & mapthings [ i ] . stringargs [ 0 ] ) ;
mapthings [ i ] . type = 700 ;
break ;
case 710 : //Machine ambience
mapthings [ i ] . args [ 0 ] = 24 ;
P_WriteConstant ( sfx_ambmac , & mapthings [ i ] . stringargs [ 0 ] ) ;
mapthings [ i ] . type = 700 ;
break ;
2021-12-26 20:33:20 +00:00
case 750 : //Slope vertex
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo ;
break ;
2021-12-21 17:19:10 +00:00
case 753 : //Zoom tube waypoint
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle > > 8 ;
mapthings [ i ] . args [ 1 ] = mapthings [ i ] . angle & 255 ;
break ;
2021-12-16 06:00:30 +00:00
case 754 : //Push point
case 755 : //Pull point
{
subsector_t * ss = R_PointInSubsector ( mapthings [ i ] . x < < FRACBITS , mapthings [ i ] . y < < FRACBITS ) ;
sector_t * s ;
line_t * line ;
if ( ! ss )
{
CONS_Debug ( DBG_GAMELOGIC , " Push/pull point: Placed outside of map bounds! \n " ) ;
break ;
}
s = ss - > sector ;
line = P_FindPointPushLine ( & s - > tags ) ;
if ( ! line )
{
CONS_Debug ( DBG_GAMELOGIC , " Push/pull point: Unable to find line of type 547 tagged to sector %s! \n " , sizeu1 ( ( size_t ) ( s - sectors ) ) ) ;
break ;
}
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
mapthings [ i ] . args [ 1 ] = P_AproxDistance ( line - > dx > > FRACBITS , line - > dy > > FRACBITS ) ;
if ( mapthings [ i ] . type = = 755 )
mapthings [ i ] . args [ 1 ] * = - 1 ;
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 2 ] | = TMPP_NOZFADE ;
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 2 ] | = TMPP_PUSHZ ;
if ( ! ( line - > flags & ML_NOCLIMB ) )
mapthings [ i ] . args [ 2 ] | = TMPP_NONEXCLUSIVE ;
mapthings [ i ] . type = 754 ;
break ;
}
2021-12-28 07:33:57 +00:00
case 756 : //Blast linedef executor
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
break ;
2021-12-18 09:31:42 +00:00
case 757 : //Fan particle generator
{
INT32 j = Tag_FindLineSpecial ( 15 , mapthings [ i ] . angle ) ;
if ( j = = - 1 )
{
CONS_Debug ( DBG_GAMELOGIC , " Particle generator (mapthing #%d) needs to be tagged to a #15 parameter line (trying to find tag %d). \n " , i , mapthings [ i ] . angle ) ;
break ;
}
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . z ;
mapthings [ i ] . args [ 1 ] = R_PointToDist2 ( lines [ j ] . v1 - > x , lines [ j ] . v1 - > y , lines [ j ] . v2 - > x , lines [ j ] . v2 - > y ) > > FRACBITS ;
mapthings [ i ] . args [ 2 ] = sides [ lines [ j ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
mapthings [ i ] . args [ 3 ] = sides [ lines [ j ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
mapthings [ i ] . args [ 4 ] = lines [ j ] . backsector ? sides [ lines [ j ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS : 0 ;
2021-12-29 14:53:20 +00:00
mapthings [ i ] . args [ 6 ] = mapthings [ i ] . angle ;
2021-12-18 09:31:42 +00:00
if ( sides [ lines [ j ] . sidenum [ 0 ] ] . toptexture )
P_WriteConstant ( sides [ lines [ j ] . sidenum [ 0 ] ] . toptexture , & mapthings [ i ] . stringargs [ 0 ] ) ;
break ;
}
2021-12-14 18:08:59 +00:00
case 762 : //PolyObject spawn point (crush)
2020-05-04 21:27:26 +00:00
{
2020-07-10 14:51:11 +00:00
INT32 check = - 1 ;
INT32 firstline = - 1 ;
2021-09-21 10:55:22 +00:00
mtag_t tag = Tag_FGet ( & mapthings [ i ] . tags ) ;
2020-07-10 14:51:11 +00:00
2021-02-11 12:24:20 +00:00
TAG_ITER_LINES ( tag , check )
2020-07-10 14:51:11 +00:00
{
if ( lines [ check ] . special = = 20 )
{
firstline = check ;
break ;
}
}
2020-05-04 21:27:26 +00:00
if ( firstline ! = - 1 )
lines [ firstline ] . args [ 3 ] | = TMPF_CRUSH ;
2020-07-10 14:51:11 +00:00
2020-05-04 21:27:26 +00:00
mapthings [ i ] . type = 761 ;
2020-01-25 09:01:01 +00:00
break ;
2020-05-04 21:27:26 +00:00
}
2021-12-28 06:29:41 +00:00
case 780 : //Skybox
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_OBJECTSPECIAL ) ;
break ;
2021-12-28 07:19:56 +00:00
case 1002 : //Dripping water
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
break ;
case 1007 : //Kelp
case 1008 : //Stalagmite (DSZ1)
case 1011 : //Stalagmite (DSZ2)
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_OBJECTSPECIAL ) ;
break ;
2021-12-28 15:38:52 +00:00
case 1102 : //Eggman Statue
mapthings [ i ] . args [ 1 ] = ! ! ( mapthings [ i ] . options & MTF_EXTRA ) ;
break ;
2021-12-14 17:50:47 +00:00
case 1104 : //Mace spawnpoint
case 1105 : //Chain with maces spawnpoint
case 1106 : //Chained spring spawnpoint
case 1107 : //Chain spawnpoint
case 1109 : //Firebar spawnpoint
case 1110 : //Custom mace spawnpoint
{
mtag_t tag = ( mtag_t ) mapthings [ i ] . angle ;
INT32 j = Tag_FindLineSpecial ( 9 , tag ) ;
if ( j = = - 1 )
{
CONS_Debug ( DBG_GAMELOGIC , " Chain/mace setup: Unable to find parameter line 9 (tag %d)! \n " , tag ) ;
break ;
}
mapthings [ i ] . angle = lines [ j ] . frontsector - > ceilingheight > > FRACBITS ;
mapthings [ i ] . pitch = lines [ j ] . frontsector - > floorheight > > FRACBITS ;
mapthings [ i ] . args [ 0 ] = lines [ j ] . dx > > FRACBITS ;
mapthings [ i ] . args [ 1 ] = mapthings [ i ] . extrainfo ;
mapthings [ i ] . args [ 3 ] = lines [ j ] . dy > > FRACBITS ;
mapthings [ i ] . args [ 4 ] = sides [ lines [ j ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
mapthings [ i ] . args [ 7 ] = - sides [ lines [ j ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ;
if ( lines [ j ] . backsector )
{
mapthings [ i ] . roll = lines [ j ] . backsector - > ceilingheight > > FRACBITS ;
mapthings [ i ] . args [ 2 ] = sides [ lines [ j ] . sidenum [ 1 ] ] . rowoffset > > FRACBITS ;
mapthings [ i ] . args [ 5 ] = lines [ j ] . backsector - > floorheight > > FRACBITS ;
mapthings [ i ] . args [ 6 ] = sides [ lines [ j ] . sidenum [ 1 ] ] . textureoffset > > FRACBITS ;
}
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 8 ] | = TMM_DOUBLESIZE ;
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 8 ] | = TMM_SILENT ;
if ( lines [ j ] . flags & ML_NOCLIMB )
mapthings [ i ] . args [ 8 ] | = TMM_ALLOWYAWCONTROL ;
if ( lines [ j ] . flags & ML_EFFECT1 )
mapthings [ i ] . args [ 8 ] | = TMM_SWING ;
if ( lines [ j ] . flags & ML_EFFECT2 )
mapthings [ i ] . args [ 8 ] | = TMM_MACELINKS ;
if ( lines [ j ] . flags & ML_EFFECT3 )
mapthings [ i ] . args [ 8 ] | = TMM_CENTERLINK ;
if ( lines [ j ] . flags & ML_EFFECT4 )
mapthings [ i ] . args [ 8 ] | = TMM_CLIP ;
if ( lines [ j ] . flags & ML_EFFECT5 )
mapthings [ i ] . args [ 8 ] | = TMM_ALWAYSTHINK ;
if ( mapthings [ i ] . type = = 1110 )
{
2021-12-14 18:08:59 +00:00
P_WriteConstant ( sides [ lines [ j ] . sidenum [ 0 ] ] . toptexture , & mapthings [ i ] . stringargs [ 0 ] ) ;
P_WriteConstant ( lines [ j ] . backsector ? sides [ lines [ j ] . sidenum [ 1 ] ] . toptexture : MT_NULL , & mapthings [ i ] . stringargs [ 1 ] ) ;
2021-12-14 17:50:47 +00:00
}
break ;
}
2021-12-27 17:52:46 +00:00
case 1101 : //Torch
case 1119 : //Candle
case 1120 : //Candle pricket
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_EXTRA ) ;
break ;
case 1121 : //Flame holder
if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 0 ] | = TMFH_NOFLAME ;
if ( mapthings [ i ] . options & MTF_EXTRA )
mapthings [ i ] . args [ 0 ] | = TMFH_CORONA ;
break ;
2021-12-28 15:38:52 +00:00
case 1127 : //Spectator EggRobo
if ( mapthings [ i ] . options & MTF_AMBUSH )
mapthings [ i ] . args [ 0 ] = TMED_LEFT ;
else if ( mapthings [ i ] . options & MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 0 ] = TMED_RIGHT ;
else
mapthings [ i ] . args [ 0 ] = TMED_NONE ;
break ;
2021-12-28 12:14:48 +00:00
case 1200 : //Tumbleweed (Big)
case 1201 : //Tumbleweed (Small)
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-13 07:24:52 +00:00
case 1202 : //Rock spawner
{
mtag_t tag = ( mtag_t ) mapthings [ i ] . angle ;
INT32 j = Tag_FindLineSpecial ( 12 , tag ) ;
if ( j = = - 1 )
{
CONS_Debug ( DBG_GAMELOGIC , " Rock spawner: Unable to find parameter line 12 (tag %d)! \n " , tag ) ;
break ;
}
mapthings [ i ] . angle = AngleFixed ( R_PointToAngle2 ( lines [ j ] . v2 - > x , lines [ j ] . v2 - > y , lines [ j ] . v1 - > x , lines [ j ] . v1 - > y ) ) > > FRACBITS ;
mapthings [ i ] . args [ 0 ] = P_AproxDistance ( lines [ j ] . dx , lines [ j ] . dy ) > > FRACBITS ;
mapthings [ i ] . args [ 1 ] = sides [ lines [ j ] . sidenum [ 0 ] ] . textureoffset > > FRACBITS ;
mapthings [ i ] . args [ 2 ] = ! ! ( lines [ j ] . flags & ML_NOCLIMB ) ;
2021-12-14 18:08:59 +00:00
P_WriteConstant ( MT_ROCKCRUMBLE1 + ( sides [ lines [ j ] . sidenum [ 0 ] ] . rowoffset > > FRACBITS ) , & mapthings [ i ] . stringargs [ 0 ] ) ;
2021-12-13 07:24:52 +00:00
break ;
}
2021-12-28 15:38:52 +00:00
case 1221 : //Minecart saloon door
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
case 1229 : //Minecart switch point
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-27 16:58:18 +00:00
case 1300 : //Flame jet (horizontal)
case 1301 : //Flame jet (vertical)
mapthings [ i ] . args [ 0 ] = ( mapthings [ i ] . angle > > 13 ) * TICRATE / 2 ;
mapthings [ i ] . args [ 1 ] = ( ( mapthings [ i ] . angle > > 10 ) & 7 ) * TICRATE / 2 ;
mapthings [ i ] . args [ 2 ] = 80 - 5 * mapthings [ i ] . extrainfo ;
2021-12-28 21:52:24 +00:00
mapthings [ i ] . args [ 3 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
2021-12-27 16:58:18 +00:00
break ;
2021-12-28 07:19:56 +00:00
case 1304 : //Lavafall
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
mapthings [ i ] . args [ 1 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-28 15:38:52 +00:00
case 1305 : //Rollout Rock
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
break ;
2021-12-28 22:06:48 +00:00
case 1500 : //Glaregoyle
case 1501 : //Glaregoyle (Up)
case 1502 : //Glaregoyle (Down)
case 1503 : //Glaregoyle (Long)
if ( mapthings [ i ] . angle > = 360 )
mapthings [ i ] . args [ 1 ] = 7 * ( mapthings [ i ] . angle / 360 ) + 1 ;
break ;
2021-12-18 09:45:50 +00:00
case 1700 : //Axis
mapthings [ i ] . args [ 2 ] = mapthings [ i ] . angle & 16383 ;
mapthings [ i ] . args [ 3 ] = ! ! ( mapthings [ i ] . angle & 16384 ) ;
/* FALLTHRU */
case 1701 : //Axis transfer
case 1702 : //Axis transfer line
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo ;
mapthings [ i ] . args [ 1 ] = mapthings [ i ] . options ;
break ;
2021-12-21 20:08:40 +00:00
case 1703 : //Ideya drone
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle & 0xFFF ;
mapthings [ i ] . args [ 1 ] = mapthings [ i ] . extrainfo * 32 ;
mapthings [ i ] . args [ 2 ] = ( ( mapthings [ i ] . angle & 0xF000 ) > > 12 ) * 32 ;
if ( ( mapthings [ i ] . options & ( MTF_OBJECTSPECIAL | MTF_EXTRA ) ) = = ( MTF_OBJECTSPECIAL | MTF_EXTRA ) )
mapthings [ i ] . args [ 3 ] = TMDA_BOTTOM ;
else if ( ( mapthings [ i ] . options & ( MTF_OBJECTSPECIAL | MTF_EXTRA ) ) = = MTF_OBJECTSPECIAL )
mapthings [ i ] . args [ 3 ] = TMDA_TOP ;
else if ( ( mapthings [ i ] . options & ( MTF_OBJECTSPECIAL | MTF_EXTRA ) ) = = MTF_EXTRA )
mapthings [ i ] . args [ 3 ] = TMDA_MIDDLE ;
else
mapthings [ i ] . args [ 3 ] = TMDA_BOTTOMOFFSET ;
2021-12-28 12:14:48 +00:00
mapthings [ i ] . args [ 4 ] = ! ! ( mapthings [ i ] . options & MTF_AMBUSH ) ;
2021-12-21 20:08:40 +00:00
break ;
2021-12-19 09:16:03 +00:00
case 1704 : //NiGHTS bumper
mapthings [ i ] . pitch = 30 * ( ( ( mapthings [ i ] . options & 15 ) + 9 ) % 12 ) ;
mapthings [ i ] . options & = ~ 0xF ;
break ;
case 1705 : //Hoop
case 1713 : //Hoop (Customizable)
{
UINT16 oldangle = mapthings [ i ] . angle ;
mapthings [ i ] . angle = ( ( oldangle > > 8 ) * 360 ) / 256 ;
mapthings [ i ] . pitch = ( ( oldangle & 255 ) * 360 ) / 256 ;
mapthings [ i ] . args [ 0 ] = ( mapthings [ i ] . type = = 1705 ) ? 96 : ( mapthings [ i ] . options & 0xF ) * 16 + 32 ;
mapthings [ i ] . options & = ~ 0xF ;
mapthings [ i ] . type = 1713 ;
break ;
}
2021-12-18 09:45:50 +00:00
case 1710 : //Ideya capture
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo ;
mapthings [ i ] . args [ 1 ] = mapthings [ i ] . angle ;
break ;
2021-12-19 09:16:03 +00:00
case 1714 : //Ideya anchor point
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . extrainfo ;
break ;
2021-12-20 22:28:18 +00:00
case 1806 : //King Bowser
mapthings [ i ] . args [ 0 ] = LE_KOOPA ;
break ;
case 1807 : //Axe
mapthings [ i ] . args [ 0 ] = LE_AXE ;
break ;
2021-12-28 07:19:56 +00:00
case 2000 : //Smashing spikeball
mapthings [ i ] . args [ 0 ] = mapthings [ i ] . angle ;
break ;
2021-12-27 17:52:46 +00:00
case 2006 : //Jack-o'-lantern 1
case 2007 : //Jack-o'-lantern 2
case 2008 : //Jack-o'-lantern 3
mapthings [ i ] . args [ 0 ] = ! ! ( mapthings [ i ] . options & MTF_EXTRA ) ;
break ;
2020-01-25 09:01:01 +00:00
default :
break ;
}
}
2020-01-05 13:31:56 +00:00
}
2019-12-28 10:30:39 +00:00
/** Compute MD5 message digest for bytes read from memory source
*
* The resulting message digest number will be written into the 16 bytes
* beginning at RESBLOCK .
*
* \ param filename path of file
* \ param resblock resulting MD5 checksum
* \ return 0 if MD5 checksum was made , and is at resblock , 1 if error was found
*/
2019-12-28 15:40:35 +00:00
static INT32 P_MakeBufferMD5 ( const char * buffer , size_t len , void * resblock )
2019-12-28 10:30:39 +00:00
{
# ifdef NOMD5
( void ) buffer ;
( void ) len ;
memset ( resblock , 0x00 , 16 ) ;
return 1 ;
# else
tic_t t = I_GetTime ( ) ;
CONS_Debug ( DBG_SETUP , " Making MD5 \n " ) ;
if ( md5_buffer ( buffer , len , resblock ) = = NULL )
return 1 ;
CONS_Debug ( DBG_SETUP , " MD5 calc took %f seconds \n " , ( float ) ( I_GetTime ( ) - t ) / NEWTICRATE ) ;
return 0 ;
# endif
}
2019-12-28 15:40:35 +00:00
static void P_MakeMapMD5 ( virtres_t * virt , void * dest )
2019-12-28 10:30:39 +00:00
{
unsigned char resmd5 [ 16 ] ;
2019-12-30 11:07:54 +00:00
2020-03-15 15:23:15 +00:00
if ( udmf )
{
virtlump_t * textmap = vres_Find ( virt , " TEXTMAP " ) ;
2019-12-30 11:07:54 +00:00
P_MakeBufferMD5 ( ( char * ) textmap - > data , textmap - > size , resmd5 ) ;
2020-03-15 15:23:15 +00:00
}
2019-12-30 11:07:54 +00:00
else
{
unsigned char linemd5 [ 16 ] ;
unsigned char sectormd5 [ 16 ] ;
unsigned char thingmd5 [ 16 ] ;
unsigned char sidedefmd5 [ 16 ] ;
UINT8 i ;
// Create a hash for the current map
// get the actual lumps!
virtlump_t * virtlines = vres_Find ( virt , " LINEDEFS " ) ;
virtlump_t * virtsectors = vres_Find ( virt , " SECTORS " ) ;
virtlump_t * virtmthings = vres_Find ( virt , " THINGS " ) ;
virtlump_t * virtsides = vres_Find ( virt , " SIDEDEFS " ) ;
P_MakeBufferMD5 ( ( char * ) virtlines - > data , virtlines - > size , linemd5 ) ;
P_MakeBufferMD5 ( ( char * ) virtsectors - > data , virtsectors - > size , sectormd5 ) ;
P_MakeBufferMD5 ( ( char * ) virtmthings - > data , virtmthings - > size , thingmd5 ) ;
P_MakeBufferMD5 ( ( char * ) virtsides - > data , virtsides - > size , sidedefmd5 ) ;
for ( i = 0 ; i < 16 ; i + + )
resmd5 [ i ] = ( linemd5 [ i ] + sectormd5 [ i ] + thingmd5 [ i ] + sidedefmd5 [ i ] ) & 0xFF ;
}
2019-12-28 10:30:39 +00:00
M_Memcpy ( dest , & resmd5 , 16 ) ;
}
2019-12-30 13:47:48 +00:00
static boolean P_LoadMapFromFile ( void )
2019-12-28 10:30:39 +00:00
{
virtres_t * virt = vres_GetMap ( lastloadedmaplumpnum ) ;
2020-01-05 13:31:56 +00:00
virtlump_t * textmap = vres_Find ( virt , " TEXTMAP " ) ;
2020-04-17 20:29:26 +00:00
size_t i ;
2020-03-15 15:23:15 +00:00
udmf = textmap ! = NULL ;
2019-12-28 10:30:39 +00:00
2019-12-30 13:47:48 +00:00
if ( ! P_LoadMapData ( virt ) )
return false ;
2019-12-28 10:30:39 +00:00
P_LoadMapBSP ( virt ) ;
P_LoadMapLUT ( virt ) ;
2019-12-28 16:40:08 +00:00
P_LinkMapData ( ) ;
2019-12-28 10:30:39 +00:00
2021-04-26 23:27:39 +00:00
if ( ! udmf )
P_AddBinaryMapTags ( ) ;
2020-07-10 14:51:11 +00:00
Taglist_InitGlobalTables ( ) ;
2020-05-04 20:40:49 +00:00
2020-03-15 15:23:15 +00:00
if ( ! udmf )
2020-01-05 13:31:56 +00:00
P_ConvertBinaryMap ( ) ;
2020-01-04 10:08:05 +00:00
// Copy relevant map data for NetArchive purposes.
spawnsectors = Z_Calloc ( numsectors * sizeof ( * sectors ) , PU_LEVEL , NULL ) ;
spawnlines = Z_Calloc ( numlines * sizeof ( * lines ) , PU_LEVEL , NULL ) ;
spawnsides = Z_Calloc ( numsides * sizeof ( * sides ) , PU_LEVEL , NULL ) ;
memcpy ( spawnsectors , sectors , numsectors * sizeof ( * sectors ) ) ;
memcpy ( spawnlines , lines , numlines * sizeof ( * lines ) ) ;
memcpy ( spawnsides , sides , numsides * sizeof ( * sides ) ) ;
2020-04-17 20:29:26 +00:00
for ( i = 0 ; i < numsectors ; i + + )
if ( sectors [ i ] . tags . count )
spawnsectors [ i ] . tags . tags = memcpy ( Z_Malloc ( sectors [ i ] . tags . count * sizeof ( mtag_t ) , PU_LEVEL , NULL ) , sectors [ i ] . tags . tags , sectors [ i ] . tags . count * sizeof ( mtag_t ) ) ;
2019-12-28 10:30:39 +00:00
P_MakeMapMD5 ( virt , & mapmd5 ) ;
vres_Free ( virt ) ;
2019-12-30 13:47:48 +00:00
return true ;
2019-12-28 10:30:39 +00:00
}
2019-12-28 15:40:35 +00:00
//
// LEVEL INITIALIZATION FUNCTIONS
//
2014-03-15 16:59:03 +00:00
/** Sets up a sky texture to use for the level.
* The sky texture is used instead of F_SKY1 .
*/
void P_SetupLevelSky ( INT32 skynum , boolean global )
{
char skytexname [ 12 ] ;
sprintf ( skytexname , " SKY%d " , skynum ) ;
skytexture = R_TextureNumForName ( skytexname ) ;
levelskynum = skynum ;
// Global change
if ( global )
globallevelskynum = levelskynum ;
// Don't go beyond for dedicated servers
if ( dedicated )
return ;
// scale up the old skies, if needed
R_SetupSkyDraw ( ) ;
}
static const char * maplumpname ;
lumpnum_t lastloadedmaplumpnum ; // for comparative savegame
//
// P_LevelInitStuff
//
// Some player initialization for map start.
//
2019-12-28 11:48:32 +00:00
static void P_InitLevelSettings ( void )
2014-03-15 16:59:03 +00:00
{
INT32 i ;
2017-05-30 19:31:51 +00:00
boolean canresetlives = true ;
2014-03-15 16:59:03 +00:00
leveltime = 0 ;
2019-08-04 15:34:55 +00:00
modulothing = 0 ;
2014-03-15 16:59:03 +00:00
// special stage tokens, emeralds, and ring total
tokenbits = 0 ;
runemeraldmanager = false ;
2015-05-27 08:01:58 +00:00
emeraldspawndelay = 60 * TICRATE ;
2019-11-14 18:25:19 +00:00
if ( ( netgame | | multiplayer ) & & ! G_IsSpecialStage ( gamemap ) )
nummaprings = - 1 ;
else
nummaprings = mapheaderinfo [ gamemap - 1 ] - > startrings ;
2014-03-15 16:59:03 +00:00
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL ;
// map time limit
if ( mapheaderinfo [ gamemap - 1 ] - > countdown )
2017-07-04 13:58:58 +00:00
{
tic_t maxtime = 0 ;
2014-03-15 16:59:03 +00:00
countdowntimer = mapheaderinfo [ gamemap - 1 ] - > countdown * TICRATE ;
2017-07-04 13:58:58 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
if ( players [ i ] . starposttime > maxtime )
maxtime = players [ i ] . starposttime ;
}
countdowntimer - = maxtime ;
}
2014-03-15 16:59:03 +00:00
else
countdowntimer = 0 ;
countdowntimeup = false ;
// clear ctf pointers
redflag = blueflag = NULL ;
rflagpoint = bflagpoint = NULL ;
// circuit, race and competition stuff
circuitmap = false ;
numstarposts = 0 ;
2018-06-03 21:41:54 +00:00
ssspheres = timeinmap = 0 ;
2014-03-15 16:59:03 +00:00
2021-04-18 16:59:49 +00:00
// Assume Special Stages were failed in unless proven otherwise - via P_GiveEmerald or emerald touchspecial
2021-04-19 21:20:34 +00:00
// Normal stages will default to be OK, until a Lua script / linedef executor says otherwise.
2021-04-18 16:59:49 +00:00
stagefailed = G_IsSpecialStage ( gamemap ) ;
2014-03-15 16:59:03 +00:00
// Reset temporary record data
memset ( & ntemprecords , 0 , sizeof ( nightsdata_t ) ) ;
// earthquake camera
memset ( & quake , 0 , sizeof ( struct quake ) ) ;
2019-12-27 20:14:56 +00:00
if ( ( netgame | | multiplayer ) & & G_GametypeUsesCoopStarposts ( ) & & cv_coopstarposts . value = = 2 )
2017-05-30 19:31:51 +00:00
{
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( playeringame [ i ] & & players [ i ] . lives > 0 )
{
canresetlives = false ;
break ;
}
}
}
2019-06-29 19:55:58 +00:00
countdown = countdown2 = exitfadestarted = 0 ;
2018-06-09 17:06:14 +00:00
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
2019-09-18 15:06:13 +00:00
G_PlayerReborn ( i , true ) ;
2019-12-27 15:28:00 +00:00
if ( canresetlives & & ( netgame | | multiplayer ) & & playeringame [ i ] & & ( G_CompetitionGametype ( ) | | players [ i ] . lives < = 0 ) )
2014-03-15 16:59:03 +00:00
{
// In Co-Op, replenish a user's lives if they are depleted.
players [ i ] . lives = cv_startinglives . value ;
}
2018-06-09 17:06:14 +00:00
// obliteration station...
2019-09-18 15:06:13 +00:00
players [ i ] . numboxes = players [ i ] . totalring = \
players [ i ] . laps = players [ i ] . marescore = players [ i ] . lastmarescore = \
players [ i ] . mare = players [ i ] . exiting = 0 ;
2014-03-15 16:59:03 +00:00
players [ i ] . drillmeter = 40 * 20 ;
2018-06-09 17:06:14 +00:00
// hit these too
2019-09-18 15:06:13 +00:00
players [ i ] . pflags & = ~ ( PF_GAMETYPEOVER ) ;
2014-03-15 16:59:03 +00:00
}
2019-09-18 15:06:13 +00:00
if ( botingame )
2019-12-30 20:01:14 +00:00
CV_SetValue ( & cv_analog [ 1 ] , true ) ;
2014-03-15 16:59:03 +00:00
}
2019-12-28 13:13:26 +00:00
// Respawns all the mapthings and mobjs in the map from the already loaded map data.
void P_RespawnThings ( void )
2014-03-15 16:59:03 +00:00
{
// Search through all the thinkers.
thinker_t * think ;
2017-06-25 16:30:53 +00:00
INT32 i , viewid = - 1 , centerid = - 1 ; // for skyboxes
// check if these are any of the normal viewpoint/centerpoint mobjs in the level or not
if ( skyboxmo [ 0 ] | | skyboxmo [ 1 ] )
for ( i = 0 ; i < 16 ; i + + )
{
if ( skyboxmo [ 0 ] & & skyboxmo [ 0 ] = = skyboxviewpnts [ i ] )
viewid = i ; // save id just in case
if ( skyboxmo [ 1 ] & & skyboxmo [ 1 ] = = skyboxcenterpnts [ i ] )
centerid = i ; // save id just in case
}
2019-04-20 21:29:20 +00:00
for ( think = thlist [ THINK_MOBJ ] . next ; think ! = & thlist [ THINK_MOBJ ] ; think = think - > next )
2014-03-15 16:59:03 +00:00
{
2019-07-12 23:42:03 +00:00
if ( think - > function . acp1 = = ( actionf_p1 ) P_RemoveThinkerDelayed )
continue ;
P_RemoveMobj ( ( mobj_t * ) think ) ;
2014-03-15 16:59:03 +00:00
}
2019-12-28 11:48:32 +00:00
P_InitLevelSettings ( ) ;
2014-03-15 16:59:03 +00:00
2020-01-31 14:57:04 +00:00
localaiming = 0 ;
localaiming2 = 0 ;
2019-12-28 10:30:39 +00:00
P_SpawnMapThings ( true ) ;
2017-06-25 16:30:53 +00:00
// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
skyboxmo [ 0 ] = skyboxviewpnts [ ( viewid > = 0 ) ? viewid : 0 ] ;
skyboxmo [ 1 ] = skyboxcenterpnts [ ( centerid > = 0 ) ? centerid : 0 ] ;
2014-03-15 16:59:03 +00:00
}
2014-08-27 03:56:30 +00:00
static void P_RunLevelScript ( const char * scriptname )
{
if ( ! ( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_SCRIPTISFILE ) )
{
lumpnum_t lumpnum ;
char newname [ 9 ] ;
strncpy ( newname , scriptname , 8 ) ;
newname [ 8 ] = ' \0 ' ;
lumpnum = W_CheckNumForName ( newname ) ;
if ( lumpnum = = LUMPERROR | | W_LumpLength ( lumpnum ) = = 0 )
{
CONS_Debug ( DBG_SETUP , " SOC Error: script lump %s not found/not valid. \n " , newname ) ;
return ;
}
COM_BufInsertText ( W_CacheLumpNum ( lumpnum , PU_CACHE ) ) ;
}
else
{
COM_BufAddText ( va ( " exec %s \n " , scriptname ) ) ;
}
COM_BufExecute ( ) ; // Run it!
}
static void P_ForceCharacter ( const char * forcecharskin )
{
if ( netgame )
{
char skincmd [ 33 ] ;
if ( splitscreen )
{
sprintf ( skincmd , " skin2 %s \n " , forcecharskin ) ;
CV_Set ( & cv_skin2 , forcecharskin ) ;
}
sprintf ( skincmd , " skin %s \n " , forcecharskin ) ;
COM_BufAddText ( skincmd ) ;
}
else
{
if ( splitscreen )
{
SetPlayerSkin ( secondarydisplayplayer , forcecharskin ) ;
if ( ( unsigned ) cv_playercolor2 . value ! = skins [ players [ secondarydisplayplayer ] . skin ] . prefcolor )
{
CV_StealthSetValue ( & cv_playercolor2 , skins [ players [ secondarydisplayplayer ] . skin ] . prefcolor ) ;
players [ secondarydisplayplayer ] . skincolor = skins [ players [ secondarydisplayplayer ] . skin ] . prefcolor ;
}
}
SetPlayerSkin ( consoleplayer , forcecharskin ) ;
// normal player colors in single player
if ( ( unsigned ) cv_playercolor . value ! = skins [ players [ consoleplayer ] . skin ] . prefcolor )
{
CV_StealthSetValue ( & cv_playercolor , skins [ players [ consoleplayer ] . skin ] . prefcolor ) ;
players [ consoleplayer ] . skincolor = skins [ players [ consoleplayer ] . skin ] . prefcolor ;
}
}
}
2019-12-28 10:37:56 +00:00
static void P_ResetSpawnpoints ( void )
{
UINT8 i ;
numdmstarts = numredctfstarts = numbluectfstarts = 0 ;
// reset the player starts
for ( i = 0 ; i < MAXPLAYERS ; i + + )
playerstarts [ i ] = bluectfstarts [ i ] = redctfstarts [ i ] = NULL ;
for ( i = 0 ; i < MAX_DM_STARTS ; i + + )
deathmatchstarts [ i ] = NULL ;
for ( i = 0 ; i < 2 ; i + + )
skyboxmo [ i ] = NULL ;
for ( i = 0 ; i < 16 ; i + + )
skyboxviewpnts [ i ] = skyboxcenterpnts [ i ] = NULL ;
}
2014-08-27 03:56:30 +00:00
static void P_LoadRecordGhosts ( void )
{
const size_t glen = strlen ( srb2home ) + 1 + strlen ( " replay " ) + 1 + strlen ( timeattackfolder ) + 1 + strlen ( " MAPXX " ) + 1 ;
char * gpath = malloc ( glen ) ;
INT32 i ;
if ( ! gpath )
return ;
sprintf ( gpath , " %s " PATHSEP " replay " PATHSEP " %s " PATHSEP " %s " , srb2home , timeattackfolder , G_BuildMapName ( gamemap ) ) ;
// Best Score ghost
if ( cv_ghost_bestscore . value )
{
for ( i = 0 ; i < numskins ; + + i )
{
if ( cv_ghost_bestscore . value = = 1 & & players [ consoleplayer ] . skin ! = i )
continue ;
if ( FIL_FileExists ( va ( " %s-%s-score-best.lmp " , gpath , skins [ i ] . name ) ) )
G_AddGhost ( va ( " %s-%s-score-best.lmp " , gpath , skins [ i ] . name ) ) ;
}
}
// Best Time ghost
if ( cv_ghost_besttime . value )
{
for ( i = 0 ; i < numskins ; + + i )
{
if ( cv_ghost_besttime . value = = 1 & & players [ consoleplayer ] . skin ! = i )
continue ;
if ( FIL_FileExists ( va ( " %s-%s-time-best.lmp " , gpath , skins [ i ] . name ) ) )
G_AddGhost ( va ( " %s-%s-time-best.lmp " , gpath , skins [ i ] . name ) ) ;
}
}
// Best Rings ghost
if ( cv_ghost_bestrings . value )
{
for ( i = 0 ; i < numskins ; + + i )
{
if ( cv_ghost_bestrings . value = = 1 & & players [ consoleplayer ] . skin ! = i )
continue ;
if ( FIL_FileExists ( va ( " %s-%s-rings-best.lmp " , gpath , skins [ i ] . name ) ) )
G_AddGhost ( va ( " %s-%s-rings-best.lmp " , gpath , skins [ i ] . name ) ) ;
}
}
// Last ghost
if ( cv_ghost_last . value )
{
for ( i = 0 ; i < numskins ; + + i )
{
if ( cv_ghost_last . value = = 1 & & players [ consoleplayer ] . skin ! = i )
continue ;
if ( FIL_FileExists ( va ( " %s-%s-last.lmp " , gpath , skins [ i ] . name ) ) )
G_AddGhost ( va ( " %s-%s-last.lmp " , gpath , skins [ i ] . name ) ) ;
}
}
// Guest ghost
if ( cv_ghost_guest . value & & FIL_FileExists ( va ( " %s-guest.lmp " , gpath ) ) )
G_AddGhost ( va ( " %s-guest.lmp " , gpath ) ) ;
free ( gpath ) ;
}
2014-11-12 00:55:07 +00:00
static void P_LoadNightsGhosts ( void )
{
const size_t glen = strlen ( srb2home ) + 1 + strlen ( " replay " ) + 1 + strlen ( timeattackfolder ) + 1 + strlen ( " MAPXX " ) + 1 ;
char * gpath = malloc ( glen ) ;
2020-06-28 20:59:36 +00:00
INT32 i ;
2014-11-12 00:55:07 +00:00
if ( ! gpath )
return ;
sprintf ( gpath , " %s " PATHSEP " replay " PATHSEP " %s " PATHSEP " %s " , srb2home , timeattackfolder , G_BuildMapName ( gamemap ) ) ;
// Best Score ghost
2020-06-28 20:59:36 +00:00
if ( cv_ghost_bestscore . value )
{
for ( i = 0 ; i < numskins ; + + i )
{
if ( cv_ghost_bestscore . value = = 1 & & players [ consoleplayer ] . skin ! = i )
continue ;
if ( FIL_FileExists ( va ( " %s-%s-score-best.lmp " , gpath , skins [ i ] . name ) ) )
G_AddGhost ( va ( " %s-%s-score-best.lmp " , gpath , skins [ i ] . name ) ) ;
}
}
2014-11-12 00:55:07 +00:00
// Best Time ghost
2020-06-28 20:59:36 +00:00
if ( cv_ghost_besttime . value )
{
for ( i = 0 ; i < numskins ; + + i )
{
if ( cv_ghost_besttime . value = = 1 & & players [ consoleplayer ] . skin ! = i )
continue ;
if ( FIL_FileExists ( va ( " %s-%s-time-best.lmp " , gpath , skins [ i ] . name ) ) )
G_AddGhost ( va ( " %s-%s-time-best.lmp " , gpath , skins [ i ] . name ) ) ;
}
}
2014-11-12 00:55:07 +00:00
// Last ghost
2020-06-28 20:59:36 +00:00
if ( cv_ghost_last . value )
{
for ( i = 0 ; i < numskins ; + + i )
{
if ( cv_ghost_last . value = = 1 & & players [ consoleplayer ] . skin ! = i )
continue ;
if ( FIL_FileExists ( va ( " %s-%s-last.lmp " , gpath , skins [ i ] . name ) ) )
G_AddGhost ( va ( " %s-%s-last.lmp " , gpath , skins [ i ] . name ) ) ;
}
}
2014-11-12 00:55:07 +00:00
// Guest ghost
if ( cv_ghost_guest . value & & FIL_FileExists ( va ( " %s-guest.lmp " , gpath ) ) )
G_AddGhost ( va ( " %s-guest.lmp " , gpath ) ) ;
free ( gpath ) ;
}
2019-12-28 10:30:39 +00:00
static void P_InitTagGametype ( void )
{
UINT8 i ;
INT32 realnumplayers = 0 ;
INT32 playersactive [ MAXPLAYERS ] ;
//I just realized how problematic this code can be.
//D_NumPlayers() will not always cover the scope of the netgame.
//What if one player is node 0 and the other node 31?
//The solution? Make a temp array of all players that are currently playing and pick from them.
//Future todo? When a player leaves, shift all nodes down so D_NumPlayers() can be used as intended?
//Also, you'd never have to loop through all 32 players slots to find anything ever again.
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
2020-02-23 22:28:16 +00:00
if ( playeringame [ i ] & & ! ( players [ i ] . spectator | | players [ i ] . quittime ) )
2019-12-28 10:30:39 +00:00
{
playersactive [ realnumplayers ] = i ; //stores the player's node in the array.
realnumplayers + + ;
}
}
if ( ! realnumplayers ) //this should also fix the dedicated crash bug. You only pick a player if one exists to be picked.
{
CONS_Printf ( M_GetText ( " No player currently available to become IT. Awaiting available players. \n " ) ) ;
return ;
}
i = P_RandomKey ( realnumplayers ) ;
players [ playersactive [ i ] ] . pflags | = PF_TAGIT ; //choose our initial tagger before map starts.
// Taken and modified from G_DoReborn()
// Remove the player so he can respawn elsewhere.
// first disassociate the corpse
if ( players [ playersactive [ i ] ] . mo )
P_RemoveMobj ( players [ playersactive [ i ] ] . mo ) ;
2020-01-22 02:57:22 +00:00
G_SpawnPlayer ( playersactive [ i ] ) ; //respawn the lucky player in his dedicated spawn location.
2019-12-28 10:30:39 +00:00
}
2018-11-12 20:07:45 +00:00
static void P_SetupCamera ( void )
{
if ( players [ displayplayer ] . mo & & ( server | | addedtogame ) )
{
camera . x = players [ displayplayer ] . mo - > x ;
camera . y = players [ displayplayer ] . mo - > y ;
camera . z = players [ displayplayer ] . mo - > z ;
camera . angle = players [ displayplayer ] . mo - > angle ;
camera . subsector = R_PointInSubsector ( camera . x , camera . y ) ; // make sure camera has a subsector set -- Monster Iestyn (12/11/18)
}
else
{
mapthing_t * thing ;
2019-12-27 15:14:33 +00:00
if ( gametyperules & GTR_DEATHMATCHSTARTS )
2018-11-12 20:07:45 +00:00
thing = deathmatchstarts [ 0 ] ;
2019-12-27 05:07:13 +00:00
else
2018-11-12 20:07:45 +00:00
thing = playerstarts [ 0 ] ;
if ( thing )
{
camera . x = thing - > x ;
camera . y = thing - > y ;
camera . z = thing - > z ;
camera . angle = FixedAngle ( ( fixed_t ) thing - > angle < < FRACBITS ) ;
camera . subsector = R_PointInSubsector ( camera . x , camera . y ) ; // make sure camera has a subsector set -- Monster Iestyn (12/11/18)
}
}
}
2019-12-28 10:30:39 +00:00
static void P_InitCamera ( void )
{
if ( ! dedicated )
{
P_SetupCamera ( ) ;
// Salt: CV_ClearChangedFlags() messes with your settings :(
/*if (!cv_cam_height.changed)
CV_Set ( & cv_cam_height , cv_cam_height . defaultvalue ) ;
if ( ! cv_cam2_height . changed )
CV_Set ( & cv_cam2_height , cv_cam2_height . defaultvalue ) ;
if ( ! cv_cam_dist . changed )
CV_Set ( & cv_cam_dist , cv_cam_dist . defaultvalue ) ;
if ( ! cv_cam2_dist . changed )
CV_Set ( & cv_cam2_dist , cv_cam2_dist . defaultvalue ) ; */
// Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P
if ( ! cv_cam_rotate . changed )
CV_Set ( & cv_cam_rotate , cv_cam_rotate . defaultvalue ) ;
if ( ! cv_cam2_rotate . changed )
CV_Set ( & cv_cam2_rotate , cv_cam2_rotate . defaultvalue ) ;
2019-12-31 18:58:36 +00:00
if ( ! cv_analog [ 0 ] . changed )
CV_SetValue ( & cv_analog [ 0 ] , 0 ) ;
if ( ! cv_analog [ 1 ] . changed )
CV_SetValue ( & cv_analog [ 1 ] , 0 ) ;
2019-12-28 10:30:39 +00:00
displayplayer = consoleplayer ; // Start with your OWN view, please!
}
if ( twodlevel )
{
2019-12-31 18:58:36 +00:00
CV_SetValue ( & cv_analog [ 0 ] , false ) ;
CV_SetValue ( & cv_analog [ 1 ] , false ) ;
2019-12-28 10:30:39 +00:00
}
else
{
2019-12-31 18:58:36 +00:00
if ( cv_useranalog [ 0 ] . value )
CV_SetValue ( & cv_analog [ 0 ] , true ) ;
2019-12-28 10:30:39 +00:00
2019-12-31 18:58:36 +00:00
if ( ( splitscreen & & cv_useranalog [ 1 ] . value ) | | botingame )
CV_SetValue ( & cv_analog [ 1 ] , true ) ;
2019-12-28 10:30:39 +00:00
}
}
static void P_RunSpecialStageWipe ( void )
{
tic_t starttime = I_GetTime ( ) ;
tic_t endtime = starttime + ( 3 * TICRATE ) / 2 ;
tic_t nowtime ;
S_StartSound ( NULL , sfx_s3kaf ) ;
// Fade music! Time it to S3KAF: 0.25 seconds is snappy.
if ( RESETMUSIC | |
strnicmp ( S_MusicName ( ) ,
( mapmusflags & MUSIC_RELOADRESET ) ? mapheaderinfo [ gamemap - 1 ] - > musname : mapmusname , 7 ) )
S_FadeOutStopMusic ( MUSICRATE / 4 ) ; //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)
F_WipeStartScreen ( ) ;
wipestyleflags | = ( WSF_FADEOUT | WSF_TOWHITE ) ;
# ifdef HWRENDER
// uh..........
if ( rendermode = = render_opengl )
F_WipeColorFill ( 0 ) ;
# endif
F_WipeEndScreen ( ) ;
F_RunWipe ( wipedefs [ wipe_speclevel_towhite ] , false ) ;
I_OsPolling ( ) ;
I_FinishUpdate ( ) ; // page flip or blit buffer
if ( moviemode )
M_SaveFrame ( ) ;
nowtime = lastwipetic ;
// Hold on white for extra effect.
while ( nowtime < endtime )
{
// wait loop
while ( ! ( ( nowtime = I_GetTime ( ) ) - lastwipetic ) )
I_Sleep ( ) ;
lastwipetic = nowtime ;
if ( moviemode ) // make sure we save frames for the white hold too
M_SaveFrame ( ) ;
}
}
static void P_RunLevelWipe ( void )
{
F_WipeStartScreen ( ) ;
wipestyleflags | = WSF_FADEOUT ;
# ifdef HWRENDER
// uh..........
if ( rendermode = = render_opengl )
F_WipeColorFill ( 31 ) ;
# endif
F_WipeEndScreen ( ) ;
// for titlemap: run a specific wipe if specified
// needed for exiting time attack
if ( wipetypepre ! = INT16_MAX )
F_RunWipe (
( wipetypepre > = 0 & & F_WipeExists ( wipetypepre ) ) ? wipetypepre : wipedefs [ wipe_level_toblack ] ,
false ) ;
wipetypepre = - 1 ;
}
static void P_InitPlayers ( void )
{
UINT8 i ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
// Start players with pity shields if possible
players [ i ] . pity = - 1 ;
players [ i ] . mo = NULL ;
if ( ! G_PlatformGametype ( ) )
G_DoReborn ( i ) ;
else // gametype is GT_COOP or GT_RACE
{
2020-01-22 02:57:22 +00:00
G_SpawnPlayer ( i ) ;
2019-12-28 10:30:39 +00:00
if ( players [ i ] . starposttime )
P_ClearStarPost ( players [ i ] . starpostnum ) ;
}
}
}
static void P_WriteLetter ( void )
{
char * buf , * b ;
if ( ! unlockables [ 27 ] . unlocked ) // pandora's box
return ;
if ( modeattacking )
return ;
# ifndef DEVELOP
if ( modifiedgame )
return ;
# endif
if ( netgame | | multiplayer )
return ;
if ( gamemap ! = 0x1d35 - 016464 )
return ;
P_SpawnMobj ( 0640370000 , 0x11000000 , 0x3180000 , MT_LETTER ) - > angle = ANGLE_90 ;
if ( textprompts [ 199 ] - > page [ 1 ] . backcolor = = 259 )
return ;
buf = W_CacheLumpName ( " WATERMAP " , PU_STATIC ) ;
b = buf ;
while ( ( * b ! = 65 ) & & ( b - buf < 256 ) )
{
* b = ( * b - 65 ) & 255 ;
b + + ;
}
* b = ' \0 ' ;
Z_Free ( textprompts [ 199 ] - > page [ 1 ] . text ) ;
textprompts [ 199 ] - > page [ 1 ] . text = Z_StrDup ( buf ) ;
textprompts [ 199 ] - > page [ 1 ] . lines = 4 ;
textprompts [ 199 ] - > page [ 1 ] . backcolor = 259 ;
Z_Free ( buf ) ;
}
2019-12-28 10:37:56 +00:00
static void P_InitGametype ( void )
{
UINT8 i ;
P_InitPlayers ( ) ;
// restore time in netgame (see also g_game.c)
2019-12-29 00:39:38 +00:00
if ( ( netgame | | multiplayer ) & & G_GametypeUsesCoopStarposts ( ) & & cv_coopstarposts . value = = 2 )
2019-12-28 10:37:56 +00:00
{
// is this a hack? maybe
tic_t maxstarposttime = 0 ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( playeringame [ i ] & & players [ i ] . starposttime > maxstarposttime )
maxstarposttime = players [ i ] . starposttime ;
}
leveltime = maxstarposttime ;
}
P_WriteLetter ( ) ;
if ( modeattacking = = ATTACKING_RECORD & & ! demoplayback )
P_LoadRecordGhosts ( ) ;
else if ( modeattacking = = ATTACKING_NIGHTS & & ! demoplayback )
P_LoadNightsGhosts ( ) ;
if ( G_TagGametype ( ) )
P_InitTagGametype ( ) ;
2020-02-29 02:47:38 +00:00
else if ( ( ( gametyperules & ( GTR_RACE | GTR_LIVES ) ) = = GTR_RACE ) & & server )
2019-12-28 10:37:56 +00:00
CV_StealthSetValue ( & cv_numlaps ,
( cv_basenumlaps . value )
? cv_basenumlaps . value
: mapheaderinfo [ gamemap - 1 ] - > numlaps ) ;
}
2014-03-15 16:59:03 +00:00
/** Loads a level from a lump or external wad.
*
2019-12-28 11:48:32 +00:00
* \ param fromnetsave If true , skip some stuff because we ' re loading a netgame snapshot .
2014-03-15 16:59:03 +00:00
* \ todo Clean up , refactor , split up ; get rid of the bloat .
*/
2020-01-31 14:57:04 +00:00
boolean P_LoadLevel ( boolean fromnetsave , boolean reloadinggamestate )
2014-03-15 16:59:03 +00:00
{
// use gamemap to get map number.
// 99% of the things already did, so.
// Map header should always be in place at this point
2019-12-28 11:48:32 +00:00
INT32 i , ranspecialwipe = 0 ;
2014-03-15 16:59:03 +00:00
sector_t * ss ;
levelloading = true ;
// This is needed. Don't touch.
maptol = mapheaderinfo [ gamemap - 1 ] - > typeoflevel ;
2019-12-31 17:00:25 +00:00
gametyperules = gametypedefaultrules [ gametype ] ;
2014-03-15 16:59:03 +00:00
CON_Drawer ( ) ; // let the user know what we are going to do
I_FinishUpdate ( ) ; // page flip or blit buffer
// Reset the palette
if ( rendermode ! = render_none )
V_SetPaletteLump ( " PLAYPAL " ) ;
// Initialize sector node list.
P_Initsecnode ( ) ;
if ( netgame | | multiplayer )
cv_debug = botskin = 0 ;
if ( metalplayback )
2014-03-23 16:00:29 +00:00
G_StopMetalDemo ( ) ;
2014-03-15 16:59:03 +00:00
// Clear CECHO messages
HU_ClearCEcho ( ) ;
if ( mapheaderinfo [ gamemap - 1 ] - > runsoc [ 0 ] ! = ' # ' )
P_RunSOC ( mapheaderinfo [ gamemap - 1 ] - > runsoc ) ;
if ( cv_runscripts . value & & mapheaderinfo [ gamemap - 1 ] - > scriptname [ 0 ] ! = ' # ' )
2014-08-27 03:56:30 +00:00
P_RunLevelScript ( mapheaderinfo [ gamemap - 1 ] - > scriptname ) ;
2014-03-15 16:59:03 +00:00
2019-12-28 11:48:32 +00:00
P_InitLevelSettings ( ) ;
2014-03-15 16:59:03 +00:00
postimgtype = postimgtype2 = postimg_none ;
2017-06-25 16:30:53 +00:00
if ( mapheaderinfo [ gamemap - 1 ] - > forcecharacter [ 0 ] ! = ' \0 ' )
2014-08-27 03:56:30 +00:00
P_ForceCharacter ( mapheaderinfo [ gamemap - 1 ] - > forcecharacter ) ;
2014-03-15 16:59:03 +00:00
if ( ! dedicated )
{
2019-12-28 11:48:32 +00:00
// chasecam on in first-person gametypes and 2D
boolean chase = ( ! ( gametyperules & GTR_FIRSTPERSON ) ) | | ( maptol & TOL_2D ) ;
2017-03-26 21:11:04 +00:00
// Salt: CV_ClearChangedFlags() messes with your settings :(
/*if (!cv_cam_speed.changed)
CV_Set ( & cv_cam_speed , cv_cam_speed . defaultvalue ) ; */
2014-03-15 16:59:03 +00:00
2019-12-30 18:10:38 +00:00
CV_UpdateCamDist ( ) ;
CV_UpdateCam2Dist ( ) ;
2014-03-15 16:59:03 +00:00
if ( ! cv_chasecam . changed )
CV_SetValue ( & cv_chasecam , chase ) ;
// same for second player
if ( ! cv_chasecam2 . changed )
CV_SetValue ( & cv_chasecam2 , chase ) ;
}
// Initial height of PointOfView
// will be set by player think.
players [ consoleplayer ] . viewz = 1 ;
2018-06-14 19:17:31 +00:00
// Cancel all d_main.c fadeouts (keep fade in though).
2020-01-31 14:57:04 +00:00
if ( reloadinggamestate )
wipegamestate = gamestate ; // Don't fade if reloading the gamestate
else
wipegamestate = FORCEWIPEOFF ;
2019-09-10 02:31:48 +00:00
wipestyleflags = 0 ;
2018-06-14 19:17:31 +00:00
2020-10-14 15:39:23 +00:00
// Special stage & record attack retry fade to white
2016-01-05 13:03:00 +00:00
// This is handled BEFORE sounds are stopped.
2019-11-23 21:15:09 +00:00
if ( G_GetModeAttackRetryFlag ( ) )
{
2020-10-14 15:39:23 +00:00
if ( modeattacking & & ! demoplayback )
{
ranspecialwipe = 2 ;
2019-11-23 21:15:09 +00:00
wipestyleflags | = ( WSF_FADEOUT | WSF_TOWHITE ) ;
2020-10-14 15:39:23 +00:00
}
2019-11-23 21:15:09 +00:00
G_ClearModeAttackRetryFlag ( ) ;
}
2020-10-14 15:39:23 +00:00
else if ( rendermode ! = render_none & & G_IsSpecialStage ( gamemap ) )
{
P_RunSpecialStageWipe ( ) ;
ranspecialwipe = 1 ;
}
2019-11-23 21:15:09 +00:00
2014-03-15 16:59:03 +00:00
// Make sure all sounds are stopped before Z_FreeTags.
S_StopSounds ( ) ;
S_ClearSfx ( ) ;
2019-08-04 11:03:57 +00:00
// Fade out music here. Deduct 2 tics so the fade volume actually reaches 0.
// But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.
2020-10-27 19:22:15 +00:00
if ( ! ( reloadinggamestate | | titlemapinaction ) & & ( RESETMUSIC | |
2019-08-04 11:03:57 +00:00
strnicmp ( S_MusicName ( ) ,
( mapmusflags & MUSIC_RELOADRESET ) ? mapheaderinfo [ gamemap - 1 ] - > musname : mapmusname , 7 ) ) )
2020-10-27 19:22:15 +00:00
{
2019-08-04 11:03:57 +00:00
S_FadeMusic ( 0 , FixedMul (
FixedDiv ( ( F_GetWipeLength ( wipedefs [ wipe_level_toblack ] ) - 2 ) * NEWTICRATERATIO , NEWTICRATE ) , MUSICRATE ) ) ;
2020-10-27 19:22:15 +00:00
}
2014-03-15 16:59:03 +00:00
// Let's fade to black here
2016-01-05 13:03:00 +00:00
// But only if we didn't do the special stage wipe
2020-01-31 14:57:04 +00:00
if ( rendermode ! = render_none & & ! ( ranspecialwipe | | reloadinggamestate ) )
2019-12-28 10:30:39 +00:00
P_RunLevelWipe ( ) ;
2014-03-15 16:59:03 +00:00
2020-10-27 19:22:15 +00:00
if ( ! ( reloadinggamestate | | titlemapinaction ) )
2016-01-05 13:03:00 +00:00
{
2018-06-14 19:17:31 +00:00
if ( ranspecialwipe = = 2 )
{
2018-06-15 20:42:36 +00:00
pausedelay = - 3 ; // preticker plus one
2018-06-14 19:17:31 +00:00
S_StartSound ( NULL , sfx_s3k73 ) ;
}
2018-06-13 23:58:28 +00:00
2018-06-14 19:17:31 +00:00
// Print "SPEEDING OFF TO [ZONE] [ACT 1]..."
if ( rendermode ! = render_none )
{
// Don't include these in the fade!
char tx [ 64 ] ;
2019-11-25 16:16:46 +00:00
V_DrawSmallString ( 1 , 191 , V_ALLOWLOWERCASE | V_TRANSLUCENT | V_SNAPTOLEFT | V_SNAPTOBOTTOM , M_GetText ( " Speeding off to... " ) ) ;
2018-06-14 19:17:31 +00:00
snprintf ( tx , 63 , " %s%s%s " ,
mapheaderinfo [ gamemap - 1 ] - > lvlttl ,
2019-11-19 13:00:10 +00:00
( mapheaderinfo [ gamemap - 1 ] - > levelflags & LF_NOZONE ) ? " " : " Zone " ,
2019-11-23 17:51:32 +00:00
( mapheaderinfo [ gamemap - 1 ] - > actnum > 0 ) ? va ( " %d " , mapheaderinfo [ gamemap - 1 ] - > actnum ) : " " ) ;
2019-11-25 16:16:46 +00:00
V_DrawSmallString ( 1 , 195 , V_ALLOWLOWERCASE | V_TRANSLUCENT | V_SNAPTOLEFT | V_SNAPTOBOTTOM , tx ) ;
2018-06-14 19:17:31 +00:00
I_UpdateNoVsync ( ) ;
}
2019-08-04 11:03:57 +00:00
// As oddly named as this is, this handles music only.
// We should be fine starting it here.
// Don't do this during titlemap, because the menu code handles music by itself.
S_Start ( ) ;
2014-03-15 16:59:03 +00:00
}
2018-06-14 21:23:20 +00:00
levelfadecol = ( ranspecialwipe ) ? 0 : 31 ;
2018-11-05 03:22:47 +00:00
// Close text prompt before freeing the old level
F_EndTextPrompt ( false , true ) ;
2014-03-15 16:59:03 +00:00
LUA_InvalidateLevel ( ) ;
for ( ss = sectors ; sectors + numsectors ! = ss ; ss + + )
{
Z_Free ( ss - > attached ) ;
Z_Free ( ss - > attachedsolid ) ;
}
// Clear pointers that would be left dangling by the purge
R_FlushTranslationColormapCache ( ) ;
2020-11-22 21:18:26 +00:00
# ifdef HWRENDER
// Free GPU textures before freeing patches.
2021-03-27 23:30:59 +00:00
if ( rendermode = = render_opengl & & ( vid . glstate = = VID_GL_LIBRARY_LOADED ) )
2020-11-22 21:18:26 +00:00
HWR_ClearAllTextures ( ) ;
2014-03-15 16:59:03 +00:00
# endif
2020-09-07 05:23:07 +00:00
Patch_FreeTag ( PU_PATCH_LOWPRIORITY ) ;
2020-10-10 21:43:26 +00:00
Patch_FreeTag ( PU_PATCH_ROTATED ) ;
2014-03-15 16:59:03 +00:00
Z_FreeTags ( PU_LEVEL , PU_PURGELEVEL - 1 ) ;
P_InitThinkers ( ) ;
P_InitCachedActions ( ) ;
2019-12-28 11:48:32 +00:00
if ( ! fromnetsave & & savedata . lives > 0 )
2019-11-30 15:52:41 +00:00
{
numgameovers = savedata . numgameovers ;
players [ consoleplayer ] . continues = savedata . continues ;
players [ consoleplayer ] . lives = savedata . lives ;
players [ consoleplayer ] . score = savedata . score ;
if ( ( botingame = ( ( botskin = savedata . botskin ) ! = 0 ) ) )
botcolor = skins [ botskin - 1 ] . prefcolor ;
emeralds = savedata . emeralds ;
savedata . lives = 0 ;
}
2014-03-15 16:59:03 +00:00
// internal game map
2017-05-16 19:10:02 +00:00
maplumpname = G_BuildMapName ( gamemap ) ;
2017-05-18 19:13:18 +00:00
lastloadedmaplumpnum = W_CheckNumForName ( maplumpname ) ;
2019-12-30 13:45:39 +00:00
if ( lastloadedmaplumpnum = = LUMPERROR )
2017-05-16 19:10:02 +00:00
I_Error ( " Map %s not found. \n " , maplumpname ) ;
2014-03-15 16:59:03 +00:00
R_ReInitColormaps ( mapheaderinfo [ gamemap - 1 ] - > palette ) ;
2016-11-02 21:26:35 +00:00
CON_SetupBackColormap ( ) ;
2014-03-15 16:59:03 +00:00
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky ( mapheaderinfo [ gamemap - 1 ] - > skynum , true ) ;
2019-12-28 10:37:56 +00:00
P_ResetSpawnpoints ( ) ;
2014-03-15 16:59:03 +00:00
2020-05-12 21:50:30 +00:00
P_ResetWaypoints ( ) ;
2021-05-28 17:42:19 +00:00
P_MapStart ( ) ; // tmthing can be used starting from this point
2014-03-15 16:59:03 +00:00
2021-06-02 08:57:57 +00:00
P_InitSlopes ( ) ;
2019-12-30 13:47:48 +00:00
if ( ! P_LoadMapFromFile ( ) )
return false ;
2015-08-04 00:27:10 +00:00
2020-05-04 20:40:49 +00:00
// init anything that P_SpawnSlopes/P_LoadThings needs to know
2017-06-25 13:39:45 +00:00
P_InitSpecials ( ) ;
2020-01-04 09:39:45 +00:00
P_SpawnSlopes ( fromnetsave ) ;
2015-05-16 05:02:01 +00:00
2019-12-28 11:48:32 +00:00
P_SpawnMapThings ( ! fromnetsave ) ;
2017-06-25 13:39:45 +00:00
skyboxmo [ 0 ] = skyboxviewpnts [ 0 ] ;
skyboxmo [ 1 ] = skyboxcenterpnts [ 0 ] ;
2014-03-15 16:59:03 +00:00
for ( numcoopstarts = 0 ; numcoopstarts < MAXPLAYERS ; numcoopstarts + + )
if ( ! playerstarts [ numcoopstarts ] )
break ;
// set up world state
P_SpawnSpecials ( fromnetsave ) ;
2019-12-28 11:48:32 +00:00
if ( ! fromnetsave ) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
2014-03-15 16:59:03 +00:00
P_SpawnPrecipitation ( ) ;
# ifdef HWRENDER // not win32 only 19990829 by Kin
2020-10-15 17:31:16 +00:00
gl_maploaded = false ;
2019-12-17 19:14:26 +00:00
// Lactozilla: Free extrasubsectors regardless of renderer.
2020-08-15 01:27:16 +00:00
HWR_FreeExtraSubsectors ( ) ;
// Create plane polygons.
2019-12-08 06:23:37 +00:00
if ( rendermode = = render_opengl )
2020-08-15 01:27:16 +00:00
HWR_LoadLevel ( ) ;
2014-03-15 16:59:03 +00:00
# endif
2014-08-04 03:49:33 +00:00
// oh god I hope this helps
// (addendum: apparently it does!
// none of this needs to be done because it's not the beginning of the map when
// a netgame save is being loaded, and could actively be harmful by messing with
// the client's view of the data.)
2019-12-28 10:37:56 +00:00
if ( ! fromnetsave )
P_InitGametype ( ) ;
2014-08-04 03:49:33 +00:00
2020-01-31 14:57:04 +00:00
if ( ! reloadinggamestate )
{
P_InitCamera ( ) ;
localaiming = 0 ;
localaiming2 = 0 ;
}
2014-03-15 16:59:03 +00:00
// clear special respawning que
iquehead = iquetail = 0 ;
// Remove the loading shit from the screen
2020-01-31 14:57:04 +00:00
if ( rendermode ! = render_none & & ! ( titlemapinaction | | reloadinggamestate ) )
2019-11-05 15:10:42 +00:00
F_WipeColorFill ( levelfadecol ) ;
2014-03-15 16:59:03 +00:00
if ( precache | | dedicated )
R_PrecacheLevel ( ) ;
nextmapoverride = 0 ;
2019-07-29 13:55:36 +00:00
skipstats = 0 ;
2014-03-15 16:59:03 +00:00
2020-10-06 14:49:53 +00:00
if ( ! ( netgame | | multiplayer | | demoplayback ) & & ( ! modifiedgame | | savemoddata ) )
2014-03-15 16:59:03 +00:00
mapvisited [ gamemap - 1 ] | = MV_VISITED ;
2020-10-06 17:06:06 +00:00
else if ( netgame | | multiplayer )
2017-09-15 19:34:46 +00:00
mapvisited [ gamemap - 1 ] | = MV_MP ; // you want to record that you've been there this session, but not permanently
2014-03-15 16:59:03 +00:00
levelloading = false ;
P_RunCachedActions ( ) ;
2021-05-28 17:56:32 +00:00
P_MapEnd ( ) ; // tmthing is no longer needed from this point onwards
Special saves!
All this refactoring, just to resolve #162. Specifically, it engages savegame events not at level load (except for savefile start) but on level completion, just after you've gotten all the intermission bonuses but before the intermission actually starts.
Also fixes a never-before-discovered bug where if the titlemap has LF_SAVEGAME, your save file will be overwritten upon returning to the title screen. This game is a mess of hacks, I swear...
One unintended side effect: It may actually be faster in some speedrun circumstances in mods with cutscenes to complete the map, exit back to the title screen, and reload the file. It's a common feature of optimal runs in games with cutscenes, though, and Marathon Run has a toggle for cutscenes, so I'm not particularly bothered.
2020-06-22 18:00:47 +00:00
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
if ( ! titlemapinaction )
{
if ( ! lastmaploaded ) // Start a new game?
{
// I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020
2020-07-12 18:00:58 +00:00
if ( ! ( ultimatemode | | netgame | | multiplayer | | demoplayback | | demorecording | | metalrecording | | modeattacking | | marathonmode )
Special saves!
All this refactoring, just to resolve #162. Specifically, it engages savegame events not at level load (except for savefile start) but on level completion, just after you've gotten all the intermission bonuses but before the intermission actually starts.
Also fixes a never-before-discovered bug where if the titlemap has LF_SAVEGAME, your save file will be overwritten upon returning to the title screen. This game is a mess of hacks, I swear...
One unintended side effect: It may actually be faster in some speedrun circumstances in mods with cutscenes to complete the map, exit back to the title screen, and reload the file. It's a common feature of optimal runs in games with cutscenes, though, and Marathon Run has a toggle for cutscenes, so I'm not particularly bothered.
2020-06-22 18:00:47 +00:00
& & ( ! modifiedgame | | savemoddata ) & & cursaveslot > 0 )
G_SaveGame ( ( UINT32 ) cursaveslot , gamemap ) ;
// If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted.
}
lastmaploaded = gamemap ; // HAS to be set after saving!!
}
2017-08-07 03:47:39 +00:00
2019-12-28 11:48:32 +00:00
if ( ! fromnetsave ) // uglier hack
2014-03-15 16:59:03 +00:00
{ // to make a newly loaded level start on the second frame.
INT32 buf = gametic % BACKUPTICS ;
for ( i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( playeringame [ i ] )
G_CopyTiccmd ( & players [ i ] . cmd , & netcmds [ buf ] [ i ] , 1 ) ;
}
P_PreTicker ( 2 ) ;
2021-05-28 17:56:32 +00:00
P_MapStart ( ) ; // just in case MapLoad modifies tmthing
2020-12-12 11:06:57 +00:00
LUA_HookInt ( gamemap , HOOK ( MapLoad ) ) ;
2021-05-28 17:56:32 +00:00
P_MapEnd ( ) ; // just in case MapLoad modifies tmthing
2014-03-15 16:59:03 +00:00
}
2020-01-31 14:57:04 +00:00
// No render mode or reloading gamestate, stop here.
if ( rendermode = = render_none | | reloadinggamestate )
2019-11-18 17:08:47 +00:00
return true ;
2018-06-14 19:17:31 +00:00
2019-11-18 17:08:47 +00:00
// Title card!
2019-11-18 15:56:41 +00:00
G_StartTitleCard ( ) ;
2018-06-14 19:17:31 +00:00
2019-11-18 15:56:41 +00:00
// Can the title card actually run, though?
2019-11-18 17:08:47 +00:00
if ( ! WipeStageTitle )
return true ;
if ( ranspecialwipe = = 2 )
return true ;
2018-06-14 19:17:31 +00:00
2019-11-18 17:08:47 +00:00
// If so...
2020-01-27 02:46:07 +00:00
G_PreLevelTitleCard ( ) ;
2018-06-14 19:17:31 +00:00
2014-03-15 16:59:03 +00:00
return true ;
}
//
// P_RunSOC
//
// Runs a SOC file or a lump, depending on if ".SOC" exists in the filename
//
boolean P_RunSOC ( const char * socfilename )
{
lumpnum_t lump ;
if ( strstr ( socfilename , " .soc " ) ! = NULL )
2018-01-04 20:15:44 +00:00
return P_AddWadFile ( socfilename ) ;
2014-03-15 16:59:03 +00:00
lump = W_CheckNumForName ( socfilename ) ;
if ( lump = = LUMPERROR )
return false ;
CONS_Printf ( M_GetText ( " Loading SOC lump: %s \n " ) , socfilename ) ;
DEH_LoadDehackedLump ( lump ) ;
return true ;
}
2017-05-06 14:52:53 +00:00
// Auxiliary function for PK3 loading - looks for sound replacements.
// NOTE: it does not really add any new sound entry or anything.
void P_LoadSoundsRange ( UINT16 wadnum , UINT16 first , UINT16 num )
{
size_t j ;
lumpinfo_t * lumpinfo = wadfiles [ wadnum ] - > lumpinfo + first ;
for ( ; num > 0 ; num - - , lumpinfo + + )
{
// Let's check whether it's replacing an existing sound or it's a brand new one.
for ( j = 1 ; j < NUMSFX ; j + + )
{
if ( S_sfx [ j ] . name & & ! strnicmp ( S_sfx [ j ] . name , lumpinfo - > name + 2 , 6 ) )
{
// the sound will be reloaded when needed,
// since sfx->data will be NULL
CONS_Debug ( DBG_SETUP , " Sound %.8s replaced \n " , lumpinfo - > name ) ;
I_FreeSfx ( & S_sfx [ j ] ) ;
2018-01-04 21:06:26 +00:00
break ; // there shouldn't be two sounds with the same name, so stop looking
2017-05-06 14:52:53 +00:00
}
}
}
}
2017-06-25 12:02:39 +00:00
// Auxiliary function for PK3 loading - looks for music and music replacements.
// NOTE: does nothing but print debug messages. The code is handled somewhere else.
2017-05-06 14:52:53 +00:00
void P_LoadMusicsRange ( UINT16 wadnum , UINT16 first , UINT16 num )
{
lumpinfo_t * lumpinfo = wadfiles [ wadnum ] - > lumpinfo + first ;
char * name ;
for ( ; num > 0 ; num - - , lumpinfo + + )
{
name = lumpinfo - > name ;
if ( name [ 0 ] = = ' O ' & & name [ 1 ] = = ' _ ' )
{
CONS_Debug ( DBG_SETUP , " Music %.8s replaced \n " , name ) ;
}
else if ( name [ 0 ] = = ' D ' & & name [ 1 ] = = ' _ ' )
{
CONS_Debug ( DBG_SETUP , " Music %.8s replaced \n " , name ) ;
}
}
return ;
}
2017-11-03 03:09:52 +00:00
// Auxiliary function - input a folder name and gives us the resource markers positions.
static lumpinfo_t * FindFolder ( const char * folName , UINT16 * start , UINT16 * end , lumpinfo_t * lumpinfo , UINT16 * pnumlumps , size_t * pi )
{
UINT16 numlumps = * pnumlumps ;
size_t i = * pi ;
2020-04-20 21:40:41 +00:00
if ( ! stricmp ( lumpinfo - > fullname , folName ) )
2017-11-03 03:09:52 +00:00
{
lumpinfo + + ;
* start = + + i ;
for ( ; i < numlumps ; i + + , lumpinfo + + )
2020-04-20 21:40:41 +00:00
if ( strnicmp ( lumpinfo - > fullname , folName , strlen ( folName ) ) )
2017-11-03 03:09:52 +00:00
break ;
lumpinfo - - ;
* end = i - - - * start ;
* pi = i ;
* pnumlumps = numlumps ;
return lumpinfo ;
}
return lumpinfo ;
}
2014-03-15 16:59:03 +00:00
//
// Add a wadfile to the active wad files,
// replace sounds, musics, patches, textures, sprites and maps
//
2021-03-23 02:56:55 +00:00
static boolean P_LoadAddon ( UINT16 wadnum , UINT16 numlumps )
2014-03-15 16:59:03 +00:00
{
size_t i , j , sreplaces = 0 , mreplaces = 0 , digmreplaces = 0 ;
char * name ;
lumpinfo_t * lumpinfo ;
2019-01-07 18:00:27 +00:00
2019-01-07 20:43:58 +00:00
//boolean texturechange = false; ///\todo Useless; broken when back-frontporting PK3 changes?
2018-01-04 20:15:44 +00:00
boolean mapsadded = false ;
2014-03-15 16:59:03 +00:00
boolean replacedcurrentmap = false ;
2017-05-06 14:52:53 +00:00
// Vars to help us with the position start and amount of each resource type.
// Useful for PK3s since they use folders.
// WADs use markers for some resources, but others such as sounds are checked lump-by-lump anyway.
2017-05-16 19:10:02 +00:00
// UINT16 luaPos, luaNum = 0;
// UINT16 socPos, socNum = 0;
2019-12-08 17:35:21 +00:00
UINT16 sfxPos = 0 , sfxNum = 0 ;
2017-10-07 23:10:29 +00:00
UINT16 musPos = 0 , musNum = 0 ;
2017-10-07 22:18:25 +00:00
// UINT16 sprPos, sprNum = 0;
2019-12-08 17:35:21 +00:00
UINT16 texPos = 0 , texNum = 0 ;
2017-05-06 14:52:53 +00:00
// UINT16 patPos, patNum = 0;
// UINT16 flaPos, flaNum = 0;
2017-06-25 12:02:39 +00:00
// UINT16 mapPos, mapNum = 0;
2017-05-06 14:52:53 +00:00
2017-04-30 18:05:26 +00:00
switch ( wadfiles [ wadnum ] - > type )
2014-03-15 16:59:03 +00:00
{
2017-05-06 14:52:53 +00:00
case RET_PK3 :
2021-03-23 02:56:55 +00:00
case RET_FOLDER :
2017-11-03 03:09:52 +00:00
// Look for the lumps that act as resource delimitation markers.
lumpinfo = wadfiles [ wadnum ] - > lumpinfo ;
for ( i = 0 ; i < numlumps ; i + + , lumpinfo + + )
2014-03-15 16:59:03 +00:00
{
2017-11-03 03:09:52 +00:00
// lumpinfo = FindFolder("Lua/", &luaPos, &luaNum, lumpinfo, &numlumps, &i);
2018-06-06 16:11:12 +00:00
// lumpinfo = FindFolder("SOC/", &socPos, &socNum, lumpinfo, &numlumps, &i);
2017-11-03 03:09:52 +00:00
lumpinfo = FindFolder ( " Sounds/ " , & sfxPos , & sfxNum , lumpinfo , & numlumps , & i ) ;
lumpinfo = FindFolder ( " Music/ " , & musPos , & musNum , lumpinfo , & numlumps , & i ) ;
// lumpinfo = FindFolder("Sprites/", &sprPos, &sprNum, lumpinfo, &numlumps, &i);
lumpinfo = FindFolder ( " Textures/ " , & texPos , & texNum , lumpinfo , & numlumps , & i ) ;
// lumpinfo = FindFolder("Patches/", &patPos, &patNum, lumpinfo, &numlumps, &i);
// lumpinfo = FindFolder("Flats/", &flaPos, &flaNum, lumpinfo, &numlumps, &i);
// lumpinfo = FindFolder("Maps/", &mapPos, &mapNum, lumpinfo, &numlumps, &i);
}
2017-05-06 14:52:53 +00:00
2017-11-03 03:09:52 +00:00
// Update the detected resources.
// Note: ALWAYS load Lua scripts first, SOCs right after, and the remaining resources afterwards.
// if (luaNum) // Lua scripts.
// P_LoadLuaScrRange(wadnum, luaPos, luaNum);
// if (socNum) // SOCs.
// P_LoadDehackRange(wadnum, socPos, socNum);
if ( sfxNum ) // Sounds. TODO: Function currently only updates already existing sounds, the rest is handled somewhere else.
P_LoadSoundsRange ( wadnum , sfxPos , sfxNum ) ;
if ( musNum ) // Music. TODO: Useless function right now.
P_LoadMusicsRange ( wadnum , musPos , musNum ) ;
// if (sprNum) // Sprites.
// R_LoadSpritsRange(wadnum, sprPos, sprNum);
// if (texNum) // Textures. TODO: R_LoadTextures() does the folder positioning once again. New function maybe?
// R_LoadTextures();
// if (mapNum) // Maps. TODO: Actually implement the map WAD loading code, lulz.
// P_LoadWadMapRange(wadnum, mapPos, mapNum);
2017-04-30 18:05:26 +00:00
break ;
default :
2017-05-06 14:52:53 +00:00
lumpinfo = wadfiles [ wadnum ] - > lumpinfo ;
2017-04-30 18:05:26 +00:00
for ( i = 0 ; i < numlumps ; i + + , lumpinfo + + )
{
name = lumpinfo - > name ;
if ( name [ 0 ] = = ' D ' )
{
2018-01-04 21:06:26 +00:00
if ( name [ 1 ] = = ' S ' )
2017-04-30 18:05:26 +00:00
{
2018-01-04 21:06:26 +00:00
for ( j = 1 ; j < NUMSFX ; j + + )
2017-04-30 18:05:26 +00:00
{
2018-01-04 21:06:26 +00:00
if ( S_sfx [ j ] . name & & ! strnicmp ( S_sfx [ j ] . name , name + 2 , 6 ) )
{
// the sound will be reloaded when needed,
// since sfx->data will be NULL
CONS_Debug ( DBG_SETUP , " Sound %.8s replaced \n " , name ) ;
2017-04-30 18:05:26 +00:00
2018-01-04 21:06:26 +00:00
I_FreeSfx ( & S_sfx [ j ] ) ;
2017-04-30 18:05:26 +00:00
2018-01-04 21:06:26 +00:00
sreplaces + + ;
break ; // there shouldn't be two sounds with the same name, so stop looking
}
2017-04-30 18:05:26 +00:00
}
}
else if ( name [ 1 ] = = ' _ ' )
{
CONS_Debug ( DBG_SETUP , " Music %.8s replaced \n " , name ) ;
mreplaces + + ;
}
}
else if ( name [ 0 ] = = ' O ' & & name [ 1 ] = = ' _ ' )
2014-03-15 16:59:03 +00:00
{
CONS_Debug ( DBG_SETUP , " Music %.8s replaced \n " , name ) ;
2017-04-30 18:05:26 +00:00
digmreplaces + + ;
2014-03-15 16:59:03 +00:00
}
}
2017-04-30 18:05:26 +00:00
break ;
2014-03-15 16:59:03 +00:00
}
if ( ! devparm & & sreplaces )
CONS_Printf ( M_GetText ( " %s sounds replaced \n " ) , sizeu1 ( sreplaces ) ) ;
if ( ! devparm & & mreplaces )
CONS_Printf ( M_GetText ( " %s midi musics replaced \n " ) , sizeu1 ( mreplaces ) ) ;
if ( ! devparm & & digmreplaces )
CONS_Printf ( M_GetText ( " %s digital musics replaced \n " ) , sizeu1 ( digmreplaces ) ) ;
2020-11-22 21:23:35 +00:00
# ifdef HWRENDER
// Free GPU textures before freeing patches.
2021-03-27 23:30:59 +00:00
if ( rendermode = = render_opengl & & ( vid . glstate = = VID_GL_LIBRARY_LOADED ) )
2020-11-22 21:23:35 +00:00
HWR_ClearAllTextures ( ) ;
# endif
2018-11-23 15:58:16 +00:00
2014-03-15 16:59:03 +00:00
//
// search for sprite replacements
//
2020-09-07 05:23:07 +00:00
Patch_FreeTag ( PU_SPRITE ) ;
2020-10-10 21:43:26 +00:00
Patch_FreeTag ( PU_PATCH_ROTATED ) ;
2017-10-30 21:07:17 +00:00
R_AddSpriteDefs ( wadnum ) ;
2017-05-18 19:13:18 +00:00
// Reload it all anyway, just in case they
// added some textures but didn't insert a
2017-10-30 20:54:14 +00:00
// TEXTURES/etc. list.
2017-05-18 19:13:18 +00:00
R_LoadTextures ( ) ; // numtexture changes
2017-10-30 20:54:14 +00:00
// Reload ANIMDEFS
2016-10-19 07:22:11 +00:00
P_InitPicAnims ( ) ;
2014-03-15 16:59:03 +00:00
// Flush and reload HUD graphics
ST_UnloadGraphics ( ) ;
HU_LoadGraphics ( ) ;
ST_LoadGraphics ( ) ;
//
// look for skins
//
2021-04-25 11:18:32 +00:00
R_AddSkins ( wadnum , false ) ; // faB: wadfile index in wadfiles[]
R_PatchSkins ( wadnum , false ) ; // toast: PATCH PATCH
A good and bad ending cutscene now exist.
Also:
* SPR2_XTRA - instead of defining lumpnames in S_SKIN, those kinds of assets can just be bundled into the spriteset. Required for ending cutscene stuff, I guess, but also done for HUD life icon and character select image (aside from Sonic&Tails, still SOC'd in).
* Minor oversights in SPR2 support corrected.
* Better evaluation, featuring ending assets.
* Intro has warping-in blackrock, reusing ending assets.
* Cutscene text now supports lowercase (intro and custom).
* Disable the asset-fucking "gamma correction" I put in over two years ago when implementing colour cube. (This is the only thing I could move into another branch if you MUST, but it's basically invisble in the diff so w/e.)
* Don't blank the screen if the top left pixel of a screen-covering patch is transparent. (Checked via nonzero topdelta for first column)
Bugs:
* OPENGL ONLY: The first ~20 frames of both endings are fucked. A little help here? Might be HWR_DrawFadeFill's fault, which I just created. OR it could be in f_finale, but I doubt it, since it doesn't appear in Software.
2019-07-27 23:32:57 +00:00
ST_ReloadSkinFaceGraphics ( ) ;
2014-03-15 16:59:03 +00:00
Sound test is cool now!
https://cdn.discordapp.com/attachments/405336003239477249/641295998395613224/srb20042.gif
* Port MUSICDEFs from Kart.
* Safe to modify without modifying game, so we can put it in music.dta eventually.
* "Title", "AltTitle", "Authors" fields are self-evident.
* "Soundtestpage" and "Soundtestcond" are used to determine which sound test unlockable can play them (set with Unlockable's variable, just like Level Select).
* "Stoppingtime" and "BPM" both accept floats, and are used for presentation stuff on the sound test.
* Ironically, we don't share a single field name with them. Such is the case of differing foci, though, and I expect they'll change their implementation to match (since this is necessary for a sound test).
* Change how S_AddSoundFx works to avoid iterating through all of them, and to allow cv_soundtest to only scroll through defined slots (instead of the infinite wall of thok sounds when scrolling to the left).
* Change V_DrawFixedPatch to allow scaling on two seperate axes.
* Now called "V_DrawStretchyFixedPatch".
* "V_DrawFixedPatch" is a macro to V_DrawStretchyFixedPatch now (same scale on both axes).
* Available to Lua under v.drawStretched!
* Even works in GL!
* Bugfix: Add SR_PLAYER to SOC's menutypes_list.
Stay tuned for the merge request, where I put the onus on the Music Team to finish this off...
2019-11-05 16:23:46 +00:00
//
// edit music defs
//
S_LoadMusicDefs ( wadnum ) ;
2014-03-15 16:59:03 +00:00
//
// search for maps
//
lumpinfo = wadfiles [ wadnum ] - > lumpinfo ;
for ( i = 0 ; i < numlumps ; i + + , lumpinfo + + )
{
name = lumpinfo - > name ;
if ( name [ 0 ] = = ' M ' & & name [ 1 ] = = ' A ' & & name [ 2 ] = = ' P ' ) // Ignore the headers
{
2018-01-04 20:15:44 +00:00
INT16 num ;
2014-08-27 03:56:30 +00:00
if ( name [ 5 ] ! = ' \0 ' )
continue ;
2014-03-15 16:59:03 +00:00
num = ( INT16 ) M_MapNumber ( name [ 3 ] , name [ 4 ] ) ;
//If you replaced the map you're on, end the level when done.
if ( num = = gamemap )
replacedcurrentmap = true ;
CONS_Printf ( " %s \n " , name ) ;
2018-01-04 20:15:44 +00:00
mapsadded = true ;
2014-03-15 16:59:03 +00:00
}
}
2018-01-04 20:15:44 +00:00
if ( ! mapsadded )
2014-03-15 16:59:03 +00:00
CONS_Printf ( M_GetText ( " No maps added \n " ) ) ;
2019-09-29 22:03:10 +00:00
R_LoadSpriteInfoLumps ( wadnum , numlumps ) ;
2019-09-29 15:13:51 +00:00
2019-09-03 21:27:22 +00:00
# ifdef HWRENDER
HWR_ReloadModels ( ) ;
2019-11-13 00:38:02 +00:00
# endif
2019-09-03 21:27:22 +00:00
2014-03-15 16:59:03 +00:00
// reload status bar (warning should have valid player!)
if ( gamestate = = GS_LEVEL )
ST_Start ( ) ;
// Prevent savefile cheating
2017-08-20 22:18:47 +00:00
if ( cursaveslot > 0 )
cursaveslot = 0 ;
2014-03-15 16:59:03 +00:00
if ( replacedcurrentmap & & gamestate = = GS_LEVEL & & ( netgame | | multiplayer ) )
{
CONS_Printf ( M_GetText ( " Current map %d replaced by added file, ending the level to ensure consistency. \n " ) , gamemap ) ;
if ( server )
SendNetXCmd ( XD_EXITLEVEL , NULL , 0 ) ;
}
return true ;
}
2021-03-23 02:56:55 +00:00
boolean P_AddWadFile ( const char * wadfilename )
{
UINT16 numlumps , wadnum ;
// Init file.
if ( ( numlumps = W_InitFile ( wadfilename , false , false ) ) = = INT16_MAX )
{
refreshdirmenu | = REFRESHDIR_NOTLOADED ;
return false ;
}
else
wadnum = ( UINT16 ) ( numwadfiles - 1 ) ;
return P_LoadAddon ( wadnum , numlumps ) ;
}
boolean P_AddFolder ( const char * folderpath )
{
UINT16 numlumps , wadnum ;
// Init file.
if ( ( numlumps = W_InitFolder ( folderpath , false , false ) ) = = INT16_MAX )
{
refreshdirmenu | = REFRESHDIR_NOTLOADED ;
return false ;
}
else
wadnum = ( UINT16 ) ( numwadfiles - 1 ) ;
return P_LoadAddon ( wadnum , numlumps ) ;
}